i18n-tasks 0.9.29 → 0.9.34

Sign up to get free protection for your applications and to get access to all the features.
Files changed (64) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +25 -5
  3. data/config/locales/en.yml +6 -0
  4. data/config/locales/ru.yml +6 -0
  5. data/i18n-tasks.gemspec +9 -6
  6. data/lib/i18n/tasks/cli.rb +12 -14
  7. data/lib/i18n/tasks/command/commander.rb +1 -1
  8. data/lib/i18n/tasks/command/commands/data.rb +8 -6
  9. data/lib/i18n/tasks/command/commands/eq_base.rb +2 -2
  10. data/lib/i18n/tasks/command/commands/health.rb +7 -6
  11. data/lib/i18n/tasks/command/commands/interpolations.rb +2 -2
  12. data/lib/i18n/tasks/command/commands/meta.rb +1 -1
  13. data/lib/i18n/tasks/command/commands/missing.rb +8 -7
  14. data/lib/i18n/tasks/command/commands/tree.rb +8 -6
  15. data/lib/i18n/tasks/command/commands/usages.rb +7 -6
  16. data/lib/i18n/tasks/command/dsl.rb +4 -4
  17. data/lib/i18n/tasks/command/option_parsers/enum.rb +2 -0
  18. data/lib/i18n/tasks/command/option_parsers/locale.rb +2 -1
  19. data/lib/i18n/tasks/command/options/data.rb +1 -0
  20. data/lib/i18n/tasks/command/options/locales.rb +5 -5
  21. data/lib/i18n/tasks/concurrent/cached_value.rb +2 -0
  22. data/lib/i18n/tasks/configuration.rb +5 -4
  23. data/lib/i18n/tasks/console_context.rb +1 -1
  24. data/lib/i18n/tasks/data/adapter/yaml_adapter.rb +1 -1
  25. data/lib/i18n/tasks/data/file_formats.rb +2 -0
  26. data/lib/i18n/tasks/data/file_system_base.rb +7 -6
  27. data/lib/i18n/tasks/data/router/conservative_router.rb +2 -1
  28. data/lib/i18n/tasks/data/router/pattern_router.rb +2 -0
  29. data/lib/i18n/tasks/data/tree/node.rb +7 -5
  30. data/lib/i18n/tasks/data/tree/nodes.rb +2 -2
  31. data/lib/i18n/tasks/data/tree/siblings.rb +10 -3
  32. data/lib/i18n/tasks/data/tree/traversal.rb +17 -10
  33. data/lib/i18n/tasks/html_keys.rb +2 -4
  34. data/lib/i18n/tasks/ignore_keys.rb +4 -3
  35. data/lib/i18n/tasks/interpolations.rb +4 -2
  36. data/lib/i18n/tasks/key_pattern_matching.rb +3 -2
  37. data/lib/i18n/tasks/missing_keys.rb +33 -7
  38. data/lib/i18n/tasks/plural_keys.rb +6 -1
  39. data/lib/i18n/tasks/references.rb +2 -0
  40. data/lib/i18n/tasks/reports/base.rb +3 -2
  41. data/lib/i18n/tasks/reports/terminal.rb +10 -9
  42. data/lib/i18n/tasks/scanners/file_scanner.rb +4 -3
  43. data/lib/i18n/tasks/scanners/files/caching_file_finder.rb +0 -3
  44. data/lib/i18n/tasks/scanners/files/file_finder.rb +3 -2
  45. data/lib/i18n/tasks/scanners/occurrence_from_position.rb +3 -3
  46. data/lib/i18n/tasks/scanners/pattern_scanner.rb +7 -4
  47. data/lib/i18n/tasks/scanners/pattern_with_scope_scanner.rb +4 -2
  48. data/lib/i18n/tasks/scanners/relative_keys.rb +1 -0
  49. data/lib/i18n/tasks/scanners/ruby_ast_scanner.rb +18 -15
  50. data/lib/i18n/tasks/scanners/ruby_key_literals.rb +3 -3
  51. data/lib/i18n/tasks/scanners/scanner_multiplexer.rb +2 -0
  52. data/lib/i18n/tasks/split_key.rb +2 -0
  53. data/lib/i18n/tasks/string_interpolation.rb +1 -0
  54. data/lib/i18n/tasks/translation.rb +6 -3
  55. data/lib/i18n/tasks/translators/base_translator.rb +3 -1
  56. data/lib/i18n/tasks/translators/deepl_translator.rb +9 -2
  57. data/lib/i18n/tasks/translators/google_translator.rb +2 -0
  58. data/lib/i18n/tasks/translators/yandex_translator.rb +63 -0
  59. data/lib/i18n/tasks/used_keys.rb +15 -11
  60. data/lib/i18n/tasks/version.rb +1 -1
  61. data/templates/config/i18n-tasks.yml +1 -1
  62. data/templates/rspec/i18n_spec.rb +9 -2
  63. metadata +48 -31
  64. data/lib/i18n/tasks/rainbow_utils.rb +0 -15
@@ -10,8 +10,8 @@ module I18n::Tasks
10
10
  end
11
11
  end
12
12
 
13
- def t(*args)
14
- I18n.t(*args)
13
+ def t(*args, **kwargs)
14
+ I18n.t(*args, **kwargs)
15
15
  end
16
16
 
17
17
  module ClassMethods
@@ -42,8 +42,8 @@ module I18n::Tasks
42
42
  end
43
43
 
44
44
  # late-bound I18n.t for module bodies
45
- def t(*args)
46
- proc { I18n.t(*args) }
45
+ def t(*args, **kwargs)
46
+ proc { I18n.t(*args, **kwargs) }
47
47
  end
48
48
 
49
49
  # if class is a module, merge DSL definitions when it is included
@@ -16,6 +16,7 @@ module I18n::Tasks
16
16
 
17
17
  def call(value, *)
18
18
  return @valid.first unless value.present?
19
+
19
20
  if @valid.include?(value)
20
21
  value
21
22
  else
@@ -37,6 +38,7 @@ module I18n::Tasks
37
38
  def call(values, *)
38
39
  values = Array(values)
39
40
  return @valid if values == %w[all]
41
+
40
42
  invalid = values - @valid
41
43
  if invalid.empty?
42
44
  if values.empty?
@@ -5,12 +5,13 @@ module I18n::Tasks
5
5
  module OptionParsers
6
6
  module Locale
7
7
  module Validator
8
- VALID_LOCALE_RE = /\A\w[\w\-\.]*\z/i
8
+ VALID_LOCALE_RE = /\A\w[\w\-.]*\z/i.freeze
9
9
 
10
10
  def validate!(locale)
11
11
  if VALID_LOCALE_RE !~ locale
12
12
  fail CommandError, I18n.t('i18n_tasks.cmd.errors.invalid_locale', invalid: locale)
13
13
  end
14
+
14
15
  locale
15
16
  end
16
17
  end
@@ -64,6 +64,7 @@ module I18n::Tasks
64
64
  # @return [I18n::Tasks::Data::Tree::Siblings]
65
65
  def parse_forest(src, format)
66
66
  fail CommandError, I18n.t('i18n_tasks.cmd.errors.pass_forest') unless src
67
+
67
68
  if format == 'keys'
68
69
  ::I18n::Tasks::Data::Tree::Siblings.from_key_names parse_keys(src)
69
70
  else
@@ -13,22 +13,22 @@ module I18n::Tasks
13
13
  '--locales en,es,ru',
14
14
  Array,
15
15
  t('i18n_tasks.cmd.args.desc.locales_filter'),
16
- parser: OptionParsers::Locale::ListParser,
17
- default: 'all',
16
+ parser: OptionParsers::Locale::ListParser,
17
+ default: 'all',
18
18
  consume_positional: true
19
19
 
20
20
  arg :locale,
21
21
  '-l',
22
22
  '--locale en',
23
23
  t('i18n_tasks.cmd.args.desc.locale'),
24
- parser: OptionParsers::Locale::Parser,
24
+ parser: OptionParsers::Locale::Parser,
25
25
  default: 'base'
26
26
 
27
27
  arg :locale_to_translate_from,
28
28
  '-f',
29
29
  '--from en',
30
30
  t('i18n_tasks.cmd.args.desc.locale_to_translate_from'),
31
- parser: OptionParsers::Locale::Parser,
31
+ parser: OptionParsers::Locale::Parser,
32
32
  default: 'base'
33
33
 
34
34
  TRANSLATION_BACKENDS = %w[google deepl].freeze
@@ -36,7 +36,7 @@ module I18n::Tasks
36
36
  '-b',
37
37
  '--backend BACKEND',
38
38
  t('i18n_tasks.cmd.args.desc.translation_backend'),
39
- parser: OptionParsers::Locale::Parser,
39
+ parser: OptionParsers::Locale::Parser,
40
40
  default: TRANSLATION_BACKENDS[0]
41
41
  end
42
42
  end
@@ -19,8 +19,10 @@ module I18n::Tasks::Concurrent
19
19
  # @return [Object] Result of the computation.
20
20
  def get
21
21
  return get_result_volatile unless get_result_volatile == NULL
22
+
22
23
  @mutex.synchronize do
23
24
  next unless get_result_volatile == NULL
25
+
24
26
  set_result_volatile @computation.call
25
27
  @computation = nil
26
28
  end
@@ -2,10 +2,10 @@
2
2
 
3
3
  module I18n::Tasks::Configuration # rubocop:disable Metrics/ModuleLength
4
4
  DEFAULTS = {
5
- base_locale: 'en',
5
+ base_locale: 'en',
6
6
  internal_locale: 'en',
7
- search: ::I18n::Tasks::UsedKeys::SEARCH_DEFAULTS,
8
- data: ::I18n::Tasks::Data::DATA_DEFAULTS
7
+ search: ::I18n::Tasks::UsedKeys::SEARCH_DEFAULTS,
8
+ data: ::I18n::Tasks::Data::DATA_DEFAULTS
9
9
  }.freeze
10
10
 
11
11
  # i18n-tasks config (defaults + config/i18n-tasks.yml)
@@ -47,7 +47,7 @@ module I18n::Tasks::Configuration # rubocop:disable Metrics/ModuleLength
47
47
  @config_sections[:data] ||= begin
48
48
  {
49
49
  adapter: data.class.name,
50
- config: data.config
50
+ config: data.config
51
51
  }
52
52
  end
53
53
  end
@@ -59,6 +59,7 @@ module I18n::Tasks::Configuration # rubocop:disable Metrics/ModuleLength
59
59
  conf = (config[:translation] || {}).with_indifferent_access
60
60
  conf[:google_translate_api_key] = ENV['GOOGLE_TRANSLATE_API_KEY'] if ENV.key?('GOOGLE_TRANSLATE_API_KEY')
61
61
  conf[:deepl_api_key] = ENV['DEEPL_AUTH_KEY'] if ENV.key?('DEEPL_AUTH_KEY')
62
+ conf[:yandex_api_key] = ENV['YANDEX_API_KEY'] if ENV.key?('YANDEX_API_KEY')
62
63
  conf
63
64
  end
64
65
  end
@@ -34,7 +34,7 @@ module I18n::Tasks
34
34
  end
35
35
 
36
36
  def guide
37
- Rainbow('i18n-tasks IRB Quick Start guide').green.bright + "\n" + <<~TEXT
37
+ "#{Rainbow('i18n-tasks IRB Quick Start guide').green.bright}\n#{<<~TEXT}"
38
38
  #{Rainbow('Data as trees').yellow}
39
39
  tree(locale)
40
40
  used_tree(key_filter: nil, strict: nil)
@@ -9,7 +9,7 @@ module I18n::Tasks
9
9
  # @return [Hash] locale tree
10
10
  def parse(str, options)
11
11
  if YAML.method(:load).arity.abs == 2
12
- YAML.load(str, options || {})
12
+ YAML.load(str, **(options || {}))
13
13
  else
14
14
  # older jruby and rbx 2.2.7 do not accept options
15
15
  YAML.load(str)
@@ -53,12 +53,14 @@ module I18n
53
53
  content = adapter_dump(hash, adapter)
54
54
  # Ignore unchanged data
55
55
  return if File.file?(path) && content == read_file(path)
56
+
56
57
  ::FileUtils.mkpath(File.dirname(path))
57
58
  ::File.open(path, 'w') { |f| f.write content }
58
59
  end
59
60
 
60
61
  def normalized?(path, tree)
61
62
  return false unless File.file?(path)
63
+
62
64
  read_file(path) == adapter_dump(tree.to_hash(true), self.class.adapter_name_for_path(path))
63
65
  end
64
66
 
@@ -12,11 +12,12 @@ module I18n::Tasks
12
12
  include ::I18n::Tasks::Data::FileFormats
13
13
  include ::I18n::Tasks::Logging
14
14
 
15
- attr_reader :config, :base_locale, :locales
16
- attr_writer :locales
15
+ attr_accessor :locales
16
+ attr_reader :config, :base_locale
17
+ attr_writer :router
17
18
 
18
19
  DEFAULTS = {
19
- read: ['config/locales/%{locale}.yml'],
20
+ read: ['config/locales/%{locale}.yml'],
20
21
  write: ['config/locales/%{locale}.yml']
21
22
  }.freeze
22
23
 
@@ -131,11 +132,12 @@ module I18n::Tasks
131
132
  def t(key, locale)
132
133
  tree = self[locale.to_s]
133
134
  return unless tree
135
+
134
136
  tree[locale][key].try(:value_or_children_hash)
135
137
  end
136
138
 
137
139
  def config=(config)
138
- @config = DEFAULTS.deep_merge((config || {}).reject { |_k, v| v.nil? })
140
+ @config = DEFAULTS.deep_merge((config || {}).compact)
139
141
  reload
140
142
  end
141
143
 
@@ -159,7 +161,6 @@ module I18n::Tasks
159
161
  router_class.new(self, @config.merge(base_locale: base_locale, locales: locales))
160
162
  end
161
163
  end
162
- attr_writer :router
163
164
 
164
165
  protected
165
166
 
@@ -188,7 +189,7 @@ module I18n::Tasks
188
189
  The following unquoted YAML keys result in a nil key:
189
190
  #{%w[null Null NULL ~].join(', ')}
190
191
  See http://yaml.org/type/null.html
191
- TEXT
192
+ TEXT
192
193
  elsif value.is_a?(Hash)
193
194
  filter_nil_keys! path, value, suffix + [key]
194
195
  end
@@ -13,8 +13,9 @@ module I18n::Tasks
13
13
  super
14
14
  end
15
15
 
16
- def route(locale, forest, &block)
16
+ def route(locale, forest, &block) # rubocop:disable Metrics/AbcSize
17
17
  return to_enum(:route, locale, forest) unless block
18
+
18
19
  out = Hash.new { |hash, key| hash[key] = Set.new }
19
20
  not_found = Set.new
20
21
  forest.keys do |key, _node|
@@ -10,6 +10,7 @@ module I18n::Tasks
10
10
  include ::I18n::Tasks::KeyPatternMatching
11
11
 
12
12
  attr_reader :routes
13
+
13
14
  # @option data_config write [Array] of routes
14
15
  # @example
15
16
  # {write:
@@ -29,6 +30,7 @@ module I18n::Tasks
29
30
  # @return [Hash] mapping of destination => [ [key, value], ... ]
30
31
  def route(locale, forest, &block)
31
32
  return to_enum(:route, locale, forest) unless block
33
+
32
34
  locale = locale.to_s
33
35
  out = {}
34
36
  forest.keys do |key, _node|
@@ -2,7 +2,6 @@
2
2
 
3
3
  require 'i18n/tasks/data/tree/traversal'
4
4
  require 'i18n/tasks/data/tree/siblings'
5
- require 'i18n/tasks/rainbow_utils'
6
5
  module I18n::Tasks::Data::Tree
7
6
  class Node # rubocop:disable Metrics/ClassLength
8
7
  include Enumerable
@@ -19,7 +18,7 @@ module I18n::Tasks::Data::Tree
19
18
  @data = data
20
19
  @parent = parent
21
20
  @warn_about_add_children_to_leaf = warn_about_add_children_to_leaf
22
- self.children = (children if children)
21
+ self.children = children if children
23
22
  end
24
23
  # rubocop:enable Metrics/ParameterLists
25
24
 
@@ -28,7 +27,7 @@ module I18n::Tasks::Data::Tree
28
27
  end
29
28
 
30
29
  def derive(new_attr = {})
31
- self.class.new(attributes.merge(new_attr))
30
+ self.class.new(**attributes.merge(new_attr))
32
31
  end
33
32
 
34
33
  def children=(children)
@@ -49,6 +48,7 @@ module I18n::Tasks::Data::Tree
49
48
 
50
49
  def each(&block)
51
50
  return to_enum(:each) { 1 } unless block
51
+
52
52
  block.yield(self)
53
53
  self
54
54
  end
@@ -113,6 +113,7 @@ module I18n::Tasks::Data::Tree
113
113
 
114
114
  def walk_to_root(&visitor)
115
115
  return to_enum(:walk_to_root) unless visitor
116
+
116
117
  visitor.yield self
117
118
  parent.walk_to_root(&visitor) if parent?
118
119
  end
@@ -125,6 +126,7 @@ module I18n::Tasks::Data::Tree
125
126
 
126
127
  def walk_from_root(&visitor)
127
128
  return to_enum(:walk_from_root) unless visitor
129
+
128
130
  walk_to_root.reverse_each do |node|
129
131
  visitor.yield node
130
132
  end
@@ -164,13 +166,13 @@ module I18n::Tasks::Data::Tree
164
166
 
165
167
  def inspect(level = 0)
166
168
  label = if key.nil?
167
- I18n::Tasks::RainbowUtils.faint_color('∅')
169
+ Rainbow('∅').faint
168
170
  else
169
171
  [Rainbow(key).color(1 + level % 15),
170
172
  (": #{format_value_for_inspect(value)}" if leaf?),
171
173
  (" #{data}" if data?)].compact.join
172
174
  end
173
- [' ' * level, label, ("\n" + children.map { |c| c.inspect(level + 1) }.join("\n") if children?)].compact.join
175
+ [' ' * level, label, ("\n#{children.map { |c| c.inspect(level + 1) }.join("\n")}" if children?)].compact.join
174
176
  end
175
177
 
176
178
  def format_value_for_inspect(value)
@@ -1,7 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'i18n/tasks/data/tree/traversal'
4
- require 'i18n/tasks/rainbow_utils'
5
4
  module I18n::Tasks::Data::Tree
6
5
  # A list of nodes
7
6
  class Nodes
@@ -48,7 +47,7 @@ module I18n::Tasks::Data::Tree
48
47
  if present?
49
48
  map(&:inspect) * "\n"
50
49
  else
51
- I18n::Tasks::RainbowUtils.faint_color('{∅}')
50
+ Rainbow('{∅}').faint
52
51
  end
53
52
  end
54
53
 
@@ -81,6 +80,7 @@ module I18n::Tasks::Data::Tree
81
80
 
82
81
  def children(&block)
83
82
  return to_enum(:children) { map { |c| c.children ? c.children.size : 0 }.reduce(:+) } unless block
83
+
84
84
  each do |node|
85
85
  node.children.each(&block) if node.children?
86
86
  end
@@ -62,6 +62,7 @@ module I18n::Tasks::Data::Tree
62
62
  # TODO: support nested references better
63
63
  nodes do |node|
64
64
  next unless node.reference?
65
+
65
66
  old_target = [(node.root.key if root), node.value.to_s].compact.join('.')
66
67
  new_target = old_key_to_new_key[old_target]
67
68
  if new_target
@@ -92,6 +93,7 @@ module I18n::Tasks::Data::Tree
92
93
  # add or replace node by full key
93
94
  def set(full_key, node)
94
95
  fail 'value should be a I18n::Tasks::Data::Tree::Node' unless node.is_a?(Node)
96
+
95
97
  key_part, rest = split_key(full_key, 2)
96
98
  child = key_to_node[key_part]
97
99
 
@@ -131,6 +133,7 @@ module I18n::Tasks::Data::Tree
131
133
  def append!(nodes)
132
134
  nodes = nodes.map do |node|
133
135
  fail "already has a child with key '#{node.key}'" if key_to_node.key?(node.key)
136
+
134
137
  key_to_node[node.key] = (node.parent == parent ? node : node.derive(parent: parent))
135
138
  end
136
139
  super(nodes)
@@ -172,16 +175,18 @@ module I18n::Tasks::Data::Tree
172
175
 
173
176
  def set_root_key!(new_key, data = nil)
174
177
  return self if empty?
178
+
175
179
  rename_key first.key, new_key
176
180
  leaves { |node| node.data.merge! data } if data
177
181
  self
178
182
  end
179
183
 
180
184
  # @param on_leaves_merge [Proc] invoked when a leaf is merged with another leaf
181
- def merge_node!(node, on_leaves_merge: nil) # rubocop:disable Metrics/AbcSize,Metrics/PerceivedComplexity
185
+ def merge_node!(node, on_leaves_merge: nil) # rubocop:disable Metrics/AbcSize
182
186
  if key_to_node.key?(node.key)
183
187
  our = key_to_node[node.key]
184
188
  return if our == node
189
+
185
190
  our.value = node.value if node.leaf?
186
191
  our.data.merge!(node.data) if node.data?
187
192
  if node.children?
@@ -262,7 +267,7 @@ module I18n::Tasks::Data::Tree
262
267
  build_forest(warn_about_add_children_to_leaf: false) do |forest|
263
268
  key_occurrences.each do |key_occurrence|
264
269
  forest[key_occurrence.key] = ::I18n::Tasks::Data::Tree::Node.new(
265
- key: split_key(key_occurrence.key).last,
270
+ key: split_key(key_occurrence.key).last,
266
271
  data: { occurrences: key_occurrence.occurrences }
267
272
  )
268
273
  end
@@ -273,7 +278,8 @@ module I18n::Tasks::Data::Tree
273
278
  build_forest(opts) do |forest|
274
279
  key_attrs.each do |(full_key, attr)|
275
280
  fail "Invalid key #{full_key.inspect}" if full_key.end_with?('.')
276
- node = ::I18n::Tasks::Data::Tree::Node.new(attr.merge(key: split_key(full_key).last))
281
+
282
+ node = ::I18n::Tasks::Data::Tree::Node.new(**attr.merge(key: split_key(full_key).last))
277
283
  yield(full_key, node) if block
278
284
  forest[full_key] = node
279
285
  end
@@ -295,6 +301,7 @@ module I18n::Tasks::Data::Tree
295
301
  def from_nested_hash(hash, opts = {})
296
302
  parse_parent_opt!(opts)
297
303
  fail I18n::Tasks::CommandError, "invalid tree #{hash.inspect}" unless hash.respond_to?(:map)
304
+
298
305
  opts[:nodes] = hash.map { |key, value| Node.from_key_value key, value }
299
306
  Siblings.new(opts)
300
307
  end
@@ -12,6 +12,7 @@ module I18n::Tasks
12
12
 
13
13
  def leaves(&visitor)
14
14
  return to_enum(:leaves) unless visitor
15
+
15
16
  nodes do |node|
16
17
  visitor.yield(node) if node.leaf?
17
18
  end
@@ -20,6 +21,7 @@ module I18n::Tasks
20
21
 
21
22
  def levels(&block)
22
23
  return to_enum(:levels) unless block
24
+
23
25
  nodes = to_nodes
24
26
  unless nodes.empty?
25
27
  block.yield nodes
@@ -35,6 +37,7 @@ module I18n::Tasks
35
37
 
36
38
  def breadth_first(&visitor)
37
39
  return to_enum(:breadth_first) unless visitor
40
+
38
41
  levels do |nodes|
39
42
  nodes.each { |node| visitor.yield(node) }
40
43
  end
@@ -43,9 +46,11 @@ module I18n::Tasks
43
46
 
44
47
  def depth_first(&visitor)
45
48
  return to_enum(:depth_first) unless visitor
49
+
46
50
  each do |node|
47
51
  visitor.yield node
48
52
  next unless node.children?
53
+
49
54
  node.children.each do |child|
50
55
  child.depth_first(&visitor)
51
56
  end
@@ -56,29 +61,28 @@ module I18n::Tasks
56
61
  # @option root include root in full key
57
62
  def keys(root: false, &visitor)
58
63
  return to_enum(:keys, root: root) unless visitor
64
+
59
65
  leaves { |node| visitor.yield(node.full_key(root: root), node) }
60
66
  self
61
67
  end
62
68
 
63
- def key_names(opts = {})
64
- opts[:root] = false unless opts.key?(:root)
65
- keys(opts).map { |key, _node| key }
69
+ def key_names(root: false)
70
+ keys(root: root).map { |key, _node| key }
66
71
  end
67
72
 
68
- def key_values(opts = {})
69
- opts[:root] = false unless opts.key?(:root)
70
- keys(opts).map { |key, node| [key, node.value] }
73
+ def key_values(root: false)
74
+ keys(root: root).map { |key, node| [key, node.value] }
71
75
  end
72
76
 
73
77
  def root_key_values(sort = false)
74
78
  result = keys(root: false).map { |key, node| [node.root.key, key, node.value] }
75
- result.sort! { |a, b| a[0] != b[0] ? a[0] <=> b[0] : a[1] <=> b[1] } if sort
79
+ result.sort! { |a, b| a[0] == b[0] ? a[1] <=> b[1] : a[0] <=> b[0] } if sort
76
80
  result
77
81
  end
78
82
 
79
83
  def root_key_value_data(sort = false)
80
84
  result = keys(root: false).map { |key, node| [node.root.key, key, node.value, node.data] }
81
- result.sort! { |a, b| a[0] != b[0] ? a[0] <=> b[0] : a[1] <=> b[1] } if sort
85
+ result.sort! { |a, b| a[0] == b[0] ? a[1] <=> b[1] : a[0] <=> b[0] } if sort
82
86
  result
83
87
  end
84
88
 
@@ -90,6 +94,7 @@ module I18n::Tasks
90
94
  tree = Siblings.new
91
95
  each do |node|
92
96
  next unless block.yield(node)
97
+
93
98
  tree.append! node.derive(
94
99
  parent: tree.parent,
95
100
  children: (node.children.select_nodes(&block).to_a if node.children)
@@ -146,12 +151,12 @@ module I18n::Tasks
146
151
  # @return [Siblings]
147
152
  def intersect_keys(other_tree, key_opts = {}, &block)
148
153
  if block
149
- select_keys(key_opts) do |key, node|
154
+ select_keys(**key_opts.slice(:root)) do |key, node|
150
155
  other_node = other_tree[key]
151
156
  other_node && yield(key, node, other_node)
152
157
  end
153
158
  else
154
- select_keys(key_opts) { |key, _node| other_tree[key] }
159
+ select_keys(**key_opts.slice(:root)) { |key, _node| other_tree[key] }
155
160
  end
156
161
  end
157
162
 
@@ -165,6 +170,7 @@ module I18n::Tasks
165
170
  value_proc ||= proc do |node|
166
171
  node_value = node.value
167
172
  next node_value if node.reference?
173
+
168
174
  human_key = ActiveSupport::Inflector.humanize(node.key.to_s)
169
175
  full_key = node.full_key
170
176
  default = (node.data[:occurrences] || []).detect { |o| o.default_arg.presence }.try(:default_arg)
@@ -181,6 +187,7 @@ module I18n::Tasks
181
187
  pattern_re = I18n::Tasks::KeyPatternMatching.compile_key_pattern(key_pattern) if key_pattern.present?
182
188
  keys.each do |key, node|
183
189
  next if pattern_re && key !~ pattern_re
190
+
184
191
  node.value = value_proc.call(node)
185
192
  end
186
193
  self