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,12 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'i18n/tasks/translators/base_translator'
3
+ require "i18n/tasks/translators/base_translator"
4
4
 
5
5
  module I18n::Tasks::Translators
6
6
  class YandexTranslator < BaseTranslator
7
7
  def initialize(*)
8
8
  begin
9
- require 'yandex-translator'
9
+ require "yandex-translator"
10
10
  rescue LoadError
11
11
  raise ::I18n::Tasks::CommandError, "Add gem 'yandex-translator' to your Gemfile to use this command"
12
12
  end
@@ -16,7 +16,11 @@ module I18n::Tasks::Translators
16
16
  protected
17
17
 
18
18
  def translate_values(list, **options)
19
- list.map { |item| translator.translate(item, options) }
19
+ result = list.map { |item| translator.translate(item, options) }
20
+
21
+ @progress_bar.progress += result.size
22
+
23
+ result
20
24
  end
21
25
 
22
26
  def options_for_translate_values(from:, to:, **options)
@@ -27,24 +31,24 @@ module I18n::Tasks::Translators
27
31
  end
28
32
 
29
33
  def options_for_html
30
- { format: 'html' }
34
+ {format: "html"}
31
35
  end
32
36
 
33
37
  def options_for_plain
34
- { format: 'plain' }
38
+ {format: "plain"}
35
39
  end
36
40
 
37
41
  def no_results_error_message
38
- I18n.t('i18n_tasks.yandex_translate.errors.no_results')
42
+ I18n.t("i18n_tasks.yandex_translate.errors.no_results")
39
43
  end
40
44
 
41
45
  private
42
46
 
43
47
  # Convert 'es-ES' to 'es'
44
48
  def to_yandex_compatible_locale(locale)
45
- return locale unless locale.include?('-')
49
+ return locale unless locale.include?("-")
46
50
 
47
- locale.split('-', 2).first
51
+ locale.split("-", 2).first
48
52
  end
49
53
 
50
54
  def translator
@@ -54,7 +58,7 @@ module I18n::Tasks::Translators
54
58
  def api_key
55
59
  @api_key ||= begin
56
60
  key = @i18n_tasks.translation_config[:yandex_api_key]
57
- fail ::I18n::Tasks::CommandError, I18n.t('i18n_tasks.yandex_translate.errors.no_api_key') if key.blank?
61
+ fail ::I18n::Tasks::CommandError, I18n.t("i18n_tasks.yandex_translate.errors.no_api_key") if key.blank?
58
62
 
59
63
  key
60
64
  end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'set'
3
+ require "set"
4
4
 
5
5
  module I18n
6
6
  module Tasks
@@ -1,17 +1,17 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'find'
4
- require 'i18n/tasks/scanners/pattern_with_scope_scanner'
5
- require 'i18n/tasks/scanners/ruby_ast_scanner'
6
- require 'i18n/tasks/scanners/erb_ast_scanner'
7
- require 'i18n/tasks/scanners/scanner_multiplexer'
8
- require 'i18n/tasks/scanners/files/caching_file_finder_provider'
9
- require 'i18n/tasks/scanners/files/caching_file_reader'
3
+ require "find"
4
+ require "i18n/tasks/scanners/pattern_with_scope_scanner"
5
+ require "i18n/tasks/scanners/ruby_scanner"
6
+ require "i18n/tasks/scanners/erb_ast_scanner"
7
+ require "i18n/tasks/scanners/scanner_multiplexer"
8
+ require "i18n/tasks/scanners/files/caching_file_finder_provider"
9
+ require "i18n/tasks/scanners/files/caching_file_reader"
10
10
 
11
11
  # Require the pattern mapper even though it's not used by i18n-tasks directly.
12
12
  # This allows the user to use it in config/i18n-tasks.yml without having to require it.
13
13
  # See https://github.com/glebm/i18n-tasks/issues/204.
14
- require 'i18n/tasks/scanners/pattern_mapper'
14
+ require "i18n/tasks/scanners/pattern_mapper"
15
15
 
16
16
  module I18n::Tasks
17
17
  module UsedKeys # rubocop:disable Metrics/ModuleLength
@@ -20,17 +20,17 @@ module I18n::Tasks
20
20
  relative_exclude_method_name_paths: [],
21
21
  relative_roots: %w[app/controllers app/helpers app/mailers app/presenters app/views].freeze,
22
22
  scanners: [
23
- ['::I18n::Tasks::Scanners::RubyAstScanner', { only: %w[*.rb] }],
24
- ['::I18n::Tasks::Scanners::ErbAstScanner', { only: %w[*.html.erb] }],
25
- ['::I18n::Tasks::Scanners::PatternWithScopeScanner', { exclude: %w[*.html.erb *.rb] }]
23
+ ["::I18n::Tasks::Scanners::RubyScanner", {only: %w[*.rb]}],
24
+ ["::I18n::Tasks::Scanners::ErbAstScanner", {only: %w[*.erb]}],
25
+ ["::I18n::Tasks::Scanners::PatternWithScopeScanner", {exclude: %w[*.erb *.rb]}]
26
26
  ],
27
27
  ast_matchers: [],
28
28
  strict: true
29
29
  }.freeze
30
30
 
31
31
  ALWAYS_EXCLUDE = %w[*.jpg *.jpeg *.png *.gif *.svg *.ico *.eot *.otf *.ttf *.woff *.woff2 *.pdf *.css *.sass *.scss
32
- *.less *.yml *.json *.zip *.tar.gz *.swf *.flv *.mp3 *.wav *.flac *.webm *.mp4 *.ogg *.opus
33
- *.webp *.map *.xlsx].freeze
32
+ *.less *.yml *.json *.zip *.tar.gz *.swf *.flv *.mp3 *.wav *.flac *.webm *.mp4 *.ogg *.opus
33
+ *.webp *.map *.xlsx].freeze
34
34
 
35
35
  # Find all keys in the source and return a forest with the keys in absolute form and their occurrences.
36
36
  #
@@ -40,12 +40,12 @@ module I18n::Tasks
40
40
  # @return [Data::Tree::Siblings]
41
41
  def used_tree(key_filter: nil, strict: nil, include_raw_references: false)
42
42
  src_tree = used_in_source_tree(key_filter: key_filter, strict: strict)
43
- raw_refs, resolved_refs, used_refs = process_references(src_tree['used'].children)
43
+ raw_refs, resolved_refs, used_refs = process_references(src_tree["used"].children)
44
44
  raw_refs.leaves { |node| node.data[:ref_type] = :reference_usage }
45
45
  resolved_refs.leaves { |node| node.data[:ref_type] = :reference_usage_resolved }
46
46
  used_refs.leaves { |node| node.data[:ref_type] = :reference_usage_key }
47
47
  src_tree.tap do |result|
48
- tree = result['used'].children
48
+ tree = result["used"].children
49
49
  tree.subtract_by_key!(raw_refs)
50
50
  tree.merge!(raw_refs) if include_raw_references
51
51
  tree.merge!(used_refs).merge!(resolved_refs)
@@ -57,11 +57,11 @@ module I18n::Tasks
57
57
  scanner(strict: strict).keys.freeze)
58
58
  if key_filter
59
59
  key_filter_re = compile_key_pattern(key_filter)
60
- keys = keys.select { |k| k.key =~ key_filter_re }
60
+ keys = keys.select { |k| k.key =~ key_filter_re }
61
61
  end
62
62
  Data::Tree::Node.new(
63
- key: 'used',
64
- data: { key_filter: key_filter },
63
+ key: "used",
64
+ data: {key_filter: key_filter},
65
65
  children: Data::Tree::Siblings.from_key_occurrences(keys)
66
66
  ).to_siblings
67
67
  end
@@ -71,11 +71,11 @@ module I18n::Tasks
71
71
  shared_options = search_config.dup
72
72
  shared_options.delete(:scanners)
73
73
  shared_options[:strict] = strict unless strict.nil?
74
- log_verbose 'Scanners: '
74
+ log_verbose "Scanners: "
75
75
  Scanners::ScannerMultiplexer.new(
76
76
  scanners: search_config[:scanners].map do |(class_name, args)|
77
77
  if args && args[:strict]
78
- fail CommandError, 'the strict option is global and cannot be applied on the scanner level'
78
+ fail CommandError, "the strict option is global and cannot be applied on the scanner level"
79
79
  end
80
80
 
81
81
  ActiveSupport::Inflector.constantize(class_name).new(
@@ -92,15 +92,15 @@ module I18n::Tasks
92
92
  @search_config ||= begin
93
93
  conf = (config[:search] || {}).deep_symbolize_keys
94
94
  if conf[:scanner]
95
- warn_deprecated 'search.scanner is now search.scanners, an array of [ScannerClass, options]'
95
+ warn_deprecated "search.scanner is now search.scanners, an array of [ScannerClass, options]"
96
96
  conf[:scanners] = [[conf.delete(:scanner)]]
97
97
  end
98
98
  if conf[:ignore_lines]
99
- warn_deprecated 'search.ignore_lines is no longer a global setting: pass it directly to the pattern scanner.'
99
+ warn_deprecated "search.ignore_lines is no longer a global setting: pass it directly to the pattern scanner."
100
100
  conf.delete(:ignore_lines)
101
101
  end
102
102
  if conf[:include]
103
- warn_deprecated 'search.include is now search.only'
103
+ warn_deprecated "search.include is now search.only"
104
104
  conf[:only] = conf.delete(:include)
105
105
  end
106
106
  merge_scanner_configs(SEARCH_DEFAULTS, conf).freeze
@@ -142,19 +142,19 @@ module I18n::Tasks
142
142
 
143
143
  # keys in the source that end with a ., e.g. t("category.#{ cat.i18n_key }") or t("category." + category.key)
144
144
  # @param [String] replacement for interpolated values.
145
- def expr_key_re(replacement: '*:')
145
+ def expr_key_re(replacement: "*:")
146
146
  @expr_key_re ||= begin
147
147
  # disallow patterns with no keys
148
148
  ignore_pattern_re = /\A[.#{replacement}]*\z/
149
- patterns = used_in_source_tree(strict: false).key_names.select do |k|
150
- k.end_with?('.') || k =~ /\#{/
149
+ patterns = used_in_source_tree(strict: false).key_names.select do |k|
150
+ k.end_with?(".") || k =~ /\#{/
151
151
  end.map do |k|
152
- pattern = "#{replace_key_exp(k, replacement)}#{replacement if k.end_with?('.')}"
152
+ pattern = "#{replace_key_exp(k, replacement)}#{replacement if k.end_with?(".")}"
153
153
  next if pattern =~ ignore_pattern_re
154
154
 
155
155
  pattern
156
156
  end.compact
157
- compile_key_pattern "{#{patterns * ','}}"
157
+ compile_key_pattern "{#{patterns * ","}}"
158
158
  end
159
159
  end
160
160
 
@@ -164,18 +164,18 @@ module I18n::Tasks
164
164
  # @return [String]
165
165
  def replace_key_exp(key, replacement)
166
166
  scanner = StringScanner.new(key)
167
- braces = []
168
- result = []
167
+ braces = []
168
+ result = []
169
169
  while (match_until = scanner.scan_until(/(?:#?\{|})/))
170
170
  case scanner.matched
171
171
  when '#{'
172
172
  braces << scanner.matched
173
173
  result << match_until[0..-3] if braces.length == 1
174
- when '}'
174
+ when "}"
175
175
  prev_brace = braces.pop
176
176
  result << replacement if braces.empty? && prev_brace == '#{'
177
177
  else
178
- braces << '{'
178
+ braces << "{"
179
179
  end
180
180
  end
181
181
  result << key[scanner.pos..] unless scanner.eos?
@@ -2,6 +2,6 @@
2
2
 
3
3
  module I18n
4
4
  module Tasks
5
- VERSION = '1.0.14'
5
+ VERSION = "1.1.0"
6
6
  end
7
7
  end
data/lib/i18n/tasks.rb CHANGED
@@ -5,7 +5,7 @@ module I18n
5
5
  module Tasks
6
6
  class << self
7
7
  def gem_path
8
- File.expand_path(File.join(File.dirname(__FILE__), '..', '..'))
8
+ File.expand_path(File.join(File.dirname(__FILE__), "..", ".."))
9
9
  end
10
10
 
11
11
  def verbose?
@@ -47,7 +47,7 @@ module I18n
47
47
  end
48
48
  end
49
49
 
50
- @verbose = !ENV['VERBOSE'].nil?
50
+ @verbose = !ENV["VERBOSE"].nil?
51
51
 
52
52
  module Data
53
53
  end
@@ -56,25 +56,26 @@ end
56
56
 
57
57
  # Per https://github.com/rails/rails/commit/0181f0edd57a2149278bd59c3519233ca1e0a413#commitcomment-60940992
58
58
  # 'active_support' must be required first even if we only use parts of it.
59
- require 'active_support'
59
+ require "active_support"
60
60
 
61
- require 'active_support/inflector'
62
- require 'active_support/core_ext/hash'
63
- require 'active_support/core_ext/array/access'
64
- require 'active_support/core_ext/array/extract_options'
65
- require 'active_support/core_ext/module/delegation'
66
- require 'active_support/core_ext/object/blank'
67
- require 'active_support/core_ext/object/try'
61
+ require "active_support/inflector"
62
+ require "active_support/core_ext/hash"
63
+ require "active_support/core_ext/array/access"
64
+ require "active_support/core_ext/array/extract_options"
65
+ require "active_support/core_ext/module/delegation"
66
+ require "active_support/core_ext/object/blank"
67
+ require "active_support/core_ext/object/try"
68
68
 
69
- require 'rainbow'
70
- require 'erubi'
69
+ require "ruby-progressbar"
70
+ require "rainbow"
71
+ require "erubi"
71
72
 
72
- require 'i18n/tasks/version'
73
- require 'i18n/tasks/base_task'
73
+ require "i18n/tasks/version"
74
+ require "i18n/tasks/base_task"
74
75
 
75
76
  # Add internal locale data to i18n gem load path
76
- require 'i18n'
77
+ require "i18n"
77
78
 
78
- Dir[File.join(I18n::Tasks.gem_path, 'config', 'locales', '*.yml')].each do |locale_file|
79
+ Dir[File.join(I18n::Tasks.gem_path, "config", "locales", "*.yml")].each do |locale_file|
79
80
  I18n.config.load_path << locale_file
80
81
  end
@@ -34,7 +34,7 @@ data:
34
34
  ## Example (replace %#= with %=):
35
35
  # - "<%#= %x[bundle info vagrant --path].chomp %>/templates/locales/%{locale}.yml"
36
36
 
37
- ## Specify the router (see Readme for details). Valid values: conservative_router, pattern_router, or a custom class.
37
+ ## Specify the router (see Readme for details). Valid values: conservative_router, pattern_router, isolating_router, or a custom class.
38
38
  # router: conservative_router
39
39
 
40
40
  yaml:
@@ -122,12 +122,24 @@ search:
122
122
  # formality: prefer_less
123
123
  # # OpenAI
124
124
  # openai_api_key: "sk-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
125
- # # openai_model: "gpt-3.5-turbo" # see https://platform.openai.com/docs/models
125
+ # # openai_model: "gpt-4o-mini" # see https://platform.openai.com/docs/models
126
+ # # openai_temperature: 0.0 # Controls randomness in responses (0.0-2.0), default: 0.0
126
127
  # # may contain `%{from}` and `%{to}`, which will be replaced by source and target locale codes, respectively (using `Kernel.format`)
127
128
  # # openai_system_prompt: >-
128
129
  # # You are a professional translator that translates content from the %{from} locale
129
130
  # # to the %{to} locale in an i18n locale array.
130
131
  # #
132
+ # # Per-locale prompts override the default prompt for specific target locales
133
+ # # openai_locale_prompts:
134
+ # # es: >-
135
+ # # You are a professional translator specializing in Latin American Spanish.
136
+ # # Translate content from the %{from} locale to the %{to} locale, using informal language
137
+ # # and regional expressions common in Mexico.
138
+ # # ja: >-
139
+ # # You are a professional translator specializing in business Japanese.
140
+ # # Translate content from the %{from} locale to the %{to} locale using formal, professional
141
+ # # language appropriate for business contexts.
142
+ # #
131
143
  # # The array has a structured format and contains multiple strings. Your task is to translate
132
144
  # # each of these strings and create a new array with the translated strings.
133
145
  # #
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'i18n/tasks'
3
+ require "i18n/tasks"
4
4
 
5
5
  class I18nTest < ActiveSupport::TestCase
6
6
  def setup
@@ -10,13 +10,13 @@ class I18nTest < ActiveSupport::TestCase
10
10
  def test_no_missing_keys
11
11
  missing_keys = @i18n.missing_keys
12
12
  assert_empty missing_keys,
13
- "Missing #{missing_keys.leaves.count} i18n keys, run `i18n-tasks missing' to show them"
13
+ "Missing #{missing_keys.leaves.count} i18n keys, run `i18n-tasks missing' to show them"
14
14
  end
15
15
 
16
16
  def test_no_unused_keys
17
17
  unused_keys = @i18n.unused_keys
18
18
  assert_empty unused_keys,
19
- "#{unused_keys.leaves.count} unused i18n keys, run `i18n-tasks unused' to show them"
19
+ "#{unused_keys.leaves.count} unused i18n keys, run `i18n-tasks unused' to show them"
20
20
  end
21
21
 
22
22
  def test_files_are_normalized
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'i18n/tasks'
3
+ require "i18n/tasks"
4
4
 
5
5
  RSpec.describe I18n do
6
6
  let(:i18n) { I18n::Tasks::BaseTask.new }
@@ -8,17 +8,17 @@ RSpec.describe I18n do
8
8
  let(:unused_keys) { i18n.unused_keys }
9
9
  let(:inconsistent_interpolations) { i18n.inconsistent_interpolations }
10
10
 
11
- it 'does not have missing keys' do
11
+ it "does not have missing keys" do
12
12
  expect(missing_keys).to be_empty,
13
- "Missing #{missing_keys.leaves.count} i18n keys, run `i18n-tasks missing' to show them"
13
+ "Missing #{missing_keys.leaves.count} i18n keys, run `i18n-tasks missing' to show them"
14
14
  end
15
15
 
16
- it 'does not have unused keys' do
16
+ it "does not have unused keys" do
17
17
  expect(unused_keys).to be_empty,
18
- "#{unused_keys.leaves.count} unused i18n keys, run `i18n-tasks unused' to show them"
18
+ "#{unused_keys.leaves.count} unused i18n keys, run `i18n-tasks unused' to show them"
19
19
  end
20
20
 
21
- it 'files are normalized' do
21
+ it "files are normalized" do
22
22
  non_normalized = i18n.non_normalized_paths
23
23
  error_message = "The following files need to be normalized:\n" \
24
24
  "#{non_normalized.map { |path| " #{path}" }.join("\n")}\n" \
@@ -26,7 +26,7 @@ RSpec.describe I18n do
26
26
  expect(non_normalized).to be_empty, error_message
27
27
  end
28
28
 
29
- it 'does not have inconsistent interpolations' do
29
+ it "does not have inconsistent interpolations" do
30
30
  error_message = "#{inconsistent_interpolations.leaves.count} i18n keys have inconsistent interpolations.\n" \
31
31
  "Run `i18n-tasks check-consistent-interpolations' to show them"
32
32
  expect(inconsistent_interpolations).to be_empty, error_message