i18n-tasks 0.9.6 → 0.9.7
Sign up to get free protection for your applications and to get access to all the features.
- 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
|