i18n-tasks 0.5.4 → 0.6.0
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/CHANGES.md +9 -0
- data/README.md +46 -36
- data/Rakefile +2 -2
- data/lib/i18n/tasks/base_task.rb +2 -0
- data/lib/i18n/tasks/commands.rb +55 -35
- data/lib/i18n/tasks/commands_base.rb +36 -9
- data/lib/i18n/tasks/configuration.rb +14 -13
- data/lib/i18n/tasks/console_context.rb +0 -1
- data/lib/i18n/tasks/data.rb +2 -2
- data/lib/i18n/tasks/data/adapter/json_adapter.rb +6 -2
- data/lib/i18n/tasks/data/file_formats.rb +19 -4
- data/lib/i18n/tasks/data/file_system_base.rb +1 -1
- data/lib/i18n/tasks/data/tree/node.rb +11 -37
- data/lib/i18n/tasks/data/tree/nodes.rb +6 -2
- data/lib/i18n/tasks/data/tree/siblings.rb +53 -29
- data/lib/i18n/tasks/data/tree/traversal.rb +4 -2
- data/lib/i18n/tasks/fill_tasks.rb +5 -2
- data/lib/i18n/tasks/ignore_keys.rb +1 -1
- data/lib/i18n/tasks/locale_pathname.rb +1 -1
- data/lib/i18n/tasks/logging.rb +2 -0
- data/lib/i18n/tasks/missing_keys.rb +74 -31
- data/lib/i18n/tasks/plural_keys.rb +4 -3
- data/lib/i18n/tasks/reports/base.rb +8 -5
- data/lib/i18n/tasks/reports/spreadsheet.rb +15 -3
- data/lib/i18n/tasks/reports/terminal.rb +62 -23
- data/lib/i18n/tasks/scanners/base_scanner.rb +4 -2
- data/lib/i18n/tasks/scanners/relative_keys.rb +21 -0
- data/lib/i18n/tasks/split_key.rb +39 -0
- data/lib/i18n/tasks/used_keys.rb +1 -1
- data/lib/i18n/tasks/version.rb +1 -1
- data/spec/fixtures/app/views/index.html.slim +2 -0
- data/spec/i18n_tasks_spec.rb +19 -5
- data/spec/locale_pathname_spec.rb +24 -0
- data/spec/locale_tree/siblings_spec.rb +41 -4
- data/spec/split_key_spec.rb +27 -0
- data/spec/support/i18n_tasks_output_matcher.rb +7 -13
- data/spec/support/trees.rb +4 -0
- data/templates/config/i18n-tasks.yml +82 -0
- data/templates/rspec/i18n_spec.rb +18 -0
- metadata +10 -3
- data/lib/i18n/tasks/relative_keys.rb +0 -19
data/lib/i18n/tasks/data.rb
CHANGED
@@ -9,14 +9,18 @@ module I18n::Tasks
|
|
9
9
|
|
10
10
|
# @return [Hash] locale tree
|
11
11
|
def parse(str, opts)
|
12
|
-
JSON.parse(str, opts
|
12
|
+
JSON.parse(str, parse_opts(opts))
|
13
13
|
end
|
14
14
|
|
15
15
|
# @return [String]
|
16
16
|
def dump(tree, opts)
|
17
|
-
JSON.generate(tree, opts
|
17
|
+
JSON.generate(tree, parse_opts(opts))
|
18
18
|
end
|
19
19
|
|
20
|
+
private
|
21
|
+
def parse_opts(opts)
|
22
|
+
opts.try(:symbolize_keys) || {}
|
23
|
+
end
|
20
24
|
end
|
21
25
|
end
|
22
26
|
end
|
@@ -13,6 +13,16 @@ module I18n
|
|
13
13
|
self.class.adapter_for(path)
|
14
14
|
end
|
15
15
|
|
16
|
+
def adapter_by_name(path)
|
17
|
+
self.class.adapter_by_name(path)
|
18
|
+
end
|
19
|
+
|
20
|
+
def adapter_dump(tree, adapter_info)
|
21
|
+
adapter_name, adapter_pattern, adapter = adapter_info
|
22
|
+
adapter_options = (config[adapter_name] || {})[:write]
|
23
|
+
adapter.dump(tree, adapter_options)
|
24
|
+
end
|
25
|
+
|
16
26
|
protected
|
17
27
|
|
18
28
|
def load_file(path)
|
@@ -24,9 +34,7 @@ module I18n
|
|
24
34
|
def write_tree(path, tree)
|
25
35
|
::FileUtils.mkpath(File.dirname path)
|
26
36
|
::File.open(path, 'w') { |f|
|
27
|
-
|
28
|
-
adapter_options = (config[adapter_name] || {})[:write]
|
29
|
-
f.write(adapter.dump(tree.to_hash, adapter_options))
|
37
|
+
f.write(adapter_dump(tree.to_hash, adapter_for(path)))
|
30
38
|
}
|
31
39
|
end
|
32
40
|
|
@@ -38,10 +46,17 @@ module I18n
|
|
38
46
|
end
|
39
47
|
|
40
48
|
def adapter_for(path)
|
41
|
-
@fn_patterns.detect { |(
|
49
|
+
@fn_patterns.detect { |(_name, pattern, _adapter)|
|
42
50
|
::File.fnmatch(pattern, path)
|
43
51
|
} or raise CommandError.new("Adapter not found for #{path}. Registered adapters: #{@fn_patterns.inspect}")
|
44
52
|
end
|
53
|
+
|
54
|
+
def adapter_by_name(name)
|
55
|
+
name = name.to_s
|
56
|
+
@fn_patterns.detect { |(adapter_name, _pattern, _adapter)|
|
57
|
+
adapter_name.to_s == name
|
58
|
+
} or raise CommandError.new("Adapter with name #{name.inspect} not found. Registered adapters: #{@fn_patterns.inspect}")
|
59
|
+
end
|
45
60
|
end
|
46
61
|
end
|
47
62
|
end
|
@@ -111,7 +111,7 @@ module I18n::Tasks
|
|
111
111
|
[path.freeze, load_file(path) || {}]
|
112
112
|
end.map do |path, data|
|
113
113
|
Data::Tree::Siblings.from_nested_hash(data).tap do |s|
|
114
|
-
s.leaves { |x| x.data
|
114
|
+
s.leaves { |x| x.data.update(path: path, locale: locale) }
|
115
115
|
end
|
116
116
|
end.reduce(:merge!) || Tree::Siblings.null
|
117
117
|
end
|
@@ -20,28 +20,19 @@ module I18n::Tasks::Data::Tree
|
|
20
20
|
end
|
21
21
|
|
22
22
|
def derive(new_attr = {})
|
23
|
-
|
24
|
-
node.children = new_attr[:children] || @children.try(:derive, parent: node)
|
25
|
-
node
|
26
|
-
end
|
27
|
-
|
28
|
-
def key=(value)
|
29
|
-
value = value.try(:to_s)
|
30
|
-
if @key != value
|
31
|
-
dirty!
|
32
|
-
parent.try(:children).try(:key_renamed, value, @key)
|
33
|
-
@key = value
|
34
|
-
end
|
23
|
+
self.class.new(attributes.merge(new_attr))
|
35
24
|
end
|
36
25
|
|
37
26
|
def children=(children)
|
27
|
+
@children = case children
|
28
|
+
when Siblings
|
29
|
+
children.parent == self ? children : children.derive(parent: self)
|
30
|
+
when NilClass
|
31
|
+
nil
|
32
|
+
else
|
33
|
+
Siblings.new(nodes: children, parent: self)
|
34
|
+
end
|
38
35
|
dirty!
|
39
|
-
if Siblings === children || children.nil?
|
40
|
-
@children = children
|
41
|
-
@children.parent = self if @children
|
42
|
-
else
|
43
|
-
@children = Siblings.new(nodes: children, parent: self)
|
44
|
-
end
|
45
36
|
end
|
46
37
|
|
47
38
|
def each(&block)
|
@@ -88,19 +79,6 @@ module I18n::Tasks::Data::Tree
|
|
88
79
|
@data.present?
|
89
80
|
end
|
90
81
|
|
91
|
-
# do not use directly. use parent.append(node) instead
|
92
|
-
def parent=(value)
|
93
|
-
return if @parent == value
|
94
|
-
@parent.children.remove!(self) if @parent.try(:children) && @parent.children != value.children
|
95
|
-
@parent = value
|
96
|
-
dirty!
|
97
|
-
@parent
|
98
|
-
end
|
99
|
-
|
100
|
-
def siblings
|
101
|
-
parent.children
|
102
|
-
end
|
103
|
-
|
104
82
|
def get(key)
|
105
83
|
children.get(key)
|
106
84
|
end
|
@@ -151,11 +129,7 @@ module I18n::Tasks::Data::Tree
|
|
151
129
|
end
|
152
130
|
|
153
131
|
def to_siblings
|
154
|
-
|
155
|
-
parent.children
|
156
|
-
else
|
157
|
-
Siblings.new(nodes: [self])
|
158
|
-
end
|
132
|
+
parent.try(:children) || Siblings.new(nodes: [self])
|
159
133
|
end
|
160
134
|
|
161
135
|
def to_hash
|
@@ -201,7 +175,7 @@ module I18n::Tasks::Data::Tree
|
|
201
175
|
def from_key_value(key, value)
|
202
176
|
Node.new(key: key.try(:to_s)).tap do |node|
|
203
177
|
if value.is_a?(Hash)
|
204
|
-
node.children = Siblings.from_nested_hash(value
|
178
|
+
node.children = Siblings.from_nested_hash(value)
|
205
179
|
else
|
206
180
|
node.value = value
|
207
181
|
end
|
@@ -23,8 +23,12 @@ module I18n::Tasks::Data::Tree
|
|
23
23
|
end
|
24
24
|
|
25
25
|
def derive(new_attr = {})
|
26
|
-
attr = attributes.merge(new_attr)
|
27
|
-
|
26
|
+
attr = attributes.except(:nodes, :parent).merge(new_attr)
|
27
|
+
if self.parent
|
28
|
+
new_attr[:parent] ||= Node.null
|
29
|
+
end
|
30
|
+
node_attr = new_attr.slice(:parent)
|
31
|
+
attr[:nodes] ||= @list.map { |node| node.derive(node_attr) }
|
28
32
|
self.class.new(attr)
|
29
33
|
end
|
30
34
|
|
@@ -11,29 +11,31 @@ module I18n::Tasks::Data::Tree
|
|
11
11
|
|
12
12
|
def initialize(opts = {})
|
13
13
|
super(nodes: opts[:nodes])
|
14
|
-
@
|
15
|
-
@parent
|
16
|
-
|
14
|
+
@parent = opts[:parent] || first.try(:parent)
|
15
|
+
@list.map! { |node| node.parent == @parent ? node : node.derive(parent: @parent) }
|
16
|
+
@key_to_node = @list.inject({}) { |h, node| h[node.key] = node; h }
|
17
17
|
end
|
18
18
|
|
19
19
|
def attributes
|
20
20
|
super.merge(parent: @parent)
|
21
21
|
end
|
22
22
|
|
23
|
-
def
|
24
|
-
|
25
|
-
|
26
|
-
|
23
|
+
def rename_key(key, new_key)
|
24
|
+
node = key_to_node.delete(key)
|
25
|
+
replace_node! node, node.derive(key: new_key)
|
26
|
+
self
|
27
27
|
end
|
28
28
|
|
29
|
-
def
|
30
|
-
|
31
|
-
|
29
|
+
def replace_node!(node, new_node)
|
30
|
+
@list[@list.index(node)] = new_node
|
31
|
+
key_to_node[new_node.key] = new_node
|
32
32
|
end
|
33
33
|
|
34
|
+
include SplitKey
|
35
|
+
|
34
36
|
# @return [Node] by full key
|
35
37
|
def get(full_key)
|
36
|
-
first_key, rest = full_key
|
38
|
+
first_key, rest = split_key(full_key, 2)
|
37
39
|
node = key_to_node[first_key]
|
38
40
|
if rest && node
|
39
41
|
node = node.children.try(:get, rest)
|
@@ -45,20 +47,25 @@ module I18n::Tasks::Data::Tree
|
|
45
47
|
|
46
48
|
# add or replace node by full key
|
47
49
|
def set(full_key, node)
|
48
|
-
|
49
|
-
|
50
|
+
raise 'value should be a I18n::Tasks::Data::Tree::Node' unless node.is_a?(Node)
|
51
|
+
key_part, rest = split_key(full_key, 2)
|
52
|
+
child = key_to_node[key_part]
|
53
|
+
|
50
54
|
if rest
|
51
55
|
unless child
|
52
|
-
child = Node.new(key: key_part)
|
56
|
+
child = Node.new(key: key_part, parent: parent, children: [])
|
53
57
|
append! child
|
54
58
|
end
|
55
|
-
child.children
|
59
|
+
unless child.children
|
60
|
+
warn_add_children_to_leaf child
|
61
|
+
child.children = []
|
62
|
+
end
|
56
63
|
child.children.set rest, node
|
57
|
-
dirty!
|
58
64
|
else
|
59
65
|
remove! child if child
|
60
66
|
append! node
|
61
67
|
end
|
68
|
+
dirty!
|
62
69
|
node
|
63
70
|
end
|
64
71
|
|
@@ -74,12 +81,11 @@ module I18n::Tasks::Data::Tree
|
|
74
81
|
end
|
75
82
|
|
76
83
|
def append!(nodes)
|
77
|
-
nodes.
|
78
|
-
raise "
|
79
|
-
key_to_node[node.key] = node
|
80
|
-
node.parent = parent
|
84
|
+
nodes = nodes.map do |node|
|
85
|
+
raise "already has a child with key '#{node.key}'" if key_to_node.key?(node.key)
|
86
|
+
key_to_node[node.key] = (node.parent == parent ? node : node.derive(parent: parent))
|
81
87
|
end
|
82
|
-
super
|
88
|
+
super(nodes)
|
83
89
|
self
|
84
90
|
end
|
85
91
|
|
@@ -95,7 +101,14 @@ module I18n::Tasks::Data::Tree
|
|
95
101
|
next if our == node
|
96
102
|
our.value = node.value if node.leaf?
|
97
103
|
our.data.merge!(node.data) if node.data?
|
98
|
-
|
104
|
+
if node.children?
|
105
|
+
if our.children
|
106
|
+
our.children.merge!(node.children)
|
107
|
+
else
|
108
|
+
warn_add_children_to_leaf our
|
109
|
+
our.children = node.children
|
110
|
+
end
|
111
|
+
end
|
99
112
|
else
|
100
113
|
key_to_node[node.key] = node.derive(parent: parent)
|
101
114
|
end
|
@@ -109,12 +122,22 @@ module I18n::Tasks::Data::Tree
|
|
109
122
|
derive.merge!(nodes)
|
110
123
|
end
|
111
124
|
|
112
|
-
def
|
113
|
-
|
114
|
-
|
125
|
+
def set_root_key(new_key, data = nil)
|
126
|
+
return self if empty?
|
127
|
+
rename_key first.key, new_key
|
128
|
+
leaves { |node| node.data.merge! data } if data
|
129
|
+
self
|
130
|
+
end
|
131
|
+
|
132
|
+
private
|
133
|
+
|
134
|
+
def warn_add_children_to_leaf(node)
|
135
|
+
::I18n::Tasks::Logging.log_warn "'#{node.full_key}' was a leaf, now has children (value <- scope conflict)"
|
115
136
|
end
|
116
137
|
|
117
138
|
class << self
|
139
|
+
include SplitKey
|
140
|
+
|
118
141
|
def null
|
119
142
|
new
|
120
143
|
end
|
@@ -124,14 +147,15 @@ module I18n::Tasks::Data::Tree
|
|
124
147
|
parse_parent_opt!(opts)
|
125
148
|
forest = Siblings.new(opts)
|
126
149
|
block.call(forest) if block
|
127
|
-
forest.parent.children = forest
|
150
|
+
# forest.parent.children = forest
|
151
|
+
forest
|
128
152
|
end
|
129
153
|
|
130
154
|
def from_key_attr(key_attrs, opts = {}, &block)
|
131
155
|
build_forest(opts) { |forest|
|
132
156
|
key_attrs.each { |(full_key, attr)|
|
133
157
|
raise "Invalid key #{full_key.inspect}" if full_key.end_with?('.')
|
134
|
-
node = Node.new(attr.merge(key: full_key
|
158
|
+
node = Node.new(attr.merge(key: split_key(full_key).last))
|
135
159
|
block.call(full_key, node) if block
|
136
160
|
forest[full_key] = node
|
137
161
|
}
|
@@ -141,7 +165,7 @@ module I18n::Tasks::Data::Tree
|
|
141
165
|
def from_key_names(keys, opts = {}, &block)
|
142
166
|
build_forest(opts) { |forest|
|
143
167
|
keys.each { |full_key|
|
144
|
-
node = Node.new(key: full_key
|
168
|
+
node = Node.new(key: split_key(full_key).last)
|
145
169
|
block.call(full_key, node) if block
|
146
170
|
forest[full_key] = node
|
147
171
|
}
|
@@ -162,7 +186,7 @@ module I18n::Tasks::Data::Tree
|
|
162
186
|
def from_flat_pairs(pairs)
|
163
187
|
Siblings.new.tap do |siblings|
|
164
188
|
pairs.each { |full_key, value|
|
165
|
-
siblings[full_key] = Node.new(key: full_key.
|
189
|
+
siblings[full_key] = Node.new(key: split_key(full_key).last, value: value)
|
166
190
|
}
|
167
191
|
end
|
168
192
|
end
|
@@ -64,8 +64,10 @@ module I18n::Tasks::Data::Tree
|
|
64
64
|
keys(opts).map { |key, node| [key, node.value] }
|
65
65
|
end
|
66
66
|
|
67
|
-
def root_key_values
|
68
|
-
keys(root: false).map { |key, node| [node.root.key, key, node.value]}
|
67
|
+
def root_key_values(sort = false)
|
68
|
+
result = keys(root: false).map { |key, node| [node.root.key, key, node.value]}
|
69
|
+
result.sort! { |a, b| a[0] != b[0] ? a[0] <=> b[0] : a[1] <=> b[1] } if sort
|
70
|
+
result
|
69
71
|
end
|
70
72
|
|
71
73
|
#-- modify / derive
|
@@ -5,9 +5,12 @@ module I18n::Tasks
|
|
5
5
|
value = opts[:value] || ''
|
6
6
|
base = opts[:base_locale] || base_locale
|
7
7
|
locales_for_update(opts).each do |locale|
|
8
|
-
m =
|
8
|
+
m = missing_keys(locales: [locale], base_locale: base).keys { |key, node|
|
9
9
|
node.value = value.respond_to?(:call) ? value.call(key, locale, node) : value
|
10
|
-
|
10
|
+
if node.data.key?(:path)
|
11
|
+
# set path hint for the router
|
12
|
+
node.data.update path: LocalePathname.replace_locale(node.data[:path], node.data[:locale], locale), locale: locale
|
13
|
+
end
|
11
14
|
}
|
12
15
|
data[locale] = data[locale].merge! m
|
13
16
|
end
|
@@ -7,7 +7,7 @@ module I18n::Tasks::IgnoreKeys
|
|
7
7
|
key =~ ignore_pattern(ignore_type, locale)
|
8
8
|
end
|
9
9
|
|
10
|
-
# @param type [:missing, :unused, :eq_base] type
|
10
|
+
# @param type [nil, :missing, :unused, :eq_base] type
|
11
11
|
# @param locale [String] only when type is :eq_base
|
12
12
|
# @return [Regexp] a regexp that matches all the keys ignored for the type (and locale)
|
13
13
|
def ignore_pattern(type, locale = nil)
|
data/lib/i18n/tasks/logging.rb
CHANGED
@@ -2,55 +2,98 @@
|
|
2
2
|
module I18n::Tasks
|
3
3
|
module MissingKeys
|
4
4
|
def missing_keys_types
|
5
|
-
@missing_keys_types ||= [:
|
5
|
+
@missing_keys_types ||= [:used, :diff]
|
6
6
|
end
|
7
7
|
|
8
|
-
# @param [:
|
8
|
+
# @param [:missing_used, :missing_diff] type (default nil)
|
9
9
|
# @return [Siblings]
|
10
10
|
def missing_keys(opts = {})
|
11
11
|
locales = Array(opts[:locales]).presence || self.locales
|
12
|
-
types = Array(opts[:
|
12
|
+
types = (Array(opts[:types]).presence || missing_keys_types).map(&:to_s)
|
13
|
+
validate_missing_types! types
|
14
|
+
base = opts[:base_locale] || base_locale
|
15
|
+
tree = Data::Tree::Siblings.new
|
13
16
|
|
14
|
-
types.
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
17
|
+
types.each do |type|
|
18
|
+
tree.merge! send(:"missing_#{type}_forest", locales, base)
|
19
|
+
end
|
20
|
+
tree
|
21
|
+
end
|
22
|
+
|
23
|
+
def eq_base_keys(opts = {})
|
24
|
+
locales = Array(opts[:locales]).presence || self.locales
|
25
|
+
(locales - [base_locale]).inject(Data::Tree::Siblings.new) { |tree, locale|
|
26
|
+
tree.merge! equal_values_tree(locale, base_locale)
|
27
|
+
}
|
28
|
+
end
|
29
|
+
|
30
|
+
def missing_diff_forest(locales, base = base_locale)
|
31
|
+
tree = Data::Tree::Siblings.new
|
32
|
+
# present in base but not locale
|
33
|
+
(locales - [base]).each { |locale|
|
34
|
+
tree.merge! missing_diff_tree(locale, base)
|
35
|
+
}
|
36
|
+
if locales.include?(base)
|
37
|
+
# present in locale but not base
|
38
|
+
(self.locales - [base]).each { |locale|
|
39
|
+
tree.merge! missing_diff_tree(base, locale).set_root_key(base)
|
40
|
+
}
|
41
|
+
end
|
42
|
+
tree
|
43
|
+
end
|
44
|
+
|
45
|
+
def missing_used_forest(locales, base = base_locale)
|
46
|
+
if locales.include?(base)
|
47
|
+
missing_used_tree(base)
|
48
|
+
else
|
49
|
+
Data::Tree::Siblings.new
|
50
|
+
end
|
24
51
|
end
|
25
52
|
|
26
|
-
def missing_tree(locale, compared_to
|
53
|
+
def missing_tree(locale, compared_to)
|
27
54
|
if locale == compared_to
|
28
|
-
|
29
|
-
set_locale_tree_type used_tree.select_keys { |key, node|
|
30
|
-
!(key_expression?(key) || key_value?(key, locale) || ignore_key?(key, :missing))
|
31
|
-
}, locale, :missing_from_base
|
55
|
+
missing_used_tree locale
|
32
56
|
else
|
33
|
-
|
34
|
-
collapse_plural_nodes! set_locale_tree_type data[compared_to].select_keys { |key, node|
|
35
|
-
!key_value?(key, locale) && !ignore_key?(key, :missing)
|
36
|
-
}, locale, :missing_from_locale
|
57
|
+
missing_diff_tree locale, compared_to
|
37
58
|
end
|
38
59
|
end
|
39
60
|
|
40
|
-
|
61
|
+
# keys present in compared_to, but not in locale
|
62
|
+
def missing_diff_tree(locale, compared_to = base_locale)
|
63
|
+
data[compared_to].select_keys { |key, _node|
|
64
|
+
locale_key_missing?(locale, key)
|
65
|
+
}.set_root_key(locale, type: :missing_diff).tap { |t| collapse_plural_nodes!(t) }
|
66
|
+
end
|
67
|
+
|
68
|
+
# keys used in the code missing translations in locale
|
69
|
+
def missing_used_tree(locale)
|
70
|
+
used_tree.select_keys { |key, _node|
|
71
|
+
!key_expression?(key) && locale_key_missing?(locale, key)
|
72
|
+
}.set_root_key(locale, type: :missing_used)
|
73
|
+
end
|
74
|
+
|
75
|
+
def equal_values_tree(locale, compare_to = base_locale)
|
41
76
|
base = data[compare_to].first.children
|
42
|
-
|
77
|
+
data[locale].select_keys(root: false) { |key, node|
|
43
78
|
other_node = base[key]
|
44
79
|
other_node && node.value == other_node.value && !ignore_key?(key, :eq_base, locale)
|
45
|
-
}
|
80
|
+
}.set_root_key(locale, type: :eq_base)
|
46
81
|
end
|
47
82
|
|
48
|
-
def
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
83
|
+
def locale_key_missing?(locale, key)
|
84
|
+
!key_value?(key, locale) && !ignore_key?(key, :missing)
|
85
|
+
end
|
86
|
+
|
87
|
+
private
|
88
|
+
|
89
|
+
def validate_missing_types!(types)
|
90
|
+
valid_types = missing_keys_types.map(&:to_s)
|
91
|
+
types = types.map(&:to_s)
|
92
|
+
invalid_types = types - valid_types
|
93
|
+
if invalid_types.present?
|
94
|
+
raise CommandError.new("Unknown types: #{invalid_types * ', '}. Valid types are: #{valid_types * ', '}.")
|
95
|
+
end
|
96
|
+
true
|
54
97
|
end
|
55
98
|
end
|
56
99
|
end
|