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.
Files changed (101) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +138 -39
  3. data/Rakefile +4 -4
  4. data/bin/i18n-tasks +3 -3
  5. data/config/locales/en.yml +17 -1
  6. data/config/locales/ru.yml +18 -1
  7. data/i18n-tasks.gemspec +28 -38
  8. data/lib/i18n/tasks/base_task.rb +19 -19
  9. data/lib/i18n/tasks/cli.rb +37 -30
  10. data/lib/i18n/tasks/command/collection.rb +4 -4
  11. data/lib/i18n/tasks/command/commander.rb +5 -5
  12. data/lib/i18n/tasks/command/commands/check_prism.rb +126 -0
  13. data/lib/i18n/tasks/command/commands/data.rb +33 -33
  14. data/lib/i18n/tasks/command/commands/eq_base.rb +3 -3
  15. data/lib/i18n/tasks/command/commands/health.rb +6 -5
  16. data/lib/i18n/tasks/command/commands/interpolations.rb +14 -3
  17. data/lib/i18n/tasks/command/commands/meta.rb +6 -6
  18. data/lib/i18n/tasks/command/commands/missing.rb +28 -26
  19. data/lib/i18n/tasks/command/commands/tree.rb +33 -33
  20. data/lib/i18n/tasks/command/commands/usages.rb +24 -24
  21. data/lib/i18n/tasks/command/dsl.rb +1 -1
  22. data/lib/i18n/tasks/command/option_parsers/enum.rb +8 -7
  23. data/lib/i18n/tasks/command/option_parsers/locale.rb +4 -4
  24. data/lib/i18n/tasks/command/options/common.rb +16 -16
  25. data/lib/i18n/tasks/command/options/data.rb +18 -18
  26. data/lib/i18n/tasks/command/options/locales.rb +33 -24
  27. data/lib/i18n/tasks/commands.rb +14 -12
  28. data/lib/i18n/tasks/concurrent/cache.rb +1 -1
  29. data/lib/i18n/tasks/concurrent/cached_value.rb +1 -1
  30. data/lib/i18n/tasks/configuration.rb +26 -20
  31. data/lib/i18n/tasks/console_context.rb +11 -11
  32. data/lib/i18n/tasks/data/adapter/json_adapter.rb +1 -1
  33. data/lib/i18n/tasks/data/adapter/yaml_adapter.rb +5 -5
  34. data/lib/i18n/tasks/data/file_formats.rb +3 -3
  35. data/lib/i18n/tasks/data/file_system.rb +5 -5
  36. data/lib/i18n/tasks/data/file_system_base.rb +26 -26
  37. data/lib/i18n/tasks/data/language_names.rb +202 -0
  38. data/lib/i18n/tasks/data/router/conservative_router.rb +3 -3
  39. data/lib/i18n/tasks/data/router/isolating_router.rb +19 -19
  40. data/lib/i18n/tasks/data/router/pattern_router.rb +5 -5
  41. data/lib/i18n/tasks/data/tree/node.rb +27 -27
  42. data/lib/i18n/tasks/data/tree/nodes.rb +10 -10
  43. data/lib/i18n/tasks/data/tree/siblings.rb +20 -20
  44. data/lib/i18n/tasks/data/tree/traversal.rb +5 -5
  45. data/lib/i18n/tasks/data.rb +4 -4
  46. data/lib/i18n/tasks/html_keys.rb +2 -2
  47. data/lib/i18n/tasks/ignore_keys.rb +9 -9
  48. data/lib/i18n/tasks/interpolations.rb +21 -1
  49. data/lib/i18n/tasks/key_pattern_matching.rb +8 -8
  50. data/lib/i18n/tasks/logging.rb +2 -1
  51. data/lib/i18n/tasks/missing_keys.rb +24 -8
  52. data/lib/i18n/tasks/plural_keys.rb +6 -4
  53. data/lib/i18n/tasks/references.rb +4 -4
  54. data/lib/i18n/tasks/reports/base.rb +18 -14
  55. data/lib/i18n/tasks/reports/terminal.rb +64 -47
  56. data/lib/i18n/tasks/scanners/ast_matchers/base_matcher.rb +3 -3
  57. data/lib/i18n/tasks/scanners/ast_matchers/default_i18n_subject_matcher.rb +3 -3
  58. data/lib/i18n/tasks/scanners/ast_matchers/message_receivers_matcher.rb +10 -10
  59. data/lib/i18n/tasks/scanners/ast_matchers/rails_model_matcher.rb +2 -2
  60. data/lib/i18n/tasks/scanners/erb_ast_scanner.rb +69 -10
  61. data/lib/i18n/tasks/scanners/file_scanner.rb +5 -5
  62. data/lib/i18n/tasks/scanners/files/caching_file_finder.rb +3 -3
  63. data/lib/i18n/tasks/scanners/files/caching_file_finder_provider.rb +3 -3
  64. data/lib/i18n/tasks/scanners/files/caching_file_reader.rb +2 -2
  65. data/lib/i18n/tasks/scanners/files/file_finder.rb +8 -8
  66. data/lib/i18n/tasks/scanners/files/file_reader.rb +1 -1
  67. data/lib/i18n/tasks/scanners/local_ruby_parser.rb +9 -9
  68. data/lib/i18n/tasks/scanners/occurrence_from_position.rb +1 -1
  69. data/lib/i18n/tasks/scanners/pattern_mapper.rb +7 -7
  70. data/lib/i18n/tasks/scanners/pattern_scanner.rb +20 -20
  71. data/lib/i18n/tasks/scanners/pattern_with_scope_scanner.rb +8 -8
  72. data/lib/i18n/tasks/scanners/prism_scanners/arguments_visitor.rb +48 -0
  73. data/lib/i18n/tasks/scanners/prism_scanners/nodes.rb +374 -0
  74. data/lib/i18n/tasks/scanners/prism_scanners/visitor.rb +337 -0
  75. data/lib/i18n/tasks/scanners/relative_keys.rb +8 -8
  76. data/lib/i18n/tasks/scanners/results/key_occurrences.rb +3 -3
  77. data/lib/i18n/tasks/scanners/results/occurrence.rb +14 -10
  78. data/lib/i18n/tasks/scanners/ruby_ast_call_finder.rb +1 -1
  79. data/lib/i18n/tasks/scanners/ruby_key_literals.rb +6 -6
  80. data/lib/i18n/tasks/scanners/ruby_parser_factory.rb +27 -0
  81. data/lib/i18n/tasks/scanners/ruby_scanner.rb +225 -0
  82. data/lib/i18n/tasks/scanners/scanner.rb +2 -2
  83. data/lib/i18n/tasks/scanners/scanner_multiplexer.rb +1 -1
  84. data/lib/i18n/tasks/split_key.rb +4 -4
  85. data/lib/i18n/tasks/stats.rb +3 -3
  86. data/lib/i18n/tasks/translation.rb +8 -5
  87. data/lib/i18n/tasks/translators/base_translator.rb +43 -13
  88. data/lib/i18n/tasks/translators/deepl_translator.rb +22 -14
  89. data/lib/i18n/tasks/translators/google_translator.rb +178 -26
  90. data/lib/i18n/tasks/translators/openai_translator.rb +56 -31
  91. data/lib/i18n/tasks/translators/watsonx_translator.rb +155 -0
  92. data/lib/i18n/tasks/translators/yandex_translator.rb +13 -9
  93. data/lib/i18n/tasks/unused_keys.rb +1 -1
  94. data/lib/i18n/tasks/used_keys.rb +32 -32
  95. data/lib/i18n/tasks/version.rb +1 -1
  96. data/lib/i18n/tasks.rb +17 -16
  97. data/templates/config/i18n-tasks.yml +14 -2
  98. data/templates/minitest/i18n_test.rb +3 -3
  99. data/templates/rspec/i18n_spec.rb +7 -7
  100. metadata +38 -172
  101. data/lib/i18n/tasks/scanners/ruby_ast_scanner.rb +0 -145
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'i18n/tasks/command/collection'
3
+ require "i18n/tasks/command/collection"
4
4
 
5
5
  module I18n::Tasks
6
6
  module Command
@@ -10,22 +10,22 @@ module I18n::Tasks
10
10
 
11
11
  missing_types = I18n::Tasks::MissingKeys.missing_keys_types
12
12
  arg :missing_types,
13
- '-t',
14
- "--types #{missing_types * ','}",
15
- Array,
16
- t('i18n_tasks.cmd.args.desc.missing_types', valid: missing_types * ', '),
17
- parser: OptionParsers::Enum::ListParser.new(
18
- missing_types,
19
- proc do |invalid, valid|
20
- I18n.t('i18n_tasks.cmd.errors.invalid_missing_type',
21
- invalid: invalid * ', ', valid: valid * ', ', count: invalid.length)
22
- end
23
- )
13
+ "-t",
14
+ "--types #{missing_types * ","}",
15
+ Array,
16
+ t("i18n_tasks.cmd.args.desc.missing_types", valid: missing_types * ", "),
17
+ parser: OptionParsers::Enum::ListParser.new(
18
+ missing_types,
19
+ proc do |invalid, valid|
20
+ I18n.t("i18n_tasks.cmd.errors.invalid_missing_type",
21
+ invalid: invalid * ", ", valid: valid * ", ", count: invalid.length)
22
+ end
23
+ )
24
24
 
25
25
  cmd :missing,
26
- pos: '[locale ...]',
27
- desc: t('i18n_tasks.cmd.desc.missing'),
28
- args: %i[locales out_format missing_types pattern]
26
+ pos: "[locale ...]",
27
+ desc: t("i18n_tasks.cmd.desc.missing"),
28
+ args: %i[locales out_format missing_types pattern]
29
29
 
30
30
  def missing(opt = {})
31
31
  forest = i18n.missing_keys(**opt.slice(:locales, :base_locale, :types))
@@ -38,9 +38,9 @@ module I18n::Tasks
38
38
  end
39
39
 
40
40
  cmd :translate_missing,
41
- pos: '[locale ...]',
42
- desc: t('i18n_tasks.cmd.desc.translate_missing'),
43
- args: [:locales, :locale_to_translate_from, arg(:out_format).from(1), :translation_backend, :pattern]
41
+ pos: "[locale ...]",
42
+ desc: t("i18n_tasks.cmd.desc.translate_missing"),
43
+ args: [:locales, :locale_to_translate_from, arg(:out_format).from(1), :translation_backend, :pattern]
44
44
 
45
45
  def translate_missing(opt = {})
46
46
  missing = i18n.missing_diff_forest opt[:locales], opt[:from]
@@ -48,17 +48,19 @@ module I18n::Tasks
48
48
  pattern_re = i18n.compile_key_pattern(opt[:pattern])
49
49
  missing.select_keys! { |full_key, _node| full_key =~ pattern_re }
50
50
  end
51
- translated = i18n.translate_forest missing, from: opt[:from], backend: opt[:backend].to_sym
51
+
52
+ backend = opt[:backend].presence || i18n.translation_config[:backend]
53
+ translated = i18n.translate_forest missing, from: opt[:from], backend: backend.to_sym
52
54
  i18n.data.merge! translated
53
- log_stderr t('i18n_tasks.translate_missing.translated', count: translated.leaves.count)
55
+ log_stderr t("i18n_tasks.translate_missing.translated", count: translated.leaves.count)
54
56
  print_forest translated, opt
55
57
  end
56
58
 
57
59
  cmd :add_missing,
58
- pos: '[locale ...]',
59
- desc: t('i18n_tasks.cmd.desc.add_missing'),
60
- args: [:locales, :out_format, :pattern, arg(:value) + [{ default: '%{value_or_default_or_human_key}' }],
61
- ['--nil-value', 'Set value to nil. Takes precedence over the value argument.']]
60
+ pos: "[locale ...]",
61
+ desc: t("i18n_tasks.cmd.desc.add_missing"),
62
+ args: [:locales, :out_format, :pattern, arg(:value) + [{default: "%{value_or_default_or_human_key}"}],
63
+ ["--nil-value", "Set value to nil. Takes precedence over the value argument."]]
62
64
 
63
65
  # Merge base locale first, as this may affect the value for the other locales
64
66
  def add_missing(opt = {}) # rubocop:disable Metrics/AbcSize
@@ -67,7 +69,7 @@ module I18n::Tasks
67
69
  opt[:locales] - [i18n.base_locale]
68
70
  ].reject(&:empty?).each_with_object(i18n.empty_forest) do |locales, added|
69
71
  forest = i18n.missing_keys(locales: locales, **opt.slice(:types, :base_locale))
70
- .set_each_value!(opt[:'nil-value'] ? nil : opt[:value])
72
+ .set_each_value!(opt[:"nil-value"] ? nil : opt[:value])
71
73
  if opt[:pattern]
72
74
  pattern_re = i18n.compile_key_pattern(opt[:pattern])
73
75
  forest.select_keys! { |full_key, _node| full_key =~ pattern_re }
@@ -75,7 +77,7 @@ module I18n::Tasks
75
77
  i18n.data.merge! forest
76
78
  added.merge! forest
77
79
  end.tap do |added|
78
- log_stderr t('i18n_tasks.add_missing.added', count: added.leaves.count)
80
+ log_stderr t("i18n_tasks.add_missing.added", count: added.leaves.count)
79
81
  print_forest added, opt
80
82
  end
81
83
  end
@@ -8,9 +8,9 @@ module I18n::Tasks
8
8
  include I18n::Tasks::KeyPatternMatching
9
9
 
10
10
  cmd :tree_translate,
11
- pos: '[tree (or stdin)]',
12
- desc: t('i18n_tasks.cmd.desc.tree_translate'),
13
- args: [:locale_to_translate_from, arg(:data_format).from(1), :translation_backend]
11
+ pos: "[tree (or stdin)]",
12
+ desc: t("i18n_tasks.cmd.desc.tree_translate"),
13
+ args: [:locale_to_translate_from, arg(:data_format).from(1), :translation_backend]
14
14
 
15
15
  def tree_translate(opts = {})
16
16
  forest = forest_pos_or_stdin!(opts)
@@ -18,79 +18,79 @@ module I18n::Tasks
18
18
  end
19
19
 
20
20
  cmd :tree_merge,
21
- pos: '[[tree] [tree] ... (or stdin)]',
22
- desc: t('i18n_tasks.cmd.desc.tree_merge'),
23
- args: %i[data_format nostdin]
21
+ pos: "[[tree] [tree] ... (or stdin)]",
22
+ desc: t("i18n_tasks.cmd.desc.tree_merge"),
23
+ args: %i[data_format nostdin]
24
24
 
25
25
  def tree_merge(opts = {})
26
26
  print_forest merge_forests_stdin_and_pos!(opts), opts
27
27
  end
28
28
 
29
29
  cmd :tree_filter,
30
- pos: '[pattern] [tree (or stdin)]',
31
- desc: t('i18n_tasks.cmd.desc.tree_filter'),
32
- args: %i[data_format pattern]
30
+ pos: "[pattern] [tree (or stdin)]",
31
+ desc: t("i18n_tasks.cmd.desc.tree_filter"),
32
+ args: %i[data_format pattern]
33
33
 
34
34
  def tree_filter(opts = {})
35
35
  pattern = arg_or_pos! :pattern, opts
36
- forest = forest_pos_or_stdin! opts
36
+ forest = forest_pos_or_stdin! opts
37
37
  unless pattern.blank?
38
38
  pattern_re = i18n.compile_key_pattern(pattern)
39
- forest = forest.select_keys { |full_key, _node| full_key =~ pattern_re }
39
+ forest = forest.select_keys { |full_key, _node| full_key =~ pattern_re }
40
40
  end
41
41
  print_forest forest, opts
42
42
  end
43
43
 
44
44
  arg :all_locales,
45
- '-a',
46
- '--all-locales',
47
- t('i18n_tasks.cmd.args.desc.all_locales')
45
+ "-a",
46
+ "--all-locales",
47
+ t("i18n_tasks.cmd.args.desc.all_locales")
48
48
 
49
49
  cmd :tree_mv,
50
- pos: 'FROM_KEY_PATTERN TO_KEY_PATTERN [tree (or stdin)]',
51
- desc: t('i18n_tasks.cmd.desc.tree_mv_key'),
52
- args: %i[data_format all_locales]
50
+ pos: "FROM_KEY_PATTERN TO_KEY_PATTERN [tree (or stdin)]",
51
+ desc: t("i18n_tasks.cmd.desc.tree_mv_key"),
52
+ args: %i[data_format all_locales]
53
53
  def tree_mv(opt = {})
54
- fail CommandError, 'requires FROM_KEY_PATTERN and TO_KEY_PATTERN' if opt[:arguments].size < 2
54
+ fail CommandError, "requires FROM_KEY_PATTERN and TO_KEY_PATTERN" if opt[:arguments].size < 2
55
55
 
56
56
  from_pattern = opt[:arguments].shift
57
57
  to_pattern = opt[:arguments].shift
58
58
  forest = forest_pos_or_stdin!(opt)
59
- forest.mv_key!(compile_key_pattern(from_pattern), to_pattern, root: !opt[:'all-locales'])
59
+ forest.mv_key!(compile_key_pattern(from_pattern), to_pattern, root: !opt[:"all-locales"])
60
60
  print_forest forest, opt
61
61
  end
62
62
 
63
63
  cmd :tree_subtract,
64
- pos: '[[tree] [tree] ... (or stdin)]',
65
- desc: t('i18n_tasks.cmd.desc.tree_subtract'),
66
- args: %i[data_format nostdin]
64
+ pos: "[[tree] [tree] ... (or stdin)]",
65
+ desc: t("i18n_tasks.cmd.desc.tree_subtract"),
66
+ args: %i[data_format nostdin]
67
67
 
68
68
  def tree_subtract(opt = {})
69
69
  forests = forests_stdin_and_pos! opt, 2
70
- forest = forests.reduce(:subtract_by_key) || empty_forest
70
+ forest = forests.reduce(:subtract_by_key) || empty_forest
71
71
  print_forest forest, opt
72
72
  end
73
73
 
74
74
  cmd :tree_set_value,
75
- pos: '[VALUE] [tree (or stdin)]',
76
- desc: t('i18n_tasks.cmd.desc.tree_set_value'),
77
- args: %i[value data_format nostdin pattern]
75
+ pos: "[VALUE] [tree (or stdin)]",
76
+ desc: t("i18n_tasks.cmd.desc.tree_set_value"),
77
+ args: %i[value data_format nostdin pattern]
78
78
 
79
79
  def tree_set_value(opt = {})
80
- value = arg_or_pos! :value, opt
81
- forest = forest_pos_or_stdin!(opt)
80
+ value = arg_or_pos! :value, opt
81
+ forest = forest_pos_or_stdin!(opt)
82
82
  key_pattern = opt[:pattern]
83
- fail CommandError, 'pass value (-v, --value)' if value.blank?
83
+ fail CommandError, "pass value (-v, --value)" if value.blank?
84
84
 
85
85
  forest.set_each_value!(value, key_pattern)
86
86
  print_forest forest, opt
87
87
  end
88
88
 
89
89
  cmd :tree_convert,
90
- pos: '[tree (or stdin)]',
91
- desc: t('i18n_tasks.cmd.desc.tree_convert'),
92
- args: [arg(:data_format).dup.tap { |a| a[0..1] = ['-f', '--from FORMAT'] },
93
- arg(:out_format).dup.tap { |a| a[0..1] = ['-t', '--to FORMAT'] }]
90
+ pos: "[tree (or stdin)]",
91
+ desc: t("i18n_tasks.cmd.desc.tree_convert"),
92
+ args: [arg(:data_format).dup.tap { |a| a[0..1] = ["-f", "--from FORMAT"] },
93
+ arg(:out_format).dup.tap { |a| a[0..1] = ["-t", "--to FORMAT"] }]
94
94
 
95
95
  def tree_convert(opt = {})
96
96
  forest = forest_pos_or_stdin! opt.merge(format: opt[:from])
@@ -7,18 +7,18 @@ module I18n::Tasks
7
7
  include Command::Collection
8
8
 
9
9
  arg :strict,
10
- '--[no-]strict',
11
- t('i18n_tasks.cmd.args.desc.strict')
10
+ "--[no-]strict",
11
+ t("i18n_tasks.cmd.args.desc.strict")
12
12
 
13
13
  arg :keep_order,
14
- '-k',
15
- '--keep-order',
16
- t('i18n_tasks.cmd.args.desc.keep_order')
14
+ "-k",
15
+ "--keep-order",
16
+ t("i18n_tasks.cmd.args.desc.keep_order")
17
17
 
18
18
  cmd :find,
19
- pos: '[pattern]',
20
- desc: t('i18n_tasks.cmd.desc.find'),
21
- args: %i[out_format pattern strict]
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
- pos: '[locale ...]',
31
- desc: t('i18n_tasks.cmd.desc.unused'),
32
- args: %i[locales out_format strict]
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
- pos: '[locale ...]',
42
- desc: t('i18n_tasks.cmd.desc.remove_unused'),
43
- args: %i[locales out_format strict keep_order confirm pattern]
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[:'keep-order']
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('i18n_tasks.remove_unused.removed', count: unused_keys.leaves.count)
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('i18n_tasks.remove_unused.noop')).green.bright
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['CONFIRM'] || opt[:confirm]
68
+ return if ENV["CONFIRM"] || opt[:confirm]
69
69
 
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(' ')
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
@@ -17,7 +17,7 @@ module I18n::Tasks
17
17
  module ClassMethods
18
18
  def cmd(name, conf = nil)
19
19
  if conf
20
- conf = conf.dup
20
+ conf = conf.dup
21
21
  conf[:args] = (conf[:args] || []).map { |arg| arg.is_a?(Symbol) ? arg(arg) : arg }
22
22
  dsl(:cmds)[name] = conf
23
23
  else
@@ -6,20 +6,21 @@ module I18n::Tasks
6
6
  module Enum
7
7
  class Parser
8
8
  DEFAULT_ERROR = proc do |invalid, valid|
9
- I18n.t('i18n_tasks.cmd.enum_opt.invalid', invalid: invalid, valid: valid * ', ')
9
+ I18n.t("i18n_tasks.cmd.enum_opt.invalid", invalid: invalid, valid: valid * ", ")
10
10
  end
11
11
 
12
- def initialize(valid, error_message = DEFAULT_ERROR)
13
- @valid = valid.map(&:to_s)
12
+ def initialize(valid, error_message = DEFAULT_ERROR, allow_blank: false)
13
+ @valid = valid.map(&:to_s)
14
14
  @error_message = error_message
15
+ @allow_blank = allow_blank
15
16
  end
16
17
 
17
18
  def call(value, *)
18
- return @valid.first unless value.present?
19
+ return @valid.first if value.blank? && !@allow_blank
19
20
 
20
21
  if @valid.include?(value)
21
22
  value
22
- else
23
+ elsif value.present? || !@allow_blank
23
24
  fail CommandError, @error_message.call(value, @valid)
24
25
  end
25
26
  end
@@ -27,11 +28,11 @@ module I18n::Tasks
27
28
 
28
29
  class ListParser
29
30
  DEFAULT_ERROR = proc do |invalid, valid|
30
- I18n.t('i18n_tasks.cmd.enum_list_opt.invalid', invalid: invalid * ', ', valid: valid * ', ')
31
+ I18n.t("i18n_tasks.cmd.enum_list_opt.invalid", invalid: invalid * ", ", valid: valid * ", ")
31
32
  end
32
33
 
33
34
  def initialize(valid, error_message = DEFAULT_ERROR)
34
- @valid = valid.map(&:to_s)
35
+ @valid = valid.map(&:to_s)
35
36
  @error_message = error_message
36
37
  end
37
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.freeze
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('i18n_tasks.cmd.errors.invalid_locale', invalid: locale)
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 == 'base'
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 == 'base' ? context.base_locale : v }, context.base_locale)
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 'i18n/tasks/command/dsl'
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
- '-S',
13
- '--nostdin',
14
- t('i18n_tasks.cmd.args.desc.nostdin')
12
+ "-S",
13
+ "--nostdin",
14
+ t("i18n_tasks.cmd.args.desc.nostdin")
15
15
 
16
16
  arg :confirm,
17
- '-y',
18
- '--confirm',
19
- desc: t('i18n_tasks.cmd.args.desc.confirm')
17
+ "-y",
18
+ "--confirm",
19
+ desc: t("i18n_tasks.cmd.args.desc.confirm")
20
20
 
21
21
  arg :pattern,
22
- '-p',
23
- '--pattern PATTERN',
24
- t('i18n_tasks.cmd.args.desc.key_pattern')
22
+ "-p",
23
+ "--pattern PATTERN",
24
+ t("i18n_tasks.cmd.args.desc.key_pattern")
25
25
 
26
26
  arg :value,
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
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
- '-c',
33
- '--config FILE',
34
- t('i18n_tasks.cmd.args.desc.config')
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 'i18n/tasks/command/option_parsers/enum'
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 = ['terminal-table', *DATA_FORMATS, 'inspect', 'key-values'].freeze
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
- '-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)
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('i18n_tasks.cmd.errors.pass_forest') unless src
66
+ fail CommandError, I18n.t("i18n_tasks.cmd.errors.pass_forest") unless src
67
67
 
68
- if format == 'keys'
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 'terminal-table'
82
+ when "terminal-table"
83
83
  terminal_report.send(version, forest)
84
- when 'inspect'
84
+ when "inspect"
85
85
  puts forest.inspect
86
- when 'keys'
86
+ when "keys"
87
87
  puts forest.key_names(root: true)
88
- when 'key-values'
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,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'i18n/tasks/command/option_parsers/locale'
3
+ require "i18n/tasks/command/option_parsers/locale"
4
+ require "i18n/tasks/command/option_parsers/enum"
4
5
 
5
6
  module I18n::Tasks
6
7
  module Command
@@ -9,35 +10,43 @@ module I18n::Tasks
9
10
  include Command::DSL
10
11
 
11
12
  arg :locales,
12
- '-l',
13
- '--locales en,es,ru',
14
- Array,
15
- t('i18n_tasks.cmd.args.desc.locales_filter'),
16
- parser: OptionParsers::Locale::ListParser,
17
- default: 'all',
18
- consume_positional: true
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
19
20
 
20
21
  arg :locale,
21
- '-l',
22
- '--locale en',
23
- t('i18n_tasks.cmd.args.desc.locale'),
24
- parser: OptionParsers::Locale::Parser,
25
- default: 'base'
22
+ "-l",
23
+ "--locale en",
24
+ t("i18n_tasks.cmd.args.desc.locale"),
25
+ parser: OptionParsers::Locale::Parser,
26
+ default: "base"
26
27
 
27
28
  arg :locale_to_translate_from,
28
- '-f',
29
- '--from en',
30
- t('i18n_tasks.cmd.args.desc.locale_to_translate_from'),
31
- parser: OptionParsers::Locale::Parser,
32
- default: 'base'
29
+ "-f",
30
+ "--from en",
31
+ t("i18n_tasks.cmd.args.desc.locale_to_translate_from"),
32
+ parser: OptionParsers::Locale::Parser,
33
+ default: "base"
33
34
 
34
- TRANSLATION_BACKENDS = %w[google deepl].freeze
35
+ TRANSLATION_BACKENDS = %w[google deepl yandex openai watsonx].freeze
35
36
  arg :translation_backend,
36
- '-b',
37
- '--backend BACKEND',
38
- t('i18n_tasks.cmd.args.desc.translation_backend'),
39
- parser: OptionParsers::Locale::Parser,
40
- default: TRANSLATION_BACKENDS[0]
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
+ )
41
50
  end
42
51
  end
43
52
  end
@@ -1,16 +1,17 @@
1
1
  # frozen_string_literal: true
2
2
 
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/commander'
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 'highline/import'
29
+ require "highline/import"
28
30
  end
29
31
  end