i18n-tasks 1.0.15 → 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 +85 -13
- data/Rakefile +4 -4
- data/bin/i18n-tasks +3 -3
- data/config/locales/en.yml +6 -0
- data/config/locales/ru.yml +7 -0
- data/i18n-tasks.gemspec +28 -41
- 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 +25 -25
- 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 +5 -5
- 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 +32 -32
- 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 +22 -21
- 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 +1 -1
- 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 +8 -8
- 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 +8 -1
- data/lib/i18n/tasks/scanners/prism_scanners/nodes.rb +101 -61
- data/lib/i18n/tasks/scanners/prism_scanners/visitor.rb +169 -105
- 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 +1 -1
- 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 +5 -5
- data/lib/i18n/tasks/translators/base_translator.rb +40 -14
- data/lib/i18n/tasks/translators/deepl_translator.rb +17 -14
- data/lib/i18n/tasks/translators/google_translator.rb +169 -25
- data/lib/i18n/tasks/translators/openai_translator.rb +34 -23
- data/lib/i18n/tasks/translators/watsonx_translator.rb +16 -16
- data/lib/i18n/tasks/translators/yandex_translator.rb +8 -8
- data/lib/i18n/tasks/unused_keys.rb +1 -1
- data/lib/i18n/tasks/used_keys.rb +32 -33
- data/lib/i18n/tasks/version.rb +1 -1
- data/lib/i18n/tasks.rb +17 -17
- data/templates/config/i18n-tasks.yml +12 -0
- data/templates/minitest/i18n_test.rb +3 -3
- data/templates/rspec/i18n_spec.rb +7 -7
- metadata +25 -185
- data/lib/i18n/tasks/scanners/prism_scanner.rb +0 -83
- data/lib/i18n/tasks/scanners/ruby_ast_scanner.rb +0 -145
|
@@ -7,18 +7,18 @@ module I18n::Tasks
|
|
|
7
7
|
include Command::Collection
|
|
8
8
|
|
|
9
9
|
arg :strict,
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
"--[no-]strict",
|
|
11
|
+
t("i18n_tasks.cmd.args.desc.strict")
|
|
12
12
|
|
|
13
13
|
arg :keep_order,
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
14
|
+
"-k",
|
|
15
|
+
"--keep-order",
|
|
16
|
+
t("i18n_tasks.cmd.args.desc.keep_order")
|
|
17
17
|
|
|
18
18
|
cmd :find,
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
19
|
+
pos: "[pattern]",
|
|
20
|
+
desc: t("i18n_tasks.cmd.desc.find"),
|
|
21
|
+
args: %i[out_format pattern strict]
|
|
22
22
|
|
|
23
23
|
def find(opt = {})
|
|
24
24
|
opt[:filter] ||= opt.delete(:pattern) || opt[:arguments].try(:first)
|
|
@@ -27,9 +27,9 @@ module I18n::Tasks
|
|
|
27
27
|
end
|
|
28
28
|
|
|
29
29
|
cmd :unused,
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
30
|
+
pos: "[locale ...]",
|
|
31
|
+
desc: t("i18n_tasks.cmd.desc.unused"),
|
|
32
|
+
args: %i[locales out_format strict]
|
|
33
33
|
|
|
34
34
|
def unused(opt = {})
|
|
35
35
|
forest = i18n.unused_keys(**opt.slice(:locales, :strict))
|
|
@@ -38,9 +38,9 @@ module I18n::Tasks
|
|
|
38
38
|
end
|
|
39
39
|
|
|
40
40
|
cmd :remove_unused,
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
41
|
+
pos: "[locale ...]",
|
|
42
|
+
desc: t("i18n_tasks.cmd.desc.remove_unused"),
|
|
43
|
+
args: %i[locales out_format strict keep_order confirm pattern]
|
|
44
44
|
|
|
45
45
|
def remove_unused(opt = {}) # rubocop:disable Metrics/AbcSize
|
|
46
46
|
unused_keys = i18n.unused_keys(**opt.slice(:locales, :strict))
|
|
@@ -53,26 +53,26 @@ module I18n::Tasks
|
|
|
53
53
|
if unused_keys.present?
|
|
54
54
|
terminal_report.unused_keys(unused_keys)
|
|
55
55
|
confirm_remove_unused!(unused_keys, opt)
|
|
56
|
-
i18n.data.config = i18n.data.config.merge(sort: false) if opt[:
|
|
56
|
+
i18n.data.config = i18n.data.config.merge(sort: false) if opt[:"keep-order"]
|
|
57
57
|
removed = i18n.data.remove_by_key!(unused_keys)
|
|
58
|
-
log_stderr t(
|
|
58
|
+
log_stderr t("i18n_tasks.remove_unused.removed", count: unused_keys.leaves.count)
|
|
59
59
|
print_forest removed, opt
|
|
60
60
|
else
|
|
61
|
-
log_stderr Rainbow(t(
|
|
61
|
+
log_stderr Rainbow(t("i18n_tasks.remove_unused.noop")).green.bright
|
|
62
62
|
end
|
|
63
63
|
end
|
|
64
64
|
|
|
65
65
|
private
|
|
66
66
|
|
|
67
67
|
def confirm_remove_unused!(unused_keys, opt)
|
|
68
|
-
return if ENV[
|
|
68
|
+
return if ENV["CONFIRM"] || opt[:confirm]
|
|
69
69
|
|
|
70
|
-
locales = Rainbow(unused_keys.flat_map { |root| root.key.split(
|
|
71
|
-
msg
|
|
72
|
-
Rainbow(t(
|
|
73
|
-
Rainbow(t(
|
|
74
|
-
Rainbow(
|
|
75
|
-
].join(
|
|
70
|
+
locales = Rainbow(unused_keys.flat_map { |root| root.key.split("+") }.sort.uniq * ", ").bright
|
|
71
|
+
msg = [
|
|
72
|
+
Rainbow(t("i18n_tasks.remove_unused.confirm", count: unused_keys.leaves.count, locales: locales)).red,
|
|
73
|
+
Rainbow(t("i18n_tasks.common.continue_q")).yellow,
|
|
74
|
+
Rainbow("(yes/no)").yellow
|
|
75
|
+
].join(" ")
|
|
76
76
|
exit 1 unless agree msg
|
|
77
77
|
end
|
|
78
78
|
end
|
|
@@ -6,13 +6,13 @@ module I18n::Tasks
|
|
|
6
6
|
module Enum
|
|
7
7
|
class Parser
|
|
8
8
|
DEFAULT_ERROR = proc do |invalid, valid|
|
|
9
|
-
I18n.t(
|
|
9
|
+
I18n.t("i18n_tasks.cmd.enum_opt.invalid", invalid: invalid, valid: valid * ", ")
|
|
10
10
|
end
|
|
11
11
|
|
|
12
12
|
def initialize(valid, error_message = DEFAULT_ERROR, allow_blank: false)
|
|
13
|
-
@valid
|
|
13
|
+
@valid = valid.map(&:to_s)
|
|
14
14
|
@error_message = error_message
|
|
15
|
-
@allow_blank
|
|
15
|
+
@allow_blank = allow_blank
|
|
16
16
|
end
|
|
17
17
|
|
|
18
18
|
def call(value, *)
|
|
@@ -28,11 +28,11 @@ module I18n::Tasks
|
|
|
28
28
|
|
|
29
29
|
class ListParser
|
|
30
30
|
DEFAULT_ERROR = proc do |invalid, valid|
|
|
31
|
-
I18n.t(
|
|
31
|
+
I18n.t("i18n_tasks.cmd.enum_list_opt.invalid", invalid: invalid * ", ", valid: valid * ", ")
|
|
32
32
|
end
|
|
33
33
|
|
|
34
34
|
def initialize(valid, error_message = DEFAULT_ERROR)
|
|
35
|
-
@valid
|
|
35
|
+
@valid = valid.map(&:to_s)
|
|
36
36
|
@error_message = error_message
|
|
37
37
|
end
|
|
38
38
|
|
|
@@ -5,11 +5,11 @@ module I18n::Tasks
|
|
|
5
5
|
module OptionParsers
|
|
6
6
|
module Locale
|
|
7
7
|
module Validator
|
|
8
|
-
VALID_LOCALE_RE = /\A\w[\w\-.]*\z/i
|
|
8
|
+
VALID_LOCALE_RE = /\A\w[\w\-.]*\z/i
|
|
9
9
|
|
|
10
10
|
def validate!(locale)
|
|
11
11
|
if VALID_LOCALE_RE !~ locale
|
|
12
|
-
fail CommandError, I18n.t(
|
|
12
|
+
fail CommandError, I18n.t("i18n_tasks.cmd.errors.invalid_locale", invalid: locale)
|
|
13
13
|
end
|
|
14
14
|
|
|
15
15
|
locale
|
|
@@ -23,7 +23,7 @@ module I18n::Tasks
|
|
|
23
23
|
|
|
24
24
|
# @param [#base_locale, #locales] context
|
|
25
25
|
def call(val, context)
|
|
26
|
-
if val.blank? || val ==
|
|
26
|
+
if val.blank? || val == "base"
|
|
27
27
|
context.base_locale
|
|
28
28
|
else
|
|
29
29
|
validate! val
|
|
@@ -41,7 +41,7 @@ module I18n::Tasks
|
|
|
41
41
|
if vals == %w[all] || vals.blank?
|
|
42
42
|
context.locales
|
|
43
43
|
else
|
|
44
|
-
move_base_locale_to_front!(vals.map { |v| v ==
|
|
44
|
+
move_base_locale_to_front!(vals.map { |v| (v == "base") ? context.base_locale : v }, context.base_locale)
|
|
45
45
|
end.tap do |locales|
|
|
46
46
|
locales.each { |locale| validate! locale }
|
|
47
47
|
end
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require
|
|
3
|
+
require "i18n/tasks/command/dsl"
|
|
4
4
|
|
|
5
5
|
module I18n::Tasks
|
|
6
6
|
module Command
|
|
@@ -9,29 +9,29 @@ module I18n::Tasks
|
|
|
9
9
|
include Command::DSL
|
|
10
10
|
|
|
11
11
|
arg :nostdin,
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
12
|
+
"-S",
|
|
13
|
+
"--nostdin",
|
|
14
|
+
t("i18n_tasks.cmd.args.desc.nostdin")
|
|
15
15
|
|
|
16
16
|
arg :confirm,
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
17
|
+
"-y",
|
|
18
|
+
"--confirm",
|
|
19
|
+
desc: t("i18n_tasks.cmd.args.desc.confirm")
|
|
20
20
|
|
|
21
21
|
arg :pattern,
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
22
|
+
"-p",
|
|
23
|
+
"--pattern PATTERN",
|
|
24
|
+
t("i18n_tasks.cmd.args.desc.key_pattern")
|
|
25
25
|
|
|
26
26
|
arg :value,
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
27
|
+
"-v",
|
|
28
|
+
"--value VALUE",
|
|
29
|
+
t("i18n_tasks.cmd.args.desc.value", dummy: "value") # Dummy value is workaround for https://github.com/ruby-i18n/i18n/issues/689
|
|
30
30
|
|
|
31
31
|
arg :config,
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
32
|
+
"-c",
|
|
33
|
+
"--config FILE",
|
|
34
|
+
t("i18n_tasks.cmd.args.desc.config")
|
|
35
35
|
|
|
36
36
|
def arg_or_pos!(key, opts)
|
|
37
37
|
opts[key] ||= opts[:arguments].try(:shift)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require
|
|
3
|
+
require "i18n/tasks/command/option_parsers/enum"
|
|
4
4
|
|
|
5
5
|
module I18n::Tasks
|
|
6
6
|
module Command
|
|
@@ -9,21 +9,21 @@ module I18n::Tasks
|
|
|
9
9
|
include Command::DSL
|
|
10
10
|
|
|
11
11
|
DATA_FORMATS = %w[yaml json keys].freeze
|
|
12
|
-
OUT_FORMATS
|
|
12
|
+
OUT_FORMATS = ["terminal-table", *DATA_FORMATS, "inspect", "key-values"].freeze
|
|
13
13
|
|
|
14
14
|
format_arg = proc do |type, values|
|
|
15
15
|
default = values.first
|
|
16
16
|
arg type,
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
17
|
+
"-f",
|
|
18
|
+
"--format FORMAT",
|
|
19
|
+
values,
|
|
20
|
+
{"yml" => "yaml"},
|
|
21
|
+
t("i18n_tasks.cmd.args.desc.#{type}", valid_text: values * ", ", default_text: default),
|
|
22
|
+
parser: OptionParsers::Enum::Parser.new(values,
|
|
23
|
+
proc do |value, valid|
|
|
24
|
+
I18n.t("i18n_tasks.cmd.errors.invalid_format",
|
|
25
|
+
invalid: value, valid: valid * ", ")
|
|
26
|
+
end)
|
|
27
27
|
end
|
|
28
28
|
|
|
29
29
|
# i18n-tasks-use t('i18n_tasks.cmd.args.desc.data_format')
|
|
@@ -63,9 +63,9 @@ module I18n::Tasks
|
|
|
63
63
|
|
|
64
64
|
# @return [I18n::Tasks::Data::Tree::Siblings]
|
|
65
65
|
def parse_forest(src, format)
|
|
66
|
-
fail CommandError, I18n.t(
|
|
66
|
+
fail CommandError, I18n.t("i18n_tasks.cmd.errors.pass_forest") unless src
|
|
67
67
|
|
|
68
|
-
if format ==
|
|
68
|
+
if format == "keys"
|
|
69
69
|
::I18n::Tasks::Data::Tree::Siblings.from_key_names parse_keys(src)
|
|
70
70
|
else
|
|
71
71
|
::I18n::Tasks::Data::Tree::Siblings.from_nested_hash i18n.data.adapter_parse(src, format)
|
|
@@ -79,13 +79,13 @@ module I18n::Tasks
|
|
|
79
79
|
def print_forest(forest, opts, version = :show_tree)
|
|
80
80
|
format = opts[:format].to_s
|
|
81
81
|
case format
|
|
82
|
-
when
|
|
82
|
+
when "terminal-table"
|
|
83
83
|
terminal_report.send(version, forest)
|
|
84
|
-
when
|
|
84
|
+
when "inspect"
|
|
85
85
|
puts forest.inspect
|
|
86
|
-
when
|
|
86
|
+
when "keys"
|
|
87
87
|
puts forest.key_names(root: true)
|
|
88
|
-
when
|
|
88
|
+
when "key-values"
|
|
89
89
|
puts(forest.key_values(root: true).map { |kv| kv.join("\t") })
|
|
90
90
|
when *DATA_FORMATS
|
|
91
91
|
puts i18n.data.adapter_dump forest.to_hash(true), format
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require
|
|
4
|
-
require
|
|
3
|
+
require "i18n/tasks/command/option_parsers/locale"
|
|
4
|
+
require "i18n/tasks/command/option_parsers/enum"
|
|
5
5
|
|
|
6
6
|
module I18n::Tasks
|
|
7
7
|
module Command
|
|
@@ -10,43 +10,43 @@ module I18n::Tasks
|
|
|
10
10
|
include Command::DSL
|
|
11
11
|
|
|
12
12
|
arg :locales,
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
13
|
+
"-l",
|
|
14
|
+
"--locales en,es,ru",
|
|
15
|
+
Array,
|
|
16
|
+
t("i18n_tasks.cmd.args.desc.locales_filter"),
|
|
17
|
+
parser: OptionParsers::Locale::ListParser,
|
|
18
|
+
default: "all",
|
|
19
|
+
consume_positional: true
|
|
20
20
|
|
|
21
21
|
arg :locale,
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
22
|
+
"-l",
|
|
23
|
+
"--locale en",
|
|
24
|
+
t("i18n_tasks.cmd.args.desc.locale"),
|
|
25
|
+
parser: OptionParsers::Locale::Parser,
|
|
26
|
+
default: "base"
|
|
27
27
|
|
|
28
28
|
arg :locale_to_translate_from,
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
29
|
+
"-f",
|
|
30
|
+
"--from en",
|
|
31
|
+
t("i18n_tasks.cmd.args.desc.locale_to_translate_from"),
|
|
32
|
+
parser: OptionParsers::Locale::Parser,
|
|
33
|
+
default: "base"
|
|
34
34
|
|
|
35
35
|
TRANSLATION_BACKENDS = %w[google deepl yandex openai watsonx].freeze
|
|
36
36
|
arg :translation_backend,
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
37
|
+
"-b",
|
|
38
|
+
"--backend BACKEND",
|
|
39
|
+
t("i18n_tasks.cmd.args.desc.translation_backend"),
|
|
40
|
+
parser:
|
|
41
|
+
OptionParsers::Enum::Parser.new(
|
|
42
|
+
TRANSLATION_BACKENDS,
|
|
43
|
+
proc do |value, valid|
|
|
44
|
+
if value.present?
|
|
45
|
+
I18n.t("i18n_tasks.cmd.errors.invalid_backend", invalid: value&.strip, valid: valid * ", ")
|
|
46
|
+
end
|
|
47
|
+
end,
|
|
48
|
+
allow_blank: true
|
|
49
|
+
)
|
|
50
50
|
end
|
|
51
51
|
end
|
|
52
52
|
end
|
data/lib/i18n/tasks/commands.rb
CHANGED
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require
|
|
4
|
-
require
|
|
5
|
-
require
|
|
6
|
-
require
|
|
7
|
-
require
|
|
8
|
-
require
|
|
9
|
-
require
|
|
10
|
-
require
|
|
11
|
-
require
|
|
12
|
-
require
|
|
13
|
-
require
|
|
3
|
+
require "i18n/tasks/command/dsl"
|
|
4
|
+
require "i18n/tasks/command/collection"
|
|
5
|
+
require "i18n/tasks/command/commands/health"
|
|
6
|
+
require "i18n/tasks/command/commands/missing"
|
|
7
|
+
require "i18n/tasks/command/commands/usages"
|
|
8
|
+
require "i18n/tasks/command/commands/interpolations"
|
|
9
|
+
require "i18n/tasks/command/commands/eq_base"
|
|
10
|
+
require "i18n/tasks/command/commands/data"
|
|
11
|
+
require "i18n/tasks/command/commands/tree"
|
|
12
|
+
require "i18n/tasks/command/commands/meta"
|
|
13
|
+
require "i18n/tasks/command/commands/check_prism"
|
|
14
|
+
require "i18n/tasks/command/commander"
|
|
14
15
|
|
|
15
16
|
module I18n::Tasks
|
|
16
17
|
class Commands < Command::Commander
|
|
@@ -23,7 +24,8 @@ module I18n::Tasks
|
|
|
23
24
|
include Command::Commands::Data
|
|
24
25
|
include Command::Commands::Tree
|
|
25
26
|
include Command::Commands::Meta
|
|
27
|
+
include Command::Commands::CheckPrism
|
|
26
28
|
|
|
27
|
-
require
|
|
29
|
+
require "highline/import"
|
|
28
30
|
end
|
|
29
31
|
end
|
|
@@ -35,7 +35,7 @@ module I18n::Tasks::Concurrent
|
|
|
35
35
|
# Below are the implementations for major ruby engines, based on concurrent-ruby.
|
|
36
36
|
# rubocop:disable Lint/DuplicateMethods,Naming/AccessorMethodName
|
|
37
37
|
case RUBY_ENGINE
|
|
38
|
-
when
|
|
38
|
+
when "rbx"
|
|
39
39
|
def get_result_volatile
|
|
40
40
|
Rubinius.memory_barrier
|
|
41
41
|
@result
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
module I18n::Tasks::Configuration # rubocop:disable Metrics/ModuleLength
|
|
4
4
|
DEFAULTS = {
|
|
5
|
-
base_locale:
|
|
6
|
-
internal_locale:
|
|
5
|
+
base_locale: "en",
|
|
6
|
+
internal_locale: "en",
|
|
7
7
|
search: ::I18n::Tasks::UsedKeys::SEARCH_DEFAULTS,
|
|
8
8
|
data: ::I18n::Tasks::Data::DATA_DEFAULTS,
|
|
9
9
|
translation_backend: :google
|
|
@@ -21,20 +21,20 @@ module I18n::Tasks::Configuration # rubocop:disable Metrics/ModuleLength
|
|
|
21
21
|
].freeze
|
|
22
22
|
|
|
23
23
|
def file_config
|
|
24
|
-
file
|
|
24
|
+
file = @config_override || CONFIG_FILES.detect { |f| File.exist?(f) }
|
|
25
25
|
# rubocop:disable Security/Eval
|
|
26
|
-
config = file && YAML.load(eval(Erubi::Engine.new(File.read(file, encoding:
|
|
26
|
+
config = file && YAML.load(eval(Erubi::Engine.new(File.read(file, encoding: "UTF-8")).src))
|
|
27
27
|
# rubocop:enable Security/Eval
|
|
28
28
|
if config.present?
|
|
29
29
|
config.with_indifferent_access.tap do |c|
|
|
30
30
|
if c[:relative_roots]
|
|
31
|
-
warn_deprecated
|
|
31
|
+
warn_deprecated "Please move relative_roots under search in config/i18n-tasks.yml."
|
|
32
32
|
c[:search][:relative_roots] = c.delete(:relative_roots)
|
|
33
33
|
end
|
|
34
34
|
|
|
35
35
|
if c.dig(:search, :exclude_method_name_paths)
|
|
36
36
|
warn_deprecated(
|
|
37
|
-
|
|
37
|
+
"Please rename exclude_method_name_paths to relative_exclude_method_name_paths in config/i18n-tasks.yml."
|
|
38
38
|
)
|
|
39
39
|
c[:search][:relative_exclude_method_name_paths] = c[:search].delete(:exclude_method_name_paths)
|
|
40
40
|
end
|
|
@@ -64,16 +64,17 @@ module I18n::Tasks::Configuration # rubocop:disable Metrics/ModuleLength
|
|
|
64
64
|
@config_sections[:translation] ||= begin
|
|
65
65
|
conf = (config[:translation] || {}).with_indifferent_access
|
|
66
66
|
conf[:backend] ||= DEFAULTS[:translation_backend]
|
|
67
|
-
conf[:google_translate_api_key] = ENV[
|
|
68
|
-
conf[:deepl_api_key] = ENV[
|
|
69
|
-
conf[:deepl_host] = ENV[
|
|
70
|
-
conf[:deepl_version] = ENV[
|
|
71
|
-
conf[:openai_api_key] = ENV[
|
|
72
|
-
conf[:openai_model] = ENV[
|
|
73
|
-
conf[:
|
|
74
|
-
conf[:
|
|
75
|
-
conf[:
|
|
76
|
-
conf[:
|
|
67
|
+
conf[:google_translate_api_key] = ENV["GOOGLE_TRANSLATE_API_KEY"] if ENV.key?("GOOGLE_TRANSLATE_API_KEY")
|
|
68
|
+
conf[:deepl_api_key] = ENV["DEEPL_AUTH_KEY"] if ENV.key?("DEEPL_AUTH_KEY")
|
|
69
|
+
conf[:deepl_host] = ENV["DEEPL_HOST"] if ENV.key?("DEEPL_HOST")
|
|
70
|
+
conf[:deepl_version] = ENV["DEEPL_VERSION"] if ENV.key?("DEEPL_VERSION")
|
|
71
|
+
conf[:openai_api_key] = ENV["OPENAI_API_KEY"] if ENV.key?("OPENAI_API_KEY")
|
|
72
|
+
conf[:openai_model] = ENV["OPENAI_MODEL"] if ENV.key?("OPENAI_MODEL")
|
|
73
|
+
conf[:openai_locale_prompts] ||= {}
|
|
74
|
+
conf[:watsonx_api_key] = ENV["WATSONX_API_KEY"] if ENV.key?("WATSONX_API_KEY")
|
|
75
|
+
conf[:watsonx_project_id] = ENV["WATSONX_PROJECT_ID"] if ENV.key?("WATSONX_PROJECT_ID")
|
|
76
|
+
conf[:watsonx_model] = ENV["WATSONX_MODEL"] if ENV.key?("WATSONX_MODEL")
|
|
77
|
+
conf[:yandex_api_key] = ENV["YANDEX_API_KEY"] if ENV.key?("YANDEX_API_KEY")
|
|
77
78
|
conf
|
|
78
79
|
end
|
|
79
80
|
end
|
|
@@ -91,11 +92,11 @@ module I18n::Tasks::Configuration # rubocop:disable Metrics/ModuleLength
|
|
|
91
92
|
def internal_locale
|
|
92
93
|
@config_sections[:internal_locale] ||= begin
|
|
93
94
|
internal_locale = (config[:internal_locale] || DEFAULTS[:internal_locale]).to_s
|
|
94
|
-
valid_locales = Dir[File.join(I18n::Tasks.gem_path,
|
|
95
|
-
|
|
95
|
+
valid_locales = Dir[File.join(I18n::Tasks.gem_path, "config", "locales", "*.yml")]
|
|
96
|
+
.map { |f| File.basename(f, ".yml") }
|
|
96
97
|
unless valid_locales.include?(internal_locale)
|
|
97
98
|
log_warn "invalid internal_locale #{internal_locale.inspect}. " \
|
|
98
|
-
"Available internal locales: #{valid_locales *
|
|
99
|
+
"Available internal locales: #{valid_locales * ", "}."
|
|
99
100
|
internal_locale = DEFAULTS[:internal_locale].to_s
|
|
100
101
|
end
|
|
101
102
|
internal_locale
|
|
@@ -103,7 +104,7 @@ module I18n::Tasks::Configuration # rubocop:disable Metrics/ModuleLength
|
|
|
103
104
|
end
|
|
104
105
|
|
|
105
106
|
def ignore_config(type = nil)
|
|
106
|
-
key = type ? "ignore_#{type}" :
|
|
107
|
+
key = type ? "ignore_#{type}" : "ignore"
|
|
107
108
|
@config_sections[key] ||= config[key]
|
|
108
109
|
end
|
|
109
110
|
|
|
@@ -126,7 +127,7 @@ module I18n::Tasks::Configuration # rubocop:disable Metrics/ModuleLength
|
|
|
126
127
|
def config_for_inspect
|
|
127
128
|
to_hash_from_indifferent(config_sections.reject { |_k, v| v.blank? }).tap do |sections|
|
|
128
129
|
sections.each_value do |section|
|
|
129
|
-
section.merge! section.delete(
|
|
130
|
+
section.merge! section.delete("config") if section.is_a?(Hash) && section.key?("config")
|
|
130
131
|
end
|
|
131
132
|
end
|
|
132
133
|
end
|
|
@@ -16,12 +16,12 @@ module I18n::Tasks
|
|
|
16
16
|
|
|
17
17
|
class << self
|
|
18
18
|
def start
|
|
19
|
-
require
|
|
19
|
+
require "irb"
|
|
20
20
|
IRB.setup nil
|
|
21
21
|
ctx = IRB::Irb.new.context
|
|
22
22
|
IRB.conf[:MAIN_CONTEXT] = ctx
|
|
23
|
-
|
|
24
|
-
require
|
|
23
|
+
warn Messages.banner
|
|
24
|
+
require "irb/ext/multi-irb"
|
|
25
25
|
IRB.irb nil, new
|
|
26
26
|
end
|
|
27
27
|
end
|
|
@@ -30,18 +30,18 @@ module I18n::Tasks
|
|
|
30
30
|
module_function
|
|
31
31
|
|
|
32
32
|
def banner
|
|
33
|
-
Rainbow("i18n-tasks v#{I18n::Tasks::VERSION} IRB").bright + "\nType #{Rainbow(
|
|
33
|
+
Rainbow("i18n-tasks v#{I18n::Tasks::VERSION} IRB").bright + "\nType #{Rainbow("guide").green} to learn more"
|
|
34
34
|
end
|
|
35
35
|
|
|
36
36
|
def guide
|
|
37
|
-
"#{Rainbow(
|
|
38
|
-
#{Rainbow(
|
|
37
|
+
"#{Rainbow("i18n-tasks IRB Quick Start guide").green.bright}\n#{<<~TEXT}"
|
|
38
|
+
#{Rainbow("Data as trees").yellow}
|
|
39
39
|
tree(locale)
|
|
40
40
|
used_tree(key_filter: nil, strict: nil)
|
|
41
41
|
unused_tree(locale: base_locale, strict: nil)
|
|
42
42
|
build_tree('es' => {'hello' => 'Hola'})
|
|
43
43
|
|
|
44
|
-
#{Rainbow(
|
|
44
|
+
#{Rainbow("Traversal").yellow}
|
|
45
45
|
tree = missing_diff_tree('es')
|
|
46
46
|
tree.nodes { |node| }
|
|
47
47
|
tree.nodes.to_a
|
|
@@ -49,23 +49,23 @@ module I18n::Tasks
|
|
|
49
49
|
tree.each { |root_node| }
|
|
50
50
|
# also levels, depth_first, and breadth_first
|
|
51
51
|
|
|
52
|
-
#{Rainbow(
|
|
52
|
+
#{Rainbow("Select nodes").yellow}
|
|
53
53
|
tree.select_nodes { |node| } # new tree with only selected nodes
|
|
54
54
|
|
|
55
|
-
#{Rainbow(
|
|
55
|
+
#{Rainbow("Match by full key").yellow}
|
|
56
56
|
tree.select_keys { |key, leaf| } # new tree with only selected keys
|
|
57
57
|
tree.grep_keys(/hello/) # grep, using ===
|
|
58
58
|
tree.keys { |key, leaf| } # enumerate over [full_key, leaf_node]
|
|
59
59
|
# Pass {root: true} to include root node in full_key (usually locale)
|
|
60
60
|
|
|
61
|
-
#{Rainbow(
|
|
61
|
+
#{Rainbow("Nodes").yellow}
|
|
62
62
|
node = node(key, locale)
|
|
63
63
|
node.key # only the part after the last dot
|
|
64
64
|
node.full_key # full key. Includes root key, pass {root: false} to override.
|
|
65
65
|
# also: value, value_or_children_hash, data, walk_to_root, walk_from_root
|
|
66
66
|
Tree::Node.new(key: 'en')
|
|
67
67
|
|
|
68
|
-
#{Rainbow(
|
|
68
|
+
#{Rainbow("Keys").yellow}
|
|
69
69
|
t(key, locale)
|
|
70
70
|
key_value?(key, locale)
|
|
71
71
|
depluralize_key(key, locale) # convert 'hat.one' to 'hat'
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require
|
|
3
|
+
require "yaml"
|
|
4
4
|
module I18n::Tasks
|
|
5
5
|
module Data
|
|
6
6
|
module Adapter
|
|
7
7
|
module YamlAdapter
|
|
8
|
-
EMOJI_REGEX = /\\u[\da-f]{8}/i
|
|
9
|
-
TRAILING_SPACE_REGEX = /
|
|
8
|
+
EMOJI_REGEX = /\\u[\da-f]{8}/i
|
|
9
|
+
TRAILING_SPACE_REGEX = / $/
|
|
10
10
|
|
|
11
11
|
class << self
|
|
12
12
|
# @return [Hash] locale tree
|
|
@@ -26,12 +26,12 @@ module I18n::Tasks
|
|
|
26
26
|
|
|
27
27
|
# @return [String]
|
|
28
28
|
def restore_emojis(yaml)
|
|
29
|
-
yaml.gsub(EMOJI_REGEX) { |m| [m[-8..].to_i(16)].pack(
|
|
29
|
+
yaml.gsub(EMOJI_REGEX) { |m| [m[-8..].to_i(16)].pack("U") }
|
|
30
30
|
end
|
|
31
31
|
|
|
32
32
|
# @return [String]
|
|
33
33
|
def strip_trailing_spaces(yaml)
|
|
34
|
-
yaml.gsub(TRAILING_SPACE_REGEX,
|
|
34
|
+
yaml.gsub(TRAILING_SPACE_REGEX, "")
|
|
35
35
|
end
|
|
36
36
|
end
|
|
37
37
|
end
|