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
data/lib/i18n/tasks/cli.rb
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require
|
|
4
|
-
require
|
|
5
|
-
require
|
|
3
|
+
require "i18n/tasks"
|
|
4
|
+
require "i18n/tasks/commands"
|
|
5
|
+
require "optparse"
|
|
6
6
|
|
|
7
7
|
class I18n::Tasks::CLI
|
|
8
8
|
include ::I18n::Tasks::Logging
|
|
@@ -11,9 +11,9 @@ class I18n::Tasks::CLI
|
|
|
11
11
|
new.start(argv)
|
|
12
12
|
end
|
|
13
13
|
|
|
14
|
-
def initialize; end
|
|
15
|
-
|
|
16
14
|
def start(argv)
|
|
15
|
+
load_dotenv
|
|
16
|
+
|
|
17
17
|
auto_output_coloring do
|
|
18
18
|
exit 1 if run(argv) == :exit1
|
|
19
19
|
rescue OptionParser::ParseError => e
|
|
@@ -35,7 +35,7 @@ class I18n::Tasks::CLI
|
|
|
35
35
|
|
|
36
36
|
def run(argv)
|
|
37
37
|
argv.each_with_index do |arg, i|
|
|
38
|
-
next unless [
|
|
38
|
+
next unless ["--config", "-c"].include?(arg)
|
|
39
39
|
|
|
40
40
|
_, config_file = argv.slice!(i, 2)
|
|
41
41
|
if File.exist?(config_file)
|
|
@@ -59,7 +59,7 @@ class I18n::Tasks::CLI
|
|
|
59
59
|
def commands
|
|
60
60
|
# load base task to initialize plugins
|
|
61
61
|
base_task
|
|
62
|
-
@commands ||= ::I18n::Tasks::Commands.cmds.transform_keys { |k| k.to_s.tr(
|
|
62
|
+
@commands ||= ::I18n::Tasks::Commands.cmds.transform_keys { |k| k.to_s.tr("_", "-") }
|
|
63
63
|
end
|
|
64
64
|
|
|
65
65
|
private
|
|
@@ -72,7 +72,7 @@ class I18n::Tasks::CLI
|
|
|
72
72
|
command = parse_command! argv
|
|
73
73
|
options = optparse! command, argv
|
|
74
74
|
parse_options! options, command, argv
|
|
75
|
-
[command.tr(
|
|
75
|
+
[command.tr("-", "_"), options.update(arguments: argv)]
|
|
76
76
|
end
|
|
77
77
|
|
|
78
78
|
def optparse!(command, argv)
|
|
@@ -85,8 +85,8 @@ class I18n::Tasks::CLI
|
|
|
85
85
|
|
|
86
86
|
def optparse_command!(command, argv)
|
|
87
87
|
cmd_conf = commands[command]
|
|
88
|
-
flags
|
|
89
|
-
options
|
|
88
|
+
flags = cmd_conf[:args].dup
|
|
89
|
+
options = {}
|
|
90
90
|
OptionParser.new("Usage: #{program_name} #{command} [options] #{cmd_conf[:pos]}".strip) do |op|
|
|
91
91
|
flags.each do |flag|
|
|
92
92
|
op.on(*optparse_args(flag)) { |v| options[option_name(flag)] = v }
|
|
@@ -98,9 +98,9 @@ class I18n::Tasks::CLI
|
|
|
98
98
|
end
|
|
99
99
|
|
|
100
100
|
def optparse_no_command!(argv)
|
|
101
|
-
argv <<
|
|
101
|
+
argv << "--help" if argv.empty?
|
|
102
102
|
OptionParser.new("Usage: #{program_name} [command] [options]") do |op|
|
|
103
|
-
op.on(
|
|
103
|
+
op.on("-v", "--version", "Print the version") do
|
|
104
104
|
puts I18n::Tasks::VERSION
|
|
105
105
|
exit
|
|
106
106
|
end
|
|
@@ -111,12 +111,12 @@ class I18n::Tasks::CLI
|
|
|
111
111
|
|
|
112
112
|
def allow_help_arg_first!(argv)
|
|
113
113
|
# allow `i18n-tasks --help command` in addition to `i18n-tasks command --help`
|
|
114
|
-
argv[0], argv[1] = argv[1], argv[0] if %w[-h --help].include?(argv[0]) && argv[1] && !argv[1].start_with?(
|
|
114
|
+
argv[0], argv[1] = argv[1], argv[0] if %w[-h --help].include?(argv[0]) && argv[1] && !argv[1].start_with?("-")
|
|
115
115
|
end
|
|
116
116
|
|
|
117
117
|
def parse_command!(argv)
|
|
118
118
|
allow_help_arg_first! argv
|
|
119
|
-
if argv[0] && !argv[0].start_with?(
|
|
119
|
+
if argv[0] && !argv[0].start_with?("-")
|
|
120
120
|
if commands.keys.include?(argv[0])
|
|
121
121
|
argv.shift
|
|
122
122
|
else
|
|
@@ -126,28 +126,28 @@ class I18n::Tasks::CLI
|
|
|
126
126
|
end
|
|
127
127
|
|
|
128
128
|
def verbose_option(op)
|
|
129
|
-
op.on(
|
|
129
|
+
op.on("--verbose", "Verbose output") do
|
|
130
130
|
::I18n::Tasks.verbose = true
|
|
131
131
|
end
|
|
132
132
|
end
|
|
133
133
|
|
|
134
134
|
def help_option(op)
|
|
135
|
-
op.on(
|
|
136
|
-
|
|
135
|
+
op.on("-h", "--help", "Show this message") do
|
|
136
|
+
warn op
|
|
137
137
|
exit
|
|
138
138
|
end
|
|
139
139
|
end
|
|
140
140
|
|
|
141
141
|
# @param [OptionParser] op
|
|
142
142
|
def commands_summary(op)
|
|
143
|
-
op.separator
|
|
144
|
-
op.separator
|
|
145
|
-
op.separator
|
|
143
|
+
op.separator ""
|
|
144
|
+
op.separator "Available commands:"
|
|
145
|
+
op.separator ""
|
|
146
146
|
commands.each do |cmd, cmd_conf|
|
|
147
|
-
op.separator " #{cmd.ljust(op.summary_width + 1,
|
|
147
|
+
op.separator " #{cmd.ljust(op.summary_width + 1, " ")}#{try_call cmd_conf[:desc]}"
|
|
148
148
|
end
|
|
149
|
-
op.separator
|
|
150
|
-
op.separator
|
|
149
|
+
op.separator ""
|
|
150
|
+
op.separator "See `i18n-tasks <command> --help` for more information on a specific command."
|
|
151
151
|
end
|
|
152
152
|
|
|
153
153
|
def optparse_args(flag)
|
|
@@ -155,14 +155,14 @@ class I18n::Tasks::CLI
|
|
|
155
155
|
args.map! { |v| try_call v }
|
|
156
156
|
conf = args.extract_options!
|
|
157
157
|
if conf.key?(:default)
|
|
158
|
-
args[-1] = "#{args[-1]}. #{I18n.t(
|
|
158
|
+
args[-1] = "#{args[-1]}. #{I18n.t("i18n_tasks.cmd.args.default_text", value: conf[:default])}"
|
|
159
159
|
end
|
|
160
160
|
args
|
|
161
161
|
end
|
|
162
162
|
|
|
163
163
|
def parse_options!(options, command, argv)
|
|
164
164
|
commands[command][:args].each do |flag|
|
|
165
|
-
name
|
|
165
|
+
name = option_name flag
|
|
166
166
|
options[name] = parse_option flag, options[name], argv, context
|
|
167
167
|
end
|
|
168
168
|
end
|
|
@@ -170,7 +170,7 @@ class I18n::Tasks::CLI
|
|
|
170
170
|
def parse_option(flag, val, argv, context)
|
|
171
171
|
conf = flag.last.is_a?(Hash) ? flag.last : {}
|
|
172
172
|
if conf[:consume_positional]
|
|
173
|
-
val = Array(val) + Array(flag.include?(Array) ? argv.flat_map { |x| x.split(
|
|
173
|
+
val = Array(val) + Array(flag.include?(Array) ? argv.flat_map { |x| x.split(",") } : argv)
|
|
174
174
|
end
|
|
175
175
|
val = conf[:default] if val.nil? && conf.key?(:default)
|
|
176
176
|
val = conf[:parser].call(val, context) if conf.key?(:parser)
|
|
@@ -179,8 +179,8 @@ class I18n::Tasks::CLI
|
|
|
179
179
|
|
|
180
180
|
def option_name(flag)
|
|
181
181
|
flag.detect do |f|
|
|
182
|
-
f.start_with?(
|
|
183
|
-
end.sub(/\A--(\[no-\])?/,
|
|
182
|
+
f.start_with?("--")
|
|
183
|
+
end.sub(/\A--(\[no-\])?/, "").sub(/[^\-\w].*\z/, "").to_sym
|
|
184
184
|
end
|
|
185
185
|
|
|
186
186
|
def try_call(v)
|
|
@@ -205,11 +205,18 @@ class I18n::Tasks::CLI
|
|
|
205
205
|
end
|
|
206
206
|
end
|
|
207
207
|
|
|
208
|
-
def auto_output_coloring(coloring = ENV[
|
|
209
|
-
coloring_was
|
|
208
|
+
def auto_output_coloring(coloring = ENV["I18N_TASKS_COLOR"] || $stdout.isatty)
|
|
209
|
+
coloring_was = Rainbow.enabled
|
|
210
210
|
Rainbow.enabled = coloring
|
|
211
211
|
yield
|
|
212
212
|
ensure
|
|
213
213
|
Rainbow.enabled = coloring_was
|
|
214
214
|
end
|
|
215
|
+
|
|
216
|
+
def load_dotenv
|
|
217
|
+
require "dotenv"
|
|
218
|
+
Dotenv.load
|
|
219
|
+
rescue LoadError
|
|
220
|
+
# dotenv not available, continue without it
|
|
221
|
+
end
|
|
215
222
|
end
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require
|
|
4
|
-
require
|
|
5
|
-
require
|
|
6
|
-
require
|
|
3
|
+
require "i18n/tasks/command/dsl"
|
|
4
|
+
require "i18n/tasks/command/options/common"
|
|
5
|
+
require "i18n/tasks/command/options/locales"
|
|
6
|
+
require "i18n/tasks/command/options/data"
|
|
7
7
|
|
|
8
8
|
module I18n::Tasks
|
|
9
9
|
module Command
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require
|
|
4
|
-
require
|
|
3
|
+
require "i18n/tasks/cli"
|
|
4
|
+
require "i18n/tasks/reports/terminal"
|
|
5
5
|
|
|
6
6
|
module I18n::Tasks
|
|
7
7
|
module Command
|
|
@@ -16,10 +16,10 @@ module I18n::Tasks
|
|
|
16
16
|
end
|
|
17
17
|
|
|
18
18
|
def run(name, opts = {})
|
|
19
|
-
log_stderr "#{Rainbow(
|
|
19
|
+
log_stderr "#{Rainbow("#StandWith").bg(:blue)}#{Rainbow("Ukraine").bg(:yellow)}"
|
|
20
20
|
name = name.to_sym
|
|
21
|
-
public_name = name.to_s.tr
|
|
22
|
-
log_verbose "task: #{public_name}(#{opts.map { |k, v| "#{k}: #{v.inspect}" } *
|
|
21
|
+
public_name = name.to_s.tr "_", "-"
|
|
22
|
+
log_verbose "task: #{public_name}(#{opts.map { |k, v| "#{k}: #{v.inspect}" } * ", "})"
|
|
23
23
|
if opts.empty? || method(name).arity.zero?
|
|
24
24
|
send name
|
|
25
25
|
else
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module I18n::Tasks
|
|
4
|
+
module Command
|
|
5
|
+
module Commands
|
|
6
|
+
module CheckPrism
|
|
7
|
+
include Command::Collection
|
|
8
|
+
|
|
9
|
+
arg :prism_mode,
|
|
10
|
+
"--prism_mode MODE",
|
|
11
|
+
"Prism parser mode: 'rails' or 'ruby'. Defaults to 'rails' if Rails is available in the project, otherwise 'ruby'."
|
|
12
|
+
|
|
13
|
+
cmd :check_prism,
|
|
14
|
+
desc: t("i18n_tasks.cmd.desc.check_prism"),
|
|
15
|
+
args: %i[prism_mode]
|
|
16
|
+
|
|
17
|
+
# Run both the default (Parser-based) and the Prism-enabled scanning
|
|
18
|
+
# and produce a plain-text report in tmp/i18n_tasks_check_prism.md suitable
|
|
19
|
+
# for pasting into an issue.
|
|
20
|
+
def check_prism(opt = {})
|
|
21
|
+
now = Time.now
|
|
22
|
+
report_path = File.join(Dir.pwd, "tmp", "i18n_tasks_check_prism.md")
|
|
23
|
+
FileUtils.mkdir_p(File.dirname(report_path))
|
|
24
|
+
|
|
25
|
+
# keep original search config and clear caches helper
|
|
26
|
+
orig_search = (i18n.config[:search] || {}).dup
|
|
27
|
+
|
|
28
|
+
results = {}
|
|
29
|
+
|
|
30
|
+
# determine prism mode: use provided opt or default to rails when Rails present
|
|
31
|
+
chosen_prism_mode = (opt[:prism_mode].presence || (rails_available? ? "rails" : "ruby")).to_s
|
|
32
|
+
unless %w[rails ruby].include?(chosen_prism_mode)
|
|
33
|
+
fail CommandError, "--prism-mode must be 'rails' or 'ruby'"
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
{default: nil, prism: chosen_prism_mode}.each do |label, prism_mode|
|
|
37
|
+
i18n.config[:search] = orig_search.merge(prism: prism_mode)
|
|
38
|
+
# clear caches used by UsedKeys
|
|
39
|
+
i18n.instance_variable_set(:@scanner, nil)
|
|
40
|
+
i18n.instance_variable_set(:@search_config, nil)
|
|
41
|
+
i18n.instance_variable_set(:@keys_used_in_source_tree, nil)
|
|
42
|
+
|
|
43
|
+
tree = i18n.used_in_source_tree
|
|
44
|
+
keys = tree.nodes.select { |n| n.data[:occurrences].present? }
|
|
45
|
+
results[label] = keys.each_with_object({}) do |node, h|
|
|
46
|
+
full_key = node.full_key(root: false)
|
|
47
|
+
h[full_key] = node.data[:occurrences]
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# restore original config and caches
|
|
52
|
+
i18n.config[:search] = orig_search
|
|
53
|
+
i18n.instance_variable_set(:@scanner, nil)
|
|
54
|
+
i18n.instance_variable_set(:@search_config, nil)
|
|
55
|
+
i18n.instance_variable_set(:@keys_used_in_source_tree, nil)
|
|
56
|
+
|
|
57
|
+
default_keys = results[:default].keys
|
|
58
|
+
prism_keys = results[:prism].keys
|
|
59
|
+
|
|
60
|
+
only_default = (default_keys - prism_keys).sort
|
|
61
|
+
only_prism = (prism_keys - default_keys).sort
|
|
62
|
+
both = (default_keys & prism_keys).sort
|
|
63
|
+
|
|
64
|
+
File.open(report_path, "w") do |f|
|
|
65
|
+
f.puts "# i18n-tasks check_prism report"
|
|
66
|
+
f.puts "Generated at: #{now.utc}"
|
|
67
|
+
f.puts "Prism mode: #{chosen_prism_mode}"
|
|
68
|
+
f.puts "Gem version: #{I18n::Tasks::VERSION}"
|
|
69
|
+
f.puts ""
|
|
70
|
+
f.puts "Summary"
|
|
71
|
+
f.puts "- total keys (default parser): #{default_keys.size}"
|
|
72
|
+
f.puts "- total keys (prism): #{prism_keys.size}"
|
|
73
|
+
f.puts "- keys in both: #{both.size}"
|
|
74
|
+
f.puts "- keys only in default parser: #{only_default.size}"
|
|
75
|
+
f.puts "- keys only in prism: #{only_prism.size}"
|
|
76
|
+
f.puts ""
|
|
77
|
+
|
|
78
|
+
unless only_default.empty?
|
|
79
|
+
f.puts "## Keys found by the default parser but NOT by Prism (#{only_default.size})"
|
|
80
|
+
only_default.each do |k|
|
|
81
|
+
f.puts "\n### #{k}"
|
|
82
|
+
results[:default][k].first(5).each do |occ|
|
|
83
|
+
src = (occ.raw_key || k).to_s
|
|
84
|
+
line = (occ.line || "").strip
|
|
85
|
+
highlighted = line.gsub(src) { |m| "`#{m}`" }
|
|
86
|
+
f.puts "- #{occ.path}:#{occ.line_num} `#{src}` — #{highlighted}"
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
unless only_prism.empty?
|
|
92
|
+
f.puts "## Keys found by Prism but NOT by the default parser (#{only_prism.size})"
|
|
93
|
+
only_prism.each do |k|
|
|
94
|
+
f.puts "\n### #{k}"
|
|
95
|
+
results[:prism][k].each do |occ|
|
|
96
|
+
src = (occ.raw_key || k).to_s
|
|
97
|
+
line = (occ.line || "").strip
|
|
98
|
+
highlighted = line.gsub(src) { |m| "`#{m}`" }
|
|
99
|
+
f.puts "- #{occ.path}:#{occ.line_num} `#{src}` — #{highlighted}"
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
f.puts "\n## Notes"
|
|
105
|
+
f.puts "- This report compares keys discovered by the project default parser and by Prism (rails mode)."
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
log_stderr "Wrote check_prism report: #{report_path}"
|
|
109
|
+
puts File.read(report_path)
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
private
|
|
113
|
+
|
|
114
|
+
def rails_available?
|
|
115
|
+
return true if defined?(Rails)
|
|
116
|
+
return true if Gem.loaded_specs.key?("rails")
|
|
117
|
+
lock = File.join(Dir.pwd, "Gemfile.lock")
|
|
118
|
+
return false unless File.exist?(lock)
|
|
119
|
+
File.read(lock).lines.any? { |l| l.strip.start_with?("rails ") || l.strip =~ /^rails \(/ }
|
|
120
|
+
rescue
|
|
121
|
+
false
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
end
|
|
@@ -7,24 +7,24 @@ module I18n::Tasks
|
|
|
7
7
|
include Command::Collection
|
|
8
8
|
|
|
9
9
|
arg :pattern_router,
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
"-p",
|
|
11
|
+
"--pattern_router",
|
|
12
|
+
t("i18n_tasks.cmd.args.desc.pattern_router")
|
|
13
13
|
|
|
14
14
|
cmd :normalize,
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
15
|
+
pos: "[locale ...]",
|
|
16
|
+
desc: t("i18n_tasks.cmd.desc.normalize"),
|
|
17
|
+
args: %i[locales pattern_router]
|
|
18
18
|
|
|
19
19
|
def normalize(opt = {})
|
|
20
20
|
i18n.normalize_store! locales: opt[:locales],
|
|
21
|
-
|
|
21
|
+
force_pattern_router: opt[:pattern_router]
|
|
22
22
|
end
|
|
23
23
|
|
|
24
24
|
cmd :check_normalized,
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
25
|
+
pos: "[locale ...]",
|
|
26
|
+
desc: t("i18n_tasks.cmd.desc.check_normalized"),
|
|
27
|
+
args: %i[locales]
|
|
28
28
|
|
|
29
29
|
def check_normalized(opt)
|
|
30
30
|
non_normalized = i18n.non_normalized_paths locales: opt[:locales]
|
|
@@ -33,10 +33,10 @@ module I18n::Tasks
|
|
|
33
33
|
end
|
|
34
34
|
|
|
35
35
|
cmd :mv,
|
|
36
|
-
|
|
37
|
-
|
|
36
|
+
pos: "FROM_KEY_PATTERN TO_KEY_PATTERN",
|
|
37
|
+
desc: t("i18n_tasks.cmd.desc.mv")
|
|
38
38
|
def mv(opt = {})
|
|
39
|
-
fail CommandError,
|
|
39
|
+
fail CommandError, "requires FROM_KEY_PATTERN and TO_KEY_PATTERN" if opt[:arguments].size < 2
|
|
40
40
|
|
|
41
41
|
from_pattern = opt[:arguments].shift
|
|
42
42
|
to_pattern = opt[:arguments].shift
|
|
@@ -47,10 +47,10 @@ module I18n::Tasks
|
|
|
47
47
|
end
|
|
48
48
|
|
|
49
49
|
cmd :cp,
|
|
50
|
-
|
|
51
|
-
|
|
50
|
+
pos: "FROM_KEY_PATTERN TO_KEY_PATTERN",
|
|
51
|
+
desc: t("i18n_tasks.cmd.desc.cp")
|
|
52
52
|
def cp(opt = {})
|
|
53
|
-
fail CommandError,
|
|
53
|
+
fail CommandError, "requires FROM_KEY_PATTERN and TO_KEY_PATTERN" if opt[:arguments].size < 2
|
|
54
54
|
|
|
55
55
|
from_pattern = opt[:arguments].shift
|
|
56
56
|
to_pattern = opt[:arguments].shift
|
|
@@ -61,32 +61,32 @@ module I18n::Tasks
|
|
|
61
61
|
end
|
|
62
62
|
|
|
63
63
|
cmd :rm,
|
|
64
|
-
|
|
65
|
-
|
|
64
|
+
pos: "KEY_PATTERN [KEY_PATTERN...]",
|
|
65
|
+
desc: t("i18n_tasks.cmd.desc.rm")
|
|
66
66
|
def rm(opt = {})
|
|
67
|
-
fail CommandError,
|
|
67
|
+
fail CommandError, "requires KEY_PATTERN" if opt[:arguments].empty?
|
|
68
68
|
|
|
69
69
|
forest = i18n.data_forest
|
|
70
70
|
results = opt[:arguments].each_with_object({}) do |key_pattern, h|
|
|
71
|
-
h.merge! forest.mv_key!(compile_key_pattern(key_pattern),
|
|
71
|
+
h.merge! forest.mv_key!(compile_key_pattern(key_pattern), "", root: false)
|
|
72
72
|
end
|
|
73
73
|
i18n.data.write forest
|
|
74
74
|
terminal_report.mv_results results
|
|
75
75
|
end
|
|
76
76
|
|
|
77
77
|
cmd :data,
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
78
|
+
pos: "[locale ...]",
|
|
79
|
+
desc: t("i18n_tasks.cmd.desc.data"),
|
|
80
|
+
args: %i[locales out_format]
|
|
81
81
|
|
|
82
82
|
def data(opt = {})
|
|
83
83
|
print_forest i18n.data_forest(opt[:locales]), opt
|
|
84
84
|
end
|
|
85
85
|
|
|
86
86
|
cmd :data_merge,
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
87
|
+
pos: "[tree ...]",
|
|
88
|
+
desc: t("i18n_tasks.cmd.desc.data_merge"),
|
|
89
|
+
args: %i[data_format nostdin]
|
|
90
90
|
|
|
91
91
|
def data_merge(opt = {})
|
|
92
92
|
forest = merge_forests_stdin_and_pos!(opt)
|
|
@@ -95,9 +95,9 @@ module I18n::Tasks
|
|
|
95
95
|
end
|
|
96
96
|
|
|
97
97
|
cmd :data_write,
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
98
|
+
pos: "[tree]",
|
|
99
|
+
desc: t("i18n_tasks.cmd.desc.data_write"),
|
|
100
|
+
args: %i[data_format nostdin]
|
|
101
101
|
|
|
102
102
|
def data_write(opt = {})
|
|
103
103
|
forest = forest_pos_or_stdin!(opt)
|
|
@@ -106,13 +106,13 @@ module I18n::Tasks
|
|
|
106
106
|
end
|
|
107
107
|
|
|
108
108
|
cmd :data_remove,
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
109
|
+
pos: "[tree]",
|
|
110
|
+
desc: t("i18n_tasks.cmd.desc.data_remove"),
|
|
111
|
+
args: %i[data_format nostdin]
|
|
112
112
|
|
|
113
113
|
def data_remove(opt = {})
|
|
114
114
|
removed = i18n.data.remove_by_key!(forest_pos_or_stdin!(opt))
|
|
115
|
-
log_stderr
|
|
115
|
+
log_stderr "Removed:"
|
|
116
116
|
print_forest removed, opt
|
|
117
117
|
end
|
|
118
118
|
end
|
|
@@ -7,9 +7,9 @@ module I18n::Tasks
|
|
|
7
7
|
include Command::Collection
|
|
8
8
|
|
|
9
9
|
cmd :eq_base,
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
pos: "[locale ...]",
|
|
11
|
+
desc: t("i18n_tasks.cmd.desc.eq_base"),
|
|
12
|
+
args: %i[locales out_format]
|
|
13
13
|
|
|
14
14
|
def eq_base(opt = {})
|
|
15
15
|
forest = i18n.eq_base_keys(opt)
|
|
@@ -7,20 +7,21 @@ module I18n::Tasks
|
|
|
7
7
|
include Command::Collection
|
|
8
8
|
|
|
9
9
|
cmd :health,
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
pos: "[locale ...]",
|
|
11
|
+
desc: t("i18n_tasks.cmd.desc.health"),
|
|
12
|
+
args: %i[locales out_format config]
|
|
13
13
|
|
|
14
14
|
def health(opt = {})
|
|
15
15
|
forest = i18n.data_forest(opt[:locales])
|
|
16
|
-
stats
|
|
17
|
-
fail CommandError, t(
|
|
16
|
+
stats = i18n.forest_stats(forest)
|
|
17
|
+
fail CommandError, t("i18n_tasks.health.no_keys_detected") if stats[:key_count].zero?
|
|
18
18
|
|
|
19
19
|
terminal_report.forest_stats forest, stats
|
|
20
20
|
[
|
|
21
21
|
missing(**opt),
|
|
22
22
|
unused(**opt),
|
|
23
23
|
check_consistent_interpolations(**opt),
|
|
24
|
+
check_reserved_interpolations(**opt),
|
|
24
25
|
check_normalized(**opt)
|
|
25
26
|
].detect { |result| result == :exit1 }
|
|
26
27
|
end
|
|
@@ -7,15 +7,26 @@ module I18n::Tasks
|
|
|
7
7
|
include Command::Collection
|
|
8
8
|
|
|
9
9
|
cmd :check_consistent_interpolations,
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
pos: "[locale ...]",
|
|
11
|
+
desc: t("i18n_tasks.cmd.desc.check_consistent_interpolations"),
|
|
12
|
+
args: %i[locales out_format]
|
|
13
13
|
|
|
14
14
|
def check_consistent_interpolations(opt = {})
|
|
15
15
|
forest = i18n.inconsistent_interpolations(**opt.slice(:locales, :base_locale))
|
|
16
16
|
print_forest forest, opt, :inconsistent_interpolations
|
|
17
17
|
:exit1 unless forest.empty?
|
|
18
18
|
end
|
|
19
|
+
|
|
20
|
+
cmd :check_reserved_interpolations,
|
|
21
|
+
pos: "[locale]",
|
|
22
|
+
desc: t("i18n_tasks.cmd.desc.check_reserved_interpolations"),
|
|
23
|
+
args: %i[locales out_format]
|
|
24
|
+
|
|
25
|
+
def check_reserved_interpolations(opt = {})
|
|
26
|
+
forest = i18n.reserved_interpolations(**opt.slice(:locale))
|
|
27
|
+
print_forest forest, opt, :reserved_interpolations
|
|
28
|
+
:exit1 unless forest.empty?
|
|
29
|
+
end
|
|
19
30
|
end
|
|
20
31
|
end
|
|
21
32
|
end
|
|
@@ -7,28 +7,28 @@ module I18n::Tasks
|
|
|
7
7
|
include Command::Collection
|
|
8
8
|
|
|
9
9
|
cmd :config,
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
pos: "[section ...]",
|
|
11
|
+
desc: t("i18n_tasks.cmd.desc.config")
|
|
12
12
|
|
|
13
13
|
def config(opts = {})
|
|
14
14
|
cfg = i18n.config_for_inspect
|
|
15
15
|
cfg = cfg.slice(*opts[:arguments]) if opts[:arguments].present?
|
|
16
16
|
cfg = cfg.to_yaml
|
|
17
|
-
cfg.sub!(/\A---\n/,
|
|
17
|
+
cfg.sub!(/\A---\n/, "")
|
|
18
18
|
cfg.gsub!(/^([^\s-].+?:)/, Rainbow('\1').cyan.bright)
|
|
19
19
|
puts cfg
|
|
20
20
|
end
|
|
21
21
|
|
|
22
|
-
cmd :gem_path, desc: t(
|
|
22
|
+
cmd :gem_path, desc: t("i18n_tasks.cmd.desc.gem_path")
|
|
23
23
|
|
|
24
24
|
def gem_path
|
|
25
25
|
puts I18n::Tasks.gem_path
|
|
26
26
|
end
|
|
27
27
|
|
|
28
|
-
cmd :irb, desc: t(
|
|
28
|
+
cmd :irb, desc: t("i18n_tasks.cmd.desc.irb")
|
|
29
29
|
|
|
30
30
|
def irb
|
|
31
|
-
require
|
|
31
|
+
require "i18n/tasks/console_context"
|
|
32
32
|
::I18n::Tasks::ConsoleContext.start
|
|
33
33
|
end
|
|
34
34
|
end
|