i18n-tasks 1.0.14 → 1.1.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/README.md +138 -39
- data/Rakefile +4 -4
- data/bin/i18n-tasks +3 -3
- data/config/locales/en.yml +17 -1
- data/config/locales/ru.yml +18 -1
- data/i18n-tasks.gemspec +28 -38
- data/lib/i18n/tasks/base_task.rb +19 -19
- data/lib/i18n/tasks/cli.rb +37 -30
- data/lib/i18n/tasks/command/collection.rb +4 -4
- data/lib/i18n/tasks/command/commander.rb +5 -5
- data/lib/i18n/tasks/command/commands/check_prism.rb +126 -0
- data/lib/i18n/tasks/command/commands/data.rb +33 -33
- data/lib/i18n/tasks/command/commands/eq_base.rb +3 -3
- data/lib/i18n/tasks/command/commands/health.rb +6 -5
- data/lib/i18n/tasks/command/commands/interpolations.rb +14 -3
- data/lib/i18n/tasks/command/commands/meta.rb +6 -6
- data/lib/i18n/tasks/command/commands/missing.rb +28 -26
- data/lib/i18n/tasks/command/commands/tree.rb +33 -33
- data/lib/i18n/tasks/command/commands/usages.rb +24 -24
- data/lib/i18n/tasks/command/dsl.rb +1 -1
- data/lib/i18n/tasks/command/option_parsers/enum.rb +8 -7
- data/lib/i18n/tasks/command/option_parsers/locale.rb +4 -4
- data/lib/i18n/tasks/command/options/common.rb +16 -16
- data/lib/i18n/tasks/command/options/data.rb +18 -18
- data/lib/i18n/tasks/command/options/locales.rb +33 -24
- data/lib/i18n/tasks/commands.rb +14 -12
- data/lib/i18n/tasks/concurrent/cache.rb +1 -1
- data/lib/i18n/tasks/concurrent/cached_value.rb +1 -1
- data/lib/i18n/tasks/configuration.rb +26 -20
- data/lib/i18n/tasks/console_context.rb +11 -11
- data/lib/i18n/tasks/data/adapter/json_adapter.rb +1 -1
- data/lib/i18n/tasks/data/adapter/yaml_adapter.rb +5 -5
- data/lib/i18n/tasks/data/file_formats.rb +3 -3
- data/lib/i18n/tasks/data/file_system.rb +5 -5
- data/lib/i18n/tasks/data/file_system_base.rb +26 -26
- data/lib/i18n/tasks/data/language_names.rb +202 -0
- data/lib/i18n/tasks/data/router/conservative_router.rb +3 -3
- data/lib/i18n/tasks/data/router/isolating_router.rb +19 -19
- data/lib/i18n/tasks/data/router/pattern_router.rb +5 -5
- data/lib/i18n/tasks/data/tree/node.rb +27 -27
- data/lib/i18n/tasks/data/tree/nodes.rb +10 -10
- data/lib/i18n/tasks/data/tree/siblings.rb +20 -20
- data/lib/i18n/tasks/data/tree/traversal.rb +5 -5
- data/lib/i18n/tasks/data.rb +4 -4
- data/lib/i18n/tasks/html_keys.rb +2 -2
- data/lib/i18n/tasks/ignore_keys.rb +9 -9
- data/lib/i18n/tasks/interpolations.rb +21 -1
- data/lib/i18n/tasks/key_pattern_matching.rb +8 -8
- data/lib/i18n/tasks/logging.rb +2 -1
- data/lib/i18n/tasks/missing_keys.rb +24 -8
- data/lib/i18n/tasks/plural_keys.rb +6 -4
- data/lib/i18n/tasks/references.rb +4 -4
- data/lib/i18n/tasks/reports/base.rb +18 -14
- data/lib/i18n/tasks/reports/terminal.rb +64 -47
- data/lib/i18n/tasks/scanners/ast_matchers/base_matcher.rb +3 -3
- data/lib/i18n/tasks/scanners/ast_matchers/default_i18n_subject_matcher.rb +3 -3
- data/lib/i18n/tasks/scanners/ast_matchers/message_receivers_matcher.rb +10 -10
- data/lib/i18n/tasks/scanners/ast_matchers/rails_model_matcher.rb +2 -2
- data/lib/i18n/tasks/scanners/erb_ast_scanner.rb +69 -10
- data/lib/i18n/tasks/scanners/file_scanner.rb +5 -5
- data/lib/i18n/tasks/scanners/files/caching_file_finder.rb +3 -3
- data/lib/i18n/tasks/scanners/files/caching_file_finder_provider.rb +3 -3
- data/lib/i18n/tasks/scanners/files/caching_file_reader.rb +2 -2
- data/lib/i18n/tasks/scanners/files/file_finder.rb +8 -8
- data/lib/i18n/tasks/scanners/files/file_reader.rb +1 -1
- data/lib/i18n/tasks/scanners/local_ruby_parser.rb +9 -9
- data/lib/i18n/tasks/scanners/occurrence_from_position.rb +1 -1
- data/lib/i18n/tasks/scanners/pattern_mapper.rb +7 -7
- data/lib/i18n/tasks/scanners/pattern_scanner.rb +20 -20
- data/lib/i18n/tasks/scanners/pattern_with_scope_scanner.rb +8 -8
- data/lib/i18n/tasks/scanners/prism_scanners/arguments_visitor.rb +48 -0
- data/lib/i18n/tasks/scanners/prism_scanners/nodes.rb +374 -0
- data/lib/i18n/tasks/scanners/prism_scanners/visitor.rb +337 -0
- data/lib/i18n/tasks/scanners/relative_keys.rb +8 -8
- data/lib/i18n/tasks/scanners/results/key_occurrences.rb +3 -3
- data/lib/i18n/tasks/scanners/results/occurrence.rb +14 -10
- data/lib/i18n/tasks/scanners/ruby_ast_call_finder.rb +1 -1
- data/lib/i18n/tasks/scanners/ruby_key_literals.rb +6 -6
- data/lib/i18n/tasks/scanners/ruby_parser_factory.rb +27 -0
- data/lib/i18n/tasks/scanners/ruby_scanner.rb +225 -0
- data/lib/i18n/tasks/scanners/scanner.rb +2 -2
- data/lib/i18n/tasks/scanners/scanner_multiplexer.rb +1 -1
- data/lib/i18n/tasks/split_key.rb +4 -4
- data/lib/i18n/tasks/stats.rb +3 -3
- data/lib/i18n/tasks/translation.rb +8 -5
- data/lib/i18n/tasks/translators/base_translator.rb +43 -13
- data/lib/i18n/tasks/translators/deepl_translator.rb +22 -14
- data/lib/i18n/tasks/translators/google_translator.rb +178 -26
- data/lib/i18n/tasks/translators/openai_translator.rb +56 -31
- data/lib/i18n/tasks/translators/watsonx_translator.rb +155 -0
- data/lib/i18n/tasks/translators/yandex_translator.rb +13 -9
- data/lib/i18n/tasks/unused_keys.rb +1 -1
- data/lib/i18n/tasks/used_keys.rb +32 -32
- data/lib/i18n/tasks/version.rb +1 -1
- data/lib/i18n/tasks.rb +17 -16
- data/templates/config/i18n-tasks.yml +14 -2
- data/templates/minitest/i18n_test.rb +3 -3
- data/templates/rspec/i18n_spec.rb +7 -7
- metadata +38 -172
- data/lib/i18n/tasks/scanners/ruby_ast_scanner.rb +0 -145
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require
|
|
4
|
-
require
|
|
3
|
+
require "i18n/tasks/key_pattern_matching"
|
|
4
|
+
require "i18n/tasks/data/tree/node"
|
|
5
5
|
|
|
6
6
|
module I18n::Tasks
|
|
7
7
|
module Data::Router
|
|
@@ -52,11 +52,11 @@ module I18n::Tasks
|
|
|
52
52
|
source_path = source_path.dup
|
|
53
53
|
|
|
54
54
|
config_read_patterns.each do |pattern|
|
|
55
|
-
regexp = Glob.new(format(pattern, locale:
|
|
55
|
+
regexp = Glob.new(format(pattern, locale: "(*)")).to_regexp
|
|
56
56
|
next unless source_path.match?(regexp)
|
|
57
57
|
|
|
58
58
|
source_path.match(regexp) do |match_data|
|
|
59
|
-
(1..match_data.size - 1).reverse_each do |capture_index|
|
|
59
|
+
(1..(match_data.size - 1)).reverse_each do |capture_index|
|
|
60
60
|
capture_begin, capture_end = match_data.offset(capture_index)
|
|
61
61
|
source_path.slice!(Range.new(capture_begin, capture_end, true))
|
|
62
62
|
source_path.insert(capture_begin, locale.to_s)
|
|
@@ -92,29 +92,29 @@ module I18n::Tasks
|
|
|
92
92
|
end
|
|
93
93
|
|
|
94
94
|
case char
|
|
95
|
-
when
|
|
96
|
-
when
|
|
97
|
-
when
|
|
98
|
-
when
|
|
99
|
-
when
|
|
95
|
+
when "**" then "(?:[^/]+/)*"
|
|
96
|
+
when "*" then ".*"
|
|
97
|
+
when "?" then "."
|
|
98
|
+
when "." then '\.'
|
|
99
|
+
when "{"
|
|
100
100
|
curlies += 1
|
|
101
|
-
|
|
102
|
-
when
|
|
101
|
+
"("
|
|
102
|
+
when "}"
|
|
103
103
|
if curlies.positive?
|
|
104
104
|
curlies -= 1
|
|
105
|
-
|
|
105
|
+
")"
|
|
106
106
|
else
|
|
107
107
|
char
|
|
108
108
|
end
|
|
109
|
-
when
|
|
109
|
+
when ","
|
|
110
110
|
if curlies.positive?
|
|
111
|
-
|
|
111
|
+
"|"
|
|
112
112
|
else
|
|
113
113
|
char
|
|
114
114
|
end
|
|
115
|
-
when
|
|
115
|
+
when "\\"
|
|
116
116
|
escaping = true
|
|
117
|
-
|
|
117
|
+
"\\"
|
|
118
118
|
else char
|
|
119
119
|
end
|
|
120
120
|
end.join
|
|
@@ -130,10 +130,10 @@ module I18n::Tasks
|
|
|
130
130
|
out = []
|
|
131
131
|
until chars.empty?
|
|
132
132
|
char = chars.shift
|
|
133
|
-
if char ==
|
|
133
|
+
if char == "*" && chars.first == "*"
|
|
134
134
|
chars.shift
|
|
135
|
-
chars.shift if chars.first ==
|
|
136
|
-
out.push(
|
|
135
|
+
chars.shift if chars.first == "/"
|
|
136
|
+
out.push("**")
|
|
137
137
|
else
|
|
138
138
|
out.push(char)
|
|
139
139
|
end
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require
|
|
4
|
-
require
|
|
3
|
+
require "i18n/tasks/key_pattern_matching"
|
|
4
|
+
require "i18n/tasks/data/tree/node"
|
|
5
5
|
|
|
6
6
|
module I18n::Tasks
|
|
7
7
|
module Data::Router
|
|
@@ -37,7 +37,7 @@ module I18n::Tasks
|
|
|
37
37
|
pattern, path = routes.detect { |route| route[0] =~ key }
|
|
38
38
|
if pattern
|
|
39
39
|
key_match = $~
|
|
40
|
-
path
|
|
40
|
+
path = format(path, locale: locale)
|
|
41
41
|
path.gsub!(/\\\d+/) { |m| key_match[m[1..].to_i] }
|
|
42
42
|
(out[path] ||= Set.new) << "#{locale}.#{key}"
|
|
43
43
|
else
|
|
@@ -46,14 +46,14 @@ module I18n::Tasks
|
|
|
46
46
|
end
|
|
47
47
|
out.each do |dest, keys|
|
|
48
48
|
block.yield dest,
|
|
49
|
-
|
|
49
|
+
forest.select_keys(root: true) { |key, _| keys.include?(key) }
|
|
50
50
|
end
|
|
51
51
|
end
|
|
52
52
|
|
|
53
53
|
private
|
|
54
54
|
|
|
55
55
|
def compile_routes(routes)
|
|
56
|
-
routes.map { |x| x.is_a?(String) ? [
|
|
56
|
+
routes.map { |x| x.is_a?(String) ? ["*", x] : x }.map do |x|
|
|
57
57
|
[compile_key_pattern(x[0]), x[1]]
|
|
58
58
|
end
|
|
59
59
|
end
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require
|
|
4
|
-
require
|
|
3
|
+
require "i18n/tasks/data/tree/traversal"
|
|
4
|
+
require "i18n/tasks/data/tree/siblings"
|
|
5
5
|
module I18n::Tasks::Data::Tree
|
|
6
6
|
class Node # rubocop:disable Metrics/ClassLength
|
|
7
7
|
include Enumerable
|
|
@@ -23,26 +23,26 @@ module I18n::Tasks::Data::Tree
|
|
|
23
23
|
# rubocop:enable Metrics/ParameterLists
|
|
24
24
|
|
|
25
25
|
def attributes
|
|
26
|
-
{
|
|
26
|
+
{key: @key, value: @value, data: @data.try(:clone), parent: @parent, children: @children}
|
|
27
27
|
end
|
|
28
28
|
|
|
29
29
|
def derive(new_attr = {})
|
|
30
|
-
self.class.new(**attributes
|
|
30
|
+
self.class.new(**attributes, **new_attr)
|
|
31
31
|
end
|
|
32
32
|
|
|
33
33
|
def children=(children)
|
|
34
34
|
@children = case children
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
35
|
+
when Siblings
|
|
36
|
+
(children.parent == self) ? children : children.derive(parent: self)
|
|
37
|
+
when NilClass
|
|
38
|
+
nil
|
|
39
|
+
else
|
|
40
|
+
Siblings.new(
|
|
41
|
+
nodes: children,
|
|
42
|
+
parent: self,
|
|
43
|
+
warn_about_add_children_to_leaf: @warn_about_add_children_to_leaf
|
|
44
|
+
)
|
|
45
|
+
end
|
|
46
46
|
dirty!
|
|
47
47
|
end
|
|
48
48
|
|
|
@@ -90,7 +90,7 @@ module I18n::Tasks::Data::Tree
|
|
|
90
90
|
children.get(key)
|
|
91
91
|
end
|
|
92
92
|
|
|
93
|
-
|
|
93
|
+
alias_method :[], :get
|
|
94
94
|
|
|
95
95
|
# append and reparent nodes
|
|
96
96
|
def append!(nodes)
|
|
@@ -138,7 +138,7 @@ module I18n::Tasks::Data::Tree
|
|
|
138
138
|
node
|
|
139
139
|
end
|
|
140
140
|
|
|
141
|
-
|
|
141
|
+
alias_method :[]=, :set
|
|
142
142
|
|
|
143
143
|
def to_nodes
|
|
144
144
|
Nodes.new([self])
|
|
@@ -154,9 +154,9 @@ module I18n::Tasks::Data::Tree
|
|
|
154
154
|
if key.nil?
|
|
155
155
|
children_hash
|
|
156
156
|
elsif leaf?
|
|
157
|
-
{
|
|
157
|
+
{key => value}
|
|
158
158
|
else
|
|
159
|
-
{
|
|
159
|
+
{key => children_hash}
|
|
160
160
|
end
|
|
161
161
|
end
|
|
162
162
|
end
|
|
@@ -166,18 +166,18 @@ module I18n::Tasks::Data::Tree
|
|
|
166
166
|
|
|
167
167
|
def inspect(level = 0)
|
|
168
168
|
label = if key.nil?
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
[
|
|
169
|
+
Rainbow("∅").faint
|
|
170
|
+
else
|
|
171
|
+
[Rainbow(key).color(1 + (level % 15)),
|
|
172
|
+
(": #{format_value_for_inspect(value)}" if leaf?),
|
|
173
|
+
(" #{data}" if data?)].compact.join
|
|
174
|
+
end
|
|
175
|
+
[" " * level, label, ("\n#{children.map { |c| c.inspect(level + 1) }.join("\n")}" if children?)].compact.join
|
|
176
176
|
end
|
|
177
177
|
|
|
178
178
|
def format_value_for_inspect(value)
|
|
179
179
|
if value.is_a?(Symbol)
|
|
180
|
-
"#{Rainbow(
|
|
180
|
+
"#{Rainbow("⮕ ").bright.yellow}#{Rainbow(value).yellow}"
|
|
181
181
|
else
|
|
182
182
|
Rainbow(value).cyan
|
|
183
183
|
end
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require
|
|
3
|
+
require "i18n/tasks/data/tree/traversal"
|
|
4
4
|
module I18n::Tasks::Data::Tree
|
|
5
5
|
# A list of nodes
|
|
6
6
|
class Nodes
|
|
@@ -20,7 +20,7 @@ module I18n::Tasks::Data::Tree
|
|
|
20
20
|
end
|
|
21
21
|
|
|
22
22
|
def attributes
|
|
23
|
-
{
|
|
23
|
+
{nodes: @list}
|
|
24
24
|
end
|
|
25
25
|
|
|
26
26
|
def derive(new_attr = {})
|
|
@@ -32,10 +32,10 @@ module I18n::Tasks::Data::Tree
|
|
|
32
32
|
|
|
33
33
|
def to_hash(sort = false)
|
|
34
34
|
(@hash ||= {})[sort] ||= if sort
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
35
|
+
sort_by(&:key)
|
|
36
|
+
else
|
|
37
|
+
self
|
|
38
|
+
end.map { |node| node.to_hash(sort) }.reduce({}, :deep_merge!)
|
|
39
39
|
end
|
|
40
40
|
|
|
41
41
|
delegate :to_json, to: :to_hash
|
|
@@ -45,7 +45,7 @@ module I18n::Tasks::Data::Tree
|
|
|
45
45
|
if present?
|
|
46
46
|
map(&:inspect) * "\n"
|
|
47
47
|
else
|
|
48
|
-
Rainbow(
|
|
48
|
+
Rainbow("{∅}").faint
|
|
49
49
|
end
|
|
50
50
|
end
|
|
51
51
|
|
|
@@ -67,14 +67,14 @@ module I18n::Tasks::Data::Tree
|
|
|
67
67
|
derive.append!(other)
|
|
68
68
|
end
|
|
69
69
|
|
|
70
|
-
|
|
70
|
+
alias_method :<<, :append
|
|
71
71
|
|
|
72
72
|
def merge!(nodes)
|
|
73
73
|
@list += nodes.to_a
|
|
74
74
|
dirty!
|
|
75
75
|
self
|
|
76
76
|
end
|
|
77
|
-
|
|
77
|
+
alias_method :+, :merge!
|
|
78
78
|
|
|
79
79
|
def children(&block)
|
|
80
80
|
return to_enum(:children) { map { |c| c.children ? c.children.size : 0 }.reduce(:+) } unless block
|
|
@@ -84,7 +84,7 @@ module I18n::Tasks::Data::Tree
|
|
|
84
84
|
end
|
|
85
85
|
end
|
|
86
86
|
|
|
87
|
-
|
|
87
|
+
alias_method :children?, :any?
|
|
88
88
|
|
|
89
89
|
protected
|
|
90
90
|
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require
|
|
4
|
-
require
|
|
5
|
-
require
|
|
3
|
+
require "set"
|
|
4
|
+
require "i18n/tasks/split_key"
|
|
5
|
+
require "i18n/tasks/data/tree/nodes"
|
|
6
6
|
|
|
7
7
|
module I18n::Tasks::Data::Tree
|
|
8
8
|
# Siblings represents a subtree sharing a common parent
|
|
@@ -17,7 +17,7 @@ module I18n::Tasks::Data::Tree
|
|
|
17
17
|
def initialize(opts = {})
|
|
18
18
|
super(nodes: opts[:nodes])
|
|
19
19
|
@parent = opts[:parent] || first.try(:parent)
|
|
20
|
-
@list.map! { |node| node.parent == @parent ? node : node.derive(parent: @parent) }
|
|
20
|
+
@list.map! { |node| (node.parent == @parent) ? node : node.derive(parent: @parent) }
|
|
21
21
|
@key_to_node = @list.each_with_object({}) { |node, h| h[node.key] = node }
|
|
22
22
|
@warn_about_add_children_to_leaf = opts.fetch(:warn_about_add_children_to_leaf, true)
|
|
23
23
|
end
|
|
@@ -52,7 +52,7 @@ module I18n::Tasks::Data::Tree
|
|
|
52
52
|
new_key = to_pattern.gsub(/\\\d+/) { |m| match[m[1..].to_i] }
|
|
53
53
|
old_key_to_new_key[full_key] = new_key
|
|
54
54
|
moved_forest.merge!(Siblings.new.tap do |forest|
|
|
55
|
-
forest[[(node.root.try(:key) unless root), new_key].compact.join(
|
|
55
|
+
forest[[(node.root.try(:key) unless root), new_key].compact.join(".")] =
|
|
56
56
|
node.derive(key: split_key(new_key).last)
|
|
57
57
|
end)
|
|
58
58
|
end
|
|
@@ -62,10 +62,10 @@ module I18n::Tasks::Data::Tree
|
|
|
62
62
|
nodes do |node|
|
|
63
63
|
next unless node.reference?
|
|
64
64
|
|
|
65
|
-
old_target = [(node.root.key if root), node.value.to_s].compact.join(
|
|
65
|
+
old_target = [(node.root.key if root), node.value.to_s].compact.join(".")
|
|
66
66
|
new_target = old_key_to_new_key[old_target]
|
|
67
67
|
if new_target
|
|
68
|
-
new_target = new_target.sub(/\A[^.]*\./,
|
|
68
|
+
new_target = new_target.sub(/\A[^.]*\./, "") if root
|
|
69
69
|
node.value = new_target.to_sym
|
|
70
70
|
end
|
|
71
71
|
end
|
|
@@ -75,26 +75,26 @@ module I18n::Tasks::Data::Tree
|
|
|
75
75
|
end
|
|
76
76
|
|
|
77
77
|
def replace_node!(node, new_node)
|
|
78
|
-
@list[@list.index(node)]
|
|
78
|
+
@list[@list.index(node)] = new_node
|
|
79
79
|
key_to_node[new_node.key] = new_node
|
|
80
80
|
end
|
|
81
81
|
|
|
82
82
|
# @return [Node] by full key
|
|
83
83
|
def get(full_key)
|
|
84
84
|
first_key, rest = split_key(full_key.to_s, 2)
|
|
85
|
-
node
|
|
85
|
+
node = key_to_node[first_key]
|
|
86
86
|
node = node.children.try(:get, rest) if rest && node
|
|
87
87
|
node
|
|
88
88
|
end
|
|
89
89
|
|
|
90
|
-
|
|
90
|
+
alias_method :[], :get
|
|
91
91
|
|
|
92
92
|
# add or replace node by full key
|
|
93
93
|
def set(full_key, node)
|
|
94
|
-
fail
|
|
94
|
+
fail "value should be a I18n::Tasks::Data::Tree::Node" unless node.is_a?(Node)
|
|
95
95
|
|
|
96
96
|
key_part, rest = split_key(full_key, 2)
|
|
97
|
-
child
|
|
97
|
+
child = key_to_node[key_part]
|
|
98
98
|
|
|
99
99
|
if rest
|
|
100
100
|
unless child
|
|
@@ -119,7 +119,7 @@ module I18n::Tasks::Data::Tree
|
|
|
119
119
|
node
|
|
120
120
|
end
|
|
121
121
|
|
|
122
|
-
|
|
122
|
+
alias_method :[]=, :set
|
|
123
123
|
|
|
124
124
|
# methods below change state
|
|
125
125
|
|
|
@@ -133,9 +133,9 @@ module I18n::Tasks::Data::Tree
|
|
|
133
133
|
nodes = nodes.map do |node|
|
|
134
134
|
fail "already has a child with key '#{node.key}'" if key_to_node.key?(node.key)
|
|
135
135
|
|
|
136
|
-
key_to_node[node.key] = (node.parent == parent ? node : node.derive(parent: parent))
|
|
136
|
+
key_to_node[node.key] = ((node.parent == parent) ? node : node.derive(parent: parent))
|
|
137
137
|
end
|
|
138
|
-
super
|
|
138
|
+
super
|
|
139
139
|
self
|
|
140
140
|
end
|
|
141
141
|
|
|
@@ -267,7 +267,7 @@ module I18n::Tasks::Data::Tree
|
|
|
267
267
|
key_occurrences.each do |key_occurrence|
|
|
268
268
|
forest[key_occurrence.key] = ::I18n::Tasks::Data::Tree::Node.new(
|
|
269
269
|
key: split_key(key_occurrence.key).last,
|
|
270
|
-
data: {
|
|
270
|
+
data: {occurrences: key_occurrence.occurrences}
|
|
271
271
|
)
|
|
272
272
|
end
|
|
273
273
|
end
|
|
@@ -276,9 +276,9 @@ module I18n::Tasks::Data::Tree
|
|
|
276
276
|
def from_key_attr(key_attrs, opts = {}, &block)
|
|
277
277
|
build_forest(opts) do |forest|
|
|
278
278
|
key_attrs.each do |(full_key, attr)|
|
|
279
|
-
fail "Invalid key #{full_key.inspect}" if full_key.end_with?(
|
|
279
|
+
fail "Invalid key #{full_key.inspect}" if full_key.end_with?(".")
|
|
280
280
|
|
|
281
|
-
node = ::I18n::Tasks::Data::Tree::Node.new(**attr
|
|
281
|
+
node = ::I18n::Tasks::Data::Tree::Node.new(**attr, key: split_key(full_key).last)
|
|
282
282
|
yield(full_key, node) if block
|
|
283
283
|
forest[full_key] = node
|
|
284
284
|
end
|
|
@@ -305,7 +305,7 @@ module I18n::Tasks::Data::Tree
|
|
|
305
305
|
Siblings.new(opts)
|
|
306
306
|
end
|
|
307
307
|
|
|
308
|
-
|
|
308
|
+
alias_method :[], :from_nested_hash
|
|
309
309
|
|
|
310
310
|
# build forest from [[Full Key, Value]]
|
|
311
311
|
def from_flat_pairs(pairs)
|
|
@@ -323,7 +323,7 @@ module I18n::Tasks::Data::Tree
|
|
|
323
323
|
opts[:parent] = ::I18n::Tasks::Data::Tree::Node.new(opts[:parent_attr]) if opts[:parent_attr]
|
|
324
324
|
if opts[:parent_locale]
|
|
325
325
|
opts[:parent] = ::I18n::Tasks::Data::Tree::Node.new(
|
|
326
|
-
key: opts[:parent_locale], data: {
|
|
326
|
+
key: opts[:parent_locale], data: {locale: opts[:parent_locale]}
|
|
327
327
|
)
|
|
328
328
|
end
|
|
329
329
|
end
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require
|
|
3
|
+
require "set"
|
|
4
4
|
|
|
5
5
|
module I18n::Tasks
|
|
6
6
|
module Data::Tree
|
|
7
7
|
# Any Enumerable that yields nodes can mix in this module
|
|
8
8
|
module Traversal # rubocop:disable Metrics/ModuleLength
|
|
9
|
-
def nodes(&
|
|
10
|
-
depth_first(&
|
|
9
|
+
def nodes(&)
|
|
10
|
+
depth_first(&)
|
|
11
11
|
end
|
|
12
12
|
|
|
13
13
|
def leaves(&visitor)
|
|
@@ -76,13 +76,13 @@ module I18n::Tasks
|
|
|
76
76
|
|
|
77
77
|
def root_key_values(sort = false)
|
|
78
78
|
result = keys(root: false).map { |key, node| [node.root.key, key, node.value] }
|
|
79
|
-
result.sort! { |a, b| a[0] == b[0] ? a[1] <=> b[1] : a[0] <=> b[0] } if sort
|
|
79
|
+
result.sort! { |a, b| (a[0] == b[0]) ? a[1] <=> b[1] : a[0] <=> b[0] } if sort
|
|
80
80
|
result
|
|
81
81
|
end
|
|
82
82
|
|
|
83
83
|
def root_key_value_data(sort = false)
|
|
84
84
|
result = keys(root: false).map { |key, node| [node.root.key, key, node.value, node.data] }
|
|
85
|
-
result.sort! { |a, b| a[0] == b[0] ? a[1] <=> b[1] : a[0] <=> b[0] } if sort
|
|
85
|
+
result.sort! { |a, b| (a[0] == b[0]) ? a[1] <=> b[1] : a[0] <=> b[0] } if sort
|
|
86
86
|
result
|
|
87
87
|
end
|
|
88
88
|
|
data/lib/i18n/tasks/data.rb
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require
|
|
3
|
+
require "i18n/tasks/data/file_system"
|
|
4
4
|
|
|
5
5
|
module I18n::Tasks
|
|
6
6
|
module Data
|
|
7
7
|
DATA_DEFAULTS = {
|
|
8
|
-
adapter:
|
|
8
|
+
adapter: "I18n::Tasks::Data::FileSystem"
|
|
9
9
|
}.freeze
|
|
10
10
|
|
|
11
11
|
# I18n data provider
|
|
@@ -17,7 +17,7 @@ module I18n::Tasks
|
|
|
17
17
|
data_config[:locales] = config[:locales]
|
|
18
18
|
adapter_class = data_config[:adapter].presence || data_config[:class].presence || DATA_DEFAULTS[:adapter]
|
|
19
19
|
adapter_class = adapter_class.to_s
|
|
20
|
-
adapter_class =
|
|
20
|
+
adapter_class = "I18n::Tasks::Data::FileSystem" if adapter_class == "file_system"
|
|
21
21
|
data_config.except!(:adapter, :class)
|
|
22
22
|
ActiveSupport::Inflector.constantize(adapter_class).new data_config
|
|
23
23
|
end
|
|
@@ -50,7 +50,7 @@ module I18n::Tasks
|
|
|
50
50
|
end
|
|
51
51
|
|
|
52
52
|
def t_proc(locale = base_locale)
|
|
53
|
-
@t_proc
|
|
53
|
+
@t_proc ||= {}
|
|
54
54
|
@t_proc[locale] ||= proc { |key| t(key, locale) }
|
|
55
55
|
end
|
|
56
56
|
|
data/lib/i18n/tasks/html_keys.rb
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
module I18n::Tasks
|
|
4
4
|
module HtmlKeys
|
|
5
|
-
HTML_KEY_PATTERN = /[.\-_]html\z
|
|
6
|
-
MAYBE_PLURAL_HTML_KEY_PATTERN = /[.\-_]html\.[^.]+\z
|
|
5
|
+
HTML_KEY_PATTERN = /[.\-_]html\z/
|
|
6
|
+
MAYBE_PLURAL_HTML_KEY_PATTERN = /[.\-_]html\.[^.]+\z/
|
|
7
7
|
|
|
8
8
|
def html_key?(full_key, locale)
|
|
9
9
|
!!(full_key =~ HTML_KEY_PATTERN ||
|
|
@@ -12,19 +12,19 @@ module I18n::Tasks::IgnoreKeys
|
|
|
12
12
|
# @param locale [String] only when type is :eq_base
|
|
13
13
|
# @return [Regexp] a regexp that matches all the keys ignored for the type (and locale)
|
|
14
14
|
def ignore_pattern(type, locale = nil)
|
|
15
|
-
@ignore_patterns
|
|
16
|
-
@ignore_patterns[type]
|
|
15
|
+
@ignore_patterns ||= HashWithIndifferentAccess.new
|
|
16
|
+
@ignore_patterns[type] ||= {}
|
|
17
17
|
@ignore_patterns[type][locale] ||= begin
|
|
18
18
|
global = ignore_config.presence || []
|
|
19
19
|
type_ignore = ignore_config(type).presence || []
|
|
20
20
|
patterns = case type_ignore
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
21
|
+
when Array
|
|
22
|
+
global + type_ignore
|
|
23
|
+
when Hash
|
|
24
|
+
# ignore per locale
|
|
25
|
+
global + (type_ignore["all"] || []) +
|
|
26
|
+
type_ignore.select { |k, _v| k.to_s =~ /\b#{locale}\b/ }.values.flatten(1).compact
|
|
27
|
+
end
|
|
28
28
|
compile_patterns_re patterns
|
|
29
29
|
end
|
|
30
30
|
end
|
|
@@ -5,7 +5,7 @@ module I18n::Tasks
|
|
|
5
5
|
class << self
|
|
6
6
|
attr_accessor :variable_regex
|
|
7
7
|
end
|
|
8
|
-
@variable_regex = /(?<!%)%{[^}]+}
|
|
8
|
+
@variable_regex = /(?<!%)%{[^}]+}/
|
|
9
9
|
|
|
10
10
|
def inconsistent_interpolations(locales: nil, base_locale: nil) # rubocop:disable Metrics/AbcSize
|
|
11
11
|
locales ||= self.locales
|
|
@@ -30,5 +30,25 @@ module I18n::Tasks
|
|
|
30
30
|
result.each { |root| root.data[:type] = :inconsistent_interpolations }
|
|
31
31
|
result
|
|
32
32
|
end
|
|
33
|
+
|
|
34
|
+
def reserved_interpolations(locales: nil)
|
|
35
|
+
locales ||= self.locales
|
|
36
|
+
result = empty_forest
|
|
37
|
+
|
|
38
|
+
locales.each do |current_locale|
|
|
39
|
+
data[current_locale].key_values.each do |key, value|
|
|
40
|
+
next unless value.is_a?(String)
|
|
41
|
+
|
|
42
|
+
reserved_variables = value.scan(::I18n.reserved_keys_pattern).flatten
|
|
43
|
+
next if reserved_variables.empty?
|
|
44
|
+
|
|
45
|
+
result.merge!(data[current_locale].first.children[key].walk_to_root.reduce(nil) do |c, p|
|
|
46
|
+
[p.derive(children: c, value: reserved_variables)]
|
|
47
|
+
end)
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
result.each { |root| root.data[:type] = :inconsistent_interpolations }
|
|
51
|
+
result
|
|
52
|
+
end
|
|
33
53
|
end
|
|
34
54
|
end
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require
|
|
3
|
+
require "strscan"
|
|
4
4
|
|
|
5
5
|
module I18n::Tasks::KeyPatternMatching
|
|
6
6
|
extend self # rubocop:disable Style/ModuleFunction
|
|
7
7
|
|
|
8
|
-
MATCH_NOTHING = /\z\A
|
|
8
|
+
MATCH_NOTHING = /\z\A/
|
|
9
9
|
|
|
10
10
|
# one regex to match any
|
|
11
11
|
def compile_patterns_re(key_patterns)
|
|
@@ -13,7 +13,7 @@ module I18n::Tasks::KeyPatternMatching
|
|
|
13
13
|
# match nothing
|
|
14
14
|
MATCH_NOTHING
|
|
15
15
|
else
|
|
16
|
-
/(?:#{key_patterns.map { |p| compile_key_pattern p } *
|
|
16
|
+
/(?:#{key_patterns.map { |p| compile_key_pattern p } * "|"})/m
|
|
17
17
|
end
|
|
18
18
|
end
|
|
19
19
|
|
|
@@ -31,10 +31,10 @@ module I18n::Tasks::KeyPatternMatching
|
|
|
31
31
|
|
|
32
32
|
def key_pattern_re_body(key_pattern)
|
|
33
33
|
key_pattern
|
|
34
|
-
.gsub(
|
|
35
|
-
.gsub(
|
|
36
|
-
.gsub(
|
|
37
|
-
.gsub(
|
|
38
|
-
.gsub(/\{(.*?)}/) { "(#{Regexp.last_match(1).strip.gsub(/\s*,\s*/,
|
|
34
|
+
.gsub(".", '\.')
|
|
35
|
+
.gsub("*:", "[^.]+?")
|
|
36
|
+
.gsub("*", ".*")
|
|
37
|
+
.gsub(":", '(?<=^|\.)[^.]+?(?=\.|$)')
|
|
38
|
+
.gsub(/\{(.*?)}/) { "(#{Regexp.last_match(1).strip.gsub(/\s*,\s*/, "|")})" }
|
|
39
39
|
end
|
|
40
40
|
end
|
data/lib/i18n/tasks/logging.rb
CHANGED
|
@@ -25,7 +25,8 @@ module I18n::Tasks::Logging
|
|
|
25
25
|
def log_stderr(*args)
|
|
26
26
|
# We don't want output from different threads to get intermixed.
|
|
27
27
|
MUTEX.synchronize do
|
|
28
|
-
$stderr
|
|
28
|
+
# Use $stderr directly to avoid issues with JRuby and thread safety
|
|
29
|
+
$stderr.puts(*args) # rubocop:disable Style/StderrPuts
|
|
29
30
|
end
|
|
30
31
|
end
|
|
31
32
|
|