i18n-tasks 0.9.6 → 0.9.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +1 -1
- data/Rakefile +2 -1
- data/bin/i18n-tasks +1 -0
- data/config/locales/en.yml +15 -9
- data/config/locales/ru.yml +80 -74
- data/i18n-tasks.gemspec +9 -8
- data/lib/i18n/tasks.rb +2 -5
- data/lib/i18n/tasks/cli.rb +14 -18
- data/lib/i18n/tasks/command/commander.rb +2 -3
- data/lib/i18n/tasks/command/commands/health.rb +1 -1
- data/lib/i18n/tasks/command/commands/meta.rb +2 -2
- data/lib/i18n/tasks/command/commands/missing.rb +17 -19
- data/lib/i18n/tasks/command/commands/tree.rb +3 -3
- data/lib/i18n/tasks/command/commands/usages.rb +6 -5
- data/lib/i18n/tasks/command/commands/xlsx.rb +1 -1
- data/lib/i18n/tasks/command/dsl.rb +1 -2
- data/lib/i18n/tasks/command/option_parsers/enum.rb +6 -6
- data/lib/i18n/tasks/command/option_parsers/locale.rb +3 -1
- data/lib/i18n/tasks/command/options/data.rb +22 -21
- data/lib/i18n/tasks/command_error.rb +1 -3
- data/lib/i18n/tasks/configuration.rb +37 -27
- data/lib/i18n/tasks/console_context.rb +3 -2
- data/lib/i18n/tasks/data.rb +5 -4
- data/lib/i18n/tasks/data/adapter/json_adapter.rb +13 -12
- data/lib/i18n/tasks/data/adapter/yaml_adapter.rb +13 -14
- data/lib/i18n/tasks/data/file_formats.rb +15 -10
- data/lib/i18n/tasks/data/file_system_base.rb +18 -22
- data/lib/i18n/tasks/data/router/conservative_router.rb +3 -6
- data/lib/i18n/tasks/data/router/pattern_router.rb +4 -5
- data/lib/i18n/tasks/data/tree/node.rb +20 -19
- data/lib/i18n/tasks/data/tree/nodes.rb +4 -3
- data/lib/i18n/tasks/data/tree/siblings.rb +36 -29
- data/lib/i18n/tasks/data/tree/traversal.rb +32 -35
- data/lib/i18n/tasks/google_translation.rb +22 -25
- data/lib/i18n/tasks/html_keys.rb +2 -0
- data/lib/i18n/tasks/ignore_keys.rb +3 -2
- data/lib/i18n/tasks/key_pattern_matching.rb +9 -8
- data/lib/i18n/tasks/locale_list.rb +4 -6
- data/lib/i18n/tasks/locale_pathname.rb +8 -8
- data/lib/i18n/tasks/logging.rb +3 -3
- data/lib/i18n/tasks/missing_keys.rb +29 -31
- data/lib/i18n/tasks/plural_keys.rb +6 -7
- data/lib/i18n/tasks/references.rb +72 -41
- data/lib/i18n/tasks/reports/base.rb +8 -7
- data/lib/i18n/tasks/reports/spreadsheet.rb +15 -16
- data/lib/i18n/tasks/reports/terminal.rb +32 -32
- data/lib/i18n/tasks/scanners/file_scanner.rb +6 -5
- data/lib/i18n/tasks/scanners/files/caching_file_finder_provider.rb +1 -2
- data/lib/i18n/tasks/scanners/files/caching_file_reader.rb +0 -1
- data/lib/i18n/tasks/scanners/files/file_finder.rb +12 -15
- data/lib/i18n/tasks/scanners/files/file_reader.rb +0 -1
- data/lib/i18n/tasks/scanners/occurrence_from_position.rb +8 -7
- data/lib/i18n/tasks/scanners/pattern_mapper.rb +2 -2
- data/lib/i18n/tasks/scanners/pattern_scanner.rb +9 -7
- data/lib/i18n/tasks/scanners/pattern_with_scope_scanner.rb +1 -2
- data/lib/i18n/tasks/scanners/relative_keys.rb +11 -11
- data/lib/i18n/tasks/scanners/results/key_occurrences.rb +3 -4
- data/lib/i18n/tasks/scanners/results/occurrence.rb +8 -7
- data/lib/i18n/tasks/scanners/ruby_ast_call_finder.rb +2 -2
- data/lib/i18n/tasks/scanners/ruby_ast_scanner.rb +39 -31
- data/lib/i18n/tasks/scanners/scanner_multiplexer.rb +9 -3
- data/lib/i18n/tasks/split_key.rb +5 -6
- data/lib/i18n/tasks/stats.rb +10 -8
- data/lib/i18n/tasks/string_interpolation.rb +1 -1
- data/lib/i18n/tasks/unused_keys.rb +2 -2
- data/lib/i18n/tasks/used_keys.rb +47 -43
- data/lib/i18n/tasks/version.rb +1 -1
- data/templates/rspec/i18n_spec.rb +2 -2
- metadata +30 -3
@@ -2,8 +2,7 @@
|
|
2
2
|
module I18n::Tasks
|
3
3
|
module Data::Tree
|
4
4
|
# Any Enumerable that yields nodes can mix in this module
|
5
|
-
module Traversal
|
6
|
-
|
5
|
+
module Traversal # rubocop:disable Metrics/ModuleLength
|
7
6
|
def nodes(&block)
|
8
7
|
depth_first(&block)
|
9
8
|
end
|
@@ -41,12 +40,13 @@ module I18n::Tasks
|
|
41
40
|
|
42
41
|
def depth_first(&visitor)
|
43
42
|
return to_enum(:depth_first) unless visitor
|
44
|
-
each
|
43
|
+
each do |node|
|
45
44
|
visitor.yield node
|
45
|
+
next unless node.children?
|
46
46
|
node.children.each do |child|
|
47
47
|
child.depth_first(&visitor)
|
48
|
-
end
|
49
|
-
|
48
|
+
end
|
49
|
+
end
|
50
50
|
self
|
51
51
|
end
|
52
52
|
|
@@ -58,7 +58,6 @@ module I18n::Tasks
|
|
58
58
|
self
|
59
59
|
end
|
60
60
|
|
61
|
-
|
62
61
|
def key_names(opts = {})
|
63
62
|
opts[:root] = false unless opts.key?(:root)
|
64
63
|
keys(opts).map { |key, _node| key }
|
@@ -88,12 +87,11 @@ module I18n::Tasks
|
|
88
87
|
def select_nodes(&block)
|
89
88
|
tree = Siblings.new
|
90
89
|
each do |node|
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
end
|
90
|
+
next unless block.yield(node)
|
91
|
+
tree.append! node.derive(
|
92
|
+
parent: tree.parent,
|
93
|
+
children: (node.children.select_nodes(&block).to_a if node.children)
|
94
|
+
)
|
97
95
|
end
|
98
96
|
tree
|
99
97
|
end
|
@@ -117,56 +115,55 @@ module I18n::Tasks
|
|
117
115
|
# @return Siblings
|
118
116
|
def select_keys(opts = {}, &block)
|
119
117
|
root = opts.key?(:root) ? opts[:root] : false
|
120
|
-
ok
|
118
|
+
ok = {}
|
121
119
|
keys(root: root) do |full_key, node|
|
122
120
|
if block.yield(full_key, node)
|
123
|
-
node.walk_to_root
|
121
|
+
node.walk_to_root do |p|
|
124
122
|
break if ok[p]
|
125
123
|
ok[p] = true
|
126
|
-
|
124
|
+
end
|
127
125
|
end
|
128
126
|
end
|
129
|
-
select_nodes
|
127
|
+
select_nodes do |node|
|
130
128
|
ok[node]
|
131
|
-
|
129
|
+
end
|
132
130
|
end
|
133
131
|
|
134
132
|
# @return Siblings
|
135
133
|
def intersect_keys(other_tree, key_opts = {}, &block)
|
136
134
|
if block
|
137
|
-
select_keys(key_opts)
|
135
|
+
select_keys(key_opts) do |key, node|
|
138
136
|
other_node = other_tree[key]
|
139
|
-
other_node &&
|
140
|
-
|
137
|
+
other_node && yield(key, node, other_node)
|
138
|
+
end
|
141
139
|
else
|
142
|
-
select_keys(key_opts) { |key,
|
140
|
+
select_keys(key_opts) { |key, _node| other_tree[key] }
|
143
141
|
end
|
144
142
|
end
|
145
143
|
|
146
144
|
def grep_keys(match, opts = {})
|
147
145
|
select_keys(opts) do |full_key, _node|
|
148
|
-
match === full_key
|
146
|
+
match === full_key # rubocop:disable Style/CaseEquality
|
149
147
|
end
|
150
148
|
end
|
151
149
|
|
152
150
|
def set_each_value!(val_pattern, key_pattern = nil, &value_proc)
|
153
|
-
value_proc ||= proc
|
151
|
+
value_proc ||= proc do |node|
|
154
152
|
node_value = node.value
|
155
153
|
next node_value if node.reference?
|
156
|
-
human_key
|
157
|
-
full_key
|
154
|
+
human_key = ActiveSupport::Inflector.humanize(node.key.to_s)
|
155
|
+
full_key = node.full_key
|
156
|
+
default = (node.data[:occurrences] || []).detect { |o| o.default_arg.presence }.try(:default_arg)
|
158
157
|
StringInterpolation.interpolate_soft(
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
o.default_arg.presence }.try(:default_arg) ||
|
167
|
-
human_key
|
158
|
+
val_pattern,
|
159
|
+
value: node_value,
|
160
|
+
human_key: human_key,
|
161
|
+
key: full_key,
|
162
|
+
default: default,
|
163
|
+
value_or_human_key: node_value.presence || human_key,
|
164
|
+
value_or_default_or_human_key: node_value.presence || default || human_key
|
168
165
|
)
|
169
|
-
|
166
|
+
end
|
170
167
|
if key_pattern.present?
|
171
168
|
pattern_re = I18n::Tasks::KeyPatternMatching.compile_key_pattern(key_pattern)
|
172
169
|
end
|
@@ -4,7 +4,6 @@ require 'i18n/tasks/html_keys'
|
|
4
4
|
|
5
5
|
module I18n::Tasks
|
6
6
|
module GoogleTranslation
|
7
|
-
|
8
7
|
# @param [I18n::Tasks::Tree::Siblings] forest to translate to the locales of its root nodes
|
9
8
|
# @param [String] from locale
|
10
9
|
# @return [I18n::Tasks::Tree::Siblings] translated forest
|
@@ -17,18 +16,18 @@ module I18n::Tasks
|
|
17
16
|
|
18
17
|
# @param [Array<[String, Object]>] list of key-value pairs
|
19
18
|
# @return [Array<[String, Object]>] translated list
|
20
|
-
def google_translate_list(list, opts)
|
19
|
+
def google_translate_list(list, opts) # rubocop:disable Metrics/AbcSize
|
21
20
|
return [] if list.empty?
|
22
|
-
opts
|
21
|
+
opts = opts.dup
|
23
22
|
opts[:key] ||= translation_config[:api_key]
|
24
23
|
validate_google_translate_api_key! opts[:key]
|
25
|
-
key_pos = list.each_with_index.inject({}) { |idx, ((k, _v), i)| idx
|
24
|
+
key_pos = list.each_with_index.inject({}) { |idx, ((k, _v), i)| idx.update(k => i) }
|
26
25
|
# copy reference keys as is, instead of translating
|
27
26
|
reference_key_vals = list.select { |_k, v| v.is_a? Symbol } || []
|
28
27
|
list -= reference_key_vals
|
29
|
-
result
|
30
|
-
fetch_google_translations list_slice, opts.merge(is_html ? {html: true} : {format: 'text'})
|
31
|
-
|
28
|
+
result = list.group_by { |k_v| html_key? k_v[0], opts[:from] }.map do |is_html, list_slice|
|
29
|
+
fetch_google_translations list_slice, opts.merge(is_html ? { html: true } : { format: 'text' })
|
30
|
+
end.reduce(:+) || []
|
32
31
|
result.concat(reference_key_vals)
|
33
32
|
result.sort! { |a, b| key_pos[a[0]] <=> key_pos[b[0]] }
|
34
33
|
result
|
@@ -39,7 +38,7 @@ module I18n::Tasks
|
|
39
38
|
def fetch_google_translations(list, opts)
|
40
39
|
from_values(list, EasyTranslate.translate(to_values(list), opts)).tap do |result|
|
41
40
|
if result.blank?
|
42
|
-
|
41
|
+
fail CommandError, I18n.t('i18n_tasks.google_translate.errors.no_results')
|
43
42
|
end
|
44
43
|
end
|
45
44
|
end
|
@@ -48,7 +47,7 @@ module I18n::Tasks
|
|
48
47
|
|
49
48
|
def validate_google_translate_api_key!(key)
|
50
49
|
if key.blank?
|
51
|
-
|
50
|
+
fail CommandError, I18n.t('i18n_tasks.google_translate.errors.no_api_key')
|
52
51
|
end
|
53
52
|
end
|
54
53
|
|
@@ -71,13 +70,11 @@ module I18n::Tasks
|
|
71
70
|
# @return [String, Array<String, nil>, nil] value for Google Translate or nil for non-string values
|
72
71
|
def dump_value(value)
|
73
72
|
case value
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
else
|
80
|
-
nil
|
73
|
+
when Array
|
74
|
+
# dump recursively
|
75
|
+
value.map { |v| dump_value v }
|
76
|
+
when String
|
77
|
+
replace_interpolations value
|
81
78
|
end
|
82
79
|
end
|
83
80
|
|
@@ -87,18 +84,18 @@ module I18n::Tasks
|
|
87
84
|
# @return [Object] final translated value
|
88
85
|
def parse_value(untranslated, each_translated)
|
89
86
|
case untranslated
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
87
|
+
when Array
|
88
|
+
# implode array
|
89
|
+
untranslated.map { |from| parse_value(from, each_translated) }
|
90
|
+
when String
|
91
|
+
restore_interpolations untranslated, each_translated.next
|
92
|
+
else
|
93
|
+
untranslated
|
97
94
|
end
|
98
95
|
end
|
99
96
|
|
100
|
-
INTERPOLATION_KEY_RE = /%\{[^}]+\}
|
101
|
-
UNTRANSLATABLE_STRING = 'zxzxzx'
|
97
|
+
INTERPOLATION_KEY_RE = /%\{[^}]+\}/
|
98
|
+
UNTRANSLATABLE_STRING = 'zxzxzx'
|
102
99
|
|
103
100
|
# @param [String] value
|
104
101
|
# @return [String] 'hello, %{name}' => 'hello, <round-trippable string>'
|
data/lib/i18n/tasks/html_keys.rb
CHANGED
@@ -5,9 +5,11 @@ module I18n::Tasks
|
|
5
5
|
MAYBE_PLURAL_HTML_KEY_PATTERN = /[.\-_]html\.[^.]+\z/
|
6
6
|
|
7
7
|
def html_key?(full_key, locale)
|
8
|
+
# rubocop:disable Style/DoubleNegation
|
8
9
|
!!(full_key =~ HTML_KEY_PATTERN ||
|
9
10
|
full_key =~ MAYBE_PLURAL_HTML_KEY_PATTERN &&
|
10
11
|
depluralize_key(split_key(full_key, 2)[1], locale) =~ HTML_KEY_PATTERN)
|
12
|
+
# rubocop:enable Style/DoubleNegation
|
11
13
|
end
|
12
14
|
end
|
13
15
|
end
|
@@ -14,13 +14,14 @@ module I18n::Tasks::IgnoreKeys
|
|
14
14
|
@ignore_patterns ||= HashWithIndifferentAccess.new
|
15
15
|
@ignore_patterns[type] ||= {}
|
16
16
|
@ignore_patterns[type][locale] ||= begin
|
17
|
-
global
|
17
|
+
global = ignore_config.presence || []
|
18
|
+
type_ignore = ignore_config(type).presence || []
|
18
19
|
patterns = if type_ignore.is_a?(Array)
|
19
20
|
global + type_ignore
|
20
21
|
elsif type_ignore.is_a?(Hash)
|
21
22
|
# ignore per locale
|
22
23
|
global + (type_ignore['all'] || []) +
|
23
|
-
|
24
|
+
type_ignore.select { |k, _v| k.to_s =~ /\b#{locale}\b/ }.values.flatten(1).compact
|
24
25
|
end
|
25
26
|
compile_patterns_re patterns
|
26
27
|
end
|
@@ -2,8 +2,9 @@
|
|
2
2
|
require 'strscan'
|
3
3
|
|
4
4
|
module I18n::Tasks::KeyPatternMatching
|
5
|
-
extend self
|
6
|
-
|
5
|
+
extend self # rubocop:disable Style/ModuleFunction
|
6
|
+
|
7
|
+
MATCH_NOTHING = /\z\A/
|
7
8
|
|
8
9
|
# one regex to match any
|
9
10
|
def compile_patterns_re(key_patterns)
|
@@ -11,7 +12,7 @@ module I18n::Tasks::KeyPatternMatching
|
|
11
12
|
# match nothing
|
12
13
|
MATCH_NOTHING
|
13
14
|
else
|
14
|
-
/(?:#{ key_patterns.map { |p| compile_key_pattern p } * '|'
|
15
|
+
/(?:#{ key_patterns.map { |p| compile_key_pattern p } * '|' })/m
|
15
16
|
end
|
16
17
|
end
|
17
18
|
|
@@ -26,10 +27,10 @@ module I18n::Tasks::KeyPatternMatching
|
|
26
27
|
end
|
27
28
|
|
28
29
|
def key_pattern_re_body(key_pattern)
|
29
|
-
key_pattern
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
30
|
+
key_pattern
|
31
|
+
.gsub(/\./, '\.')
|
32
|
+
.gsub(/\*/, '.*')
|
33
|
+
.gsub(/:/, '(?<=^|\.)[^.]+?(?=\.|$)')
|
34
|
+
.gsub(/\{(.*?)}/) { "(#{Regexp.last_match(1).strip.gsub(/\s*,\s*/, '|')})" }
|
34
35
|
end
|
35
36
|
end
|
@@ -1,19 +1,17 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
module I18n::Tasks
|
3
3
|
module LocaleList
|
4
|
-
|
4
|
+
module_function
|
5
5
|
|
6
6
|
# @return locales converted to strings, with base locale first, the rest sorted alphabetically
|
7
7
|
def normalize_locale_list(locales, base_locale, include_base = false)
|
8
8
|
locales = Array(locales).map(&:to_s).sort
|
9
9
|
if locales.include?(base_locale)
|
10
10
|
[base_locale] + (locales - [base_locale])
|
11
|
+
elsif include_base
|
12
|
+
[base_locale] + locales
|
11
13
|
else
|
12
|
-
|
13
|
-
[base_locale] + locales
|
14
|
-
else
|
15
|
-
locales
|
16
|
-
end
|
14
|
+
locales
|
17
15
|
end
|
18
16
|
end
|
19
17
|
end
|
@@ -1,16 +1,16 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
module I18n::Tasks
|
3
3
|
module LocalePathname
|
4
|
-
|
4
|
+
class << self
|
5
|
+
def replace_locale(path, from, to)
|
6
|
+
path && path.gsub(path_locale_re(from), to)
|
7
|
+
end
|
5
8
|
|
6
|
-
|
7
|
-
path && path.gsub(path_locale_re(from), to)
|
8
|
-
end
|
9
|
-
|
10
|
-
private
|
9
|
+
private
|
11
10
|
|
12
|
-
|
13
|
-
|
11
|
+
def path_locale_re(locale)
|
12
|
+
(@path_locale_res ||= {})[locale] ||= %r{(?<=^|[/.])#{locale}(?=[/.])}
|
13
|
+
end
|
14
14
|
end
|
15
15
|
end
|
16
16
|
end
|
data/lib/i18n/tasks/logging.rb
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
module I18n::Tasks::Logging
|
3
|
-
|
3
|
+
module_function
|
4
4
|
|
5
5
|
def warn_deprecated(message)
|
6
6
|
log_stderr Term::ANSIColor.yellow Term::ANSIColor.bold "#{program_name}: [DEPRECATED] #{message}"
|
7
7
|
end
|
8
8
|
|
9
|
-
def log_verbose(message = nil
|
9
|
+
def log_verbose(message = nil)
|
10
10
|
if ::I18n::Tasks.verbose?
|
11
|
-
log_stderr Term::ANSIColor.bright_blue(message ||
|
11
|
+
log_stderr Term::ANSIColor.bright_blue(message || yield)
|
12
12
|
end
|
13
13
|
end
|
14
14
|
|
@@ -2,11 +2,10 @@
|
|
2
2
|
require 'set'
|
3
3
|
module I18n::Tasks
|
4
4
|
module MissingKeys
|
5
|
-
|
6
5
|
MISSING_TYPES = {
|
7
|
-
|
8
|
-
|
9
|
-
}
|
6
|
+
used: { glyph: '✗', summary: 'used in code but missing from base locale' },
|
7
|
+
diff: { glyph: '∅', summary: 'translated in one locale but not in the other' }
|
8
|
+
}.freeze
|
10
9
|
|
11
10
|
def self.missing_keys_types
|
12
11
|
@missing_keys_types ||= MISSING_TYPES.keys
|
@@ -19,9 +18,9 @@ module I18n::Tasks
|
|
19
18
|
# @param types [:missing_used, :missing_diff] all if `nil`.
|
20
19
|
# @return [Siblings]
|
21
20
|
def missing_keys(locales: nil, types: nil, base_locale: nil)
|
22
|
-
locales
|
23
|
-
types
|
24
|
-
base
|
21
|
+
locales ||= self.locales
|
22
|
+
types ||= missing_keys_types
|
23
|
+
base = base_locale || self.base_locale
|
25
24
|
types.inject(empty_forest) do |f, type|
|
26
25
|
f.merge! send(:"missing_#{type}_forest", locales, base)
|
27
26
|
end
|
@@ -29,59 +28,59 @@ module I18n::Tasks
|
|
29
28
|
|
30
29
|
def eq_base_keys(opts = {})
|
31
30
|
locales = Array(opts[:locales]).presence || self.locales
|
32
|
-
(locales - [base_locale]).inject(empty_forest)
|
31
|
+
(locales - [base_locale]).inject(empty_forest) do |tree, locale|
|
33
32
|
tree.merge! equal_values_tree(locale, base_locale)
|
34
|
-
|
33
|
+
end
|
35
34
|
end
|
36
35
|
|
37
36
|
def missing_diff_forest(locales, base = base_locale)
|
38
37
|
tree = empty_forest
|
39
38
|
# present in base but not locale
|
40
|
-
(locales - [base]).each
|
39
|
+
(locales - [base]).each do |locale|
|
41
40
|
tree.merge! missing_diff_tree(locale, base)
|
42
|
-
|
41
|
+
end
|
43
42
|
if locales.include?(base)
|
44
43
|
# present in locale but not base
|
45
|
-
(self.locales - [base]).each
|
44
|
+
(self.locales - [base]).each do |locale|
|
46
45
|
tree.merge! missing_diff_tree(base, locale)
|
47
|
-
|
46
|
+
end
|
48
47
|
end
|
49
48
|
tree
|
50
49
|
end
|
51
50
|
|
52
51
|
def missing_used_forest(locales, _base = base_locale)
|
53
|
-
locales.inject(empty_forest)
|
52
|
+
locales.inject(empty_forest) do |forest, locale|
|
54
53
|
forest.merge! missing_used_tree(locale)
|
55
|
-
|
54
|
+
end
|
56
55
|
end
|
57
56
|
|
58
57
|
# keys present in compared_to, but not in locale
|
59
58
|
def missing_diff_tree(locale, compared_to = base_locale)
|
60
|
-
data[compared_to].select_keys
|
59
|
+
data[compared_to].select_keys do |key, _node|
|
61
60
|
locale_key_missing? locale, depluralize_key(key, compared_to)
|
62
|
-
|
61
|
+
end.set_root_key!(locale, type: :missing_diff).keys do |_key, node|
|
63
62
|
# change path and locale to base
|
64
|
-
data = {locale: locale, missing_diff_locale: node.data[:locale]}
|
63
|
+
data = { locale: locale, missing_diff_locale: node.data[:locale] }
|
65
64
|
if node.data.key?(:path)
|
66
65
|
data[:path] = LocalePathname.replace_locale(node.data[:path], node.data[:locale], locale)
|
67
66
|
end
|
68
67
|
node.data.update data
|
69
|
-
|
68
|
+
end
|
70
69
|
end
|
71
70
|
|
72
71
|
# keys used in the code missing translations in locale
|
73
72
|
def missing_used_tree(locale)
|
74
|
-
used_tree(strict: true).select_keys
|
73
|
+
used_tree(strict: true).select_keys do |key, _node|
|
75
74
|
locale_key_missing?(locale, key)
|
76
|
-
|
75
|
+
end.set_root_key!(locale, type: :missing_used)
|
77
76
|
end
|
78
77
|
|
79
78
|
def equal_values_tree(locale, compare_to = base_locale)
|
80
79
|
base = data[compare_to].first.children
|
81
|
-
data[locale].select_keys(root: false)
|
80
|
+
data[locale].select_keys(root: false) do |key, node|
|
82
81
|
other_node = base[key]
|
83
82
|
other_node && !node.reference? && node.value == other_node.value && !ignore_key?(key, :eq_base, locale)
|
84
|
-
|
83
|
+
end.set_root_key!(locale, type: :eq_base)
|
85
84
|
end
|
86
85
|
|
87
86
|
def locale_key_missing?(locale, key)
|
@@ -96,7 +95,7 @@ module I18n::Tasks
|
|
96
95
|
to_remove = []
|
97
96
|
forest.each do |root|
|
98
97
|
locale = root.key
|
99
|
-
root.keys
|
98
|
+
root.keys do |key, node|
|
100
99
|
next unless yield node
|
101
100
|
if locales_and_node_by_key.key?(key)
|
102
101
|
locales_and_node_by_key[key][0] << locale
|
@@ -104,17 +103,16 @@ module I18n::Tasks
|
|
104
103
|
locales_and_node_by_key[key] = [[locale], node]
|
105
104
|
end
|
106
105
|
to_remove << node
|
107
|
-
|
106
|
+
end
|
108
107
|
end
|
109
108
|
forest.remove_nodes_and_emptied_ancestors! to_remove
|
110
|
-
locales_and_node_by_key.
|
109
|
+
locales_and_node_by_key.each_with_object({}) do |(key, (locales, node)), inv|
|
111
110
|
(inv[locales.sort.join('+')] ||= []) << [key, node]
|
112
|
-
|
113
|
-
|
114
|
-
keys_nodes.each { |(key, node)|
|
111
|
+
end.map do |locales, keys_nodes|
|
112
|
+
keys_nodes.each do |(key, node)|
|
115
113
|
forest["#{locales}.#{key}"] = node
|
116
|
-
|
117
|
-
|
114
|
+
end
|
115
|
+
end
|
118
116
|
forest
|
119
117
|
end
|
120
118
|
end
|