i18n-tasks 1.0.10 → 1.0.12

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c1ae937151395c0958e2cab91b89bca5b4b97fb12d307940a9e75bb005f41e2e
4
- data.tar.gz: 7dd9cbac5bc49401c15df858adae478c63d49f69e91c3a34b8ee7732793efb4c
3
+ metadata.gz: e77c4c19ca040adf1879259e8ad1d963e181eb1682e97ffa99f5b09d1b59e803
4
+ data.tar.gz: cc5ed0a16159c8f14a9006ab3908cfdc93b5dbc338603d54846d0ae4f84abb80
5
5
  SHA512:
6
- metadata.gz: 3b918580b7971a2843bf170277195e9bb59019b2040d2a8403f400ef41e718b25d5545b29a2b8b34f050db753d2f9067bc9a8b892c3b2c491403d80ecf0dfab6
7
- data.tar.gz: 254c3e547b8d06b684900f1dc3551ed1f52079a6623e5f572fb9bf9ec31c4eaa30b43eb9b2e0aeecd5287b69643a0ed23976bdd8886b42c5b7625bf879fb62ab
6
+ metadata.gz: 978d87d9e73dc5f4e183a7fdebabeec9864c3b1ba530f722bc3a80428b1c422eeda55f2bbd2b7ec8c1a67649ee128db4ae9ab0fc24db4b8cf386f7740b0f34d4
7
+ data.tar.gz: 46a0b0cbb262c17aaf1195293edd1fc04d665dd85d5f8d1b399f1ae565db2eb99e3e281fb1a34a5cb3629aadee2c2b279642d8beca623814fcd9b75c0c502b5e
data/README.md CHANGED
@@ -24,7 +24,7 @@ i18n-tasks can be used with any project using the ruby [i18n gem][i18n-gem] (def
24
24
  Add i18n-tasks to the Gemfile:
25
25
 
26
26
  ```ruby
27
- gem 'i18n-tasks', '~> 1.0.10'
27
+ gem 'i18n-tasks', '~> 1.0.12'
28
28
  ```
29
29
 
30
30
  Copy the default [configuration file](#configuration):
@@ -33,7 +33,7 @@ en:
33
33
  Value. Interpolates: %{value}, %{human_key}, %{key}, %{default}, %{value_or_human_key},
34
34
  %{value_or_default_or_human_key}
35
35
  desc:
36
- add_missing: add missing keys to locale data
36
+ add_missing: add missing keys to locale data, optionally match a pattern
37
37
  check_consistent_interpolations: verify that all translations use correct interpolation variables
38
38
  check_normalized: verify that all translation data is normalized
39
39
  config: display i18n-tasks configuration
@@ -46,12 +46,13 @@ en:
46
46
  gem_path: show path to the gem
47
47
  health: is everything OK?
48
48
  irb: start REPL session within i18n-tasks context
49
- missing: show missing translations
49
+ missing: show missing translations, optionally match a pattern
50
50
  mv: rename/merge the keys in locale data that match the given pattern
51
51
  normalize: 'normalize translation data: sort and move to the right files'
52
52
  remove_unused: remove unused keys
53
53
  rm: remove the keys in locale data that match the given pattern
54
- translate_missing: translate missing keys with Google Translate or DeepL Pro
54
+ translate_missing: translate missing keys with Google Translate or DeepL Pro, optionally match
55
+ a pattern
55
56
  tree_convert: convert tree between formats
56
57
  tree_filter: filter tree by key pattern
57
58
  tree_merge: merge trees
data/i18n-tasks.gemspec CHANGED
@@ -22,6 +22,8 @@ Gem::Specification.new do |s| # rubocop:disable Metrics/BlockLength
22
22
  cp $(bundle exec i18n-tasks gem-path)/templates/config/i18n-tasks.yml config/
23
23
  # Add an RSpec for missing and unused keys:
24
24
  cp $(bundle exec i18n-tasks gem-path)/templates/rspec/i18n_spec.rb spec/
25
+ # Or for minitest:
26
+ cp $(bundle exec i18n-tasks gem-path)/templates/minitest/i18n_test.rb test/
25
27
  TEXT
26
28
  s.homepage = 'https://github.com/glebm/i18n-tasks'
27
29
  s.metadata = {
@@ -38,7 +40,7 @@ Gem::Specification.new do |s| # rubocop:disable Metrics/BlockLength
38
40
 
39
41
  s.add_dependency 'activesupport', '>= 4.0.2'
40
42
  s.add_dependency 'ast', '>= 2.1.0'
41
- s.add_dependency 'better_html', '~> 1.0'
43
+ s.add_dependency 'better_html', '>= 1.0', '< 3.0'
42
44
  s.add_dependency 'erubi'
43
45
  s.add_dependency 'highline', '>= 2.0.0'
44
46
  s.add_dependency 'i18n'
@@ -36,11 +36,12 @@ class I18n::Tasks::CLI
36
36
  def run(argv)
37
37
  argv.each_with_index do |arg, i|
38
38
  if ['--config', '-c'].include?(arg)
39
- if File.exist?(argv[i + 1])
40
- @config_file = argv[i + 1]
39
+ _, config_file = argv.slice!(i, 2)
40
+ if File.exist?(config_file)
41
+ @config_file = config_file
41
42
  break
42
43
  else
43
- error "Config file doesn't exist: #{argv[i + 1]}", 128
44
+ error "Config file doesn't exist: #{config_file}", 128
44
45
  end
45
46
  end
46
47
  end
@@ -25,10 +25,14 @@ module I18n::Tasks
25
25
  cmd :missing,
26
26
  pos: '[locale ...]',
27
27
  desc: t('i18n_tasks.cmd.desc.missing'),
28
- args: %i[locales out_format missing_types]
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))
32
+ if opt[:pattern]
33
+ pattern_re = i18n.compile_key_pattern(opt[:pattern])
34
+ forest.select_keys! { |full_key, _node| full_key =~ pattern_re }
35
+ end
32
36
  print_forest forest, opt, :missing_keys
33
37
  :exit1 unless forest.empty?
34
38
  end
@@ -36,10 +40,14 @@ module I18n::Tasks
36
40
  cmd :translate_missing,
37
41
  pos: '[locale ...]',
38
42
  desc: t('i18n_tasks.cmd.desc.translate_missing'),
39
- args: [:locales, :locale_to_translate_from, arg(:out_format).from(1), :translation_backend]
43
+ args: [:locales, :locale_to_translate_from, arg(:out_format).from(1), :translation_backend, :pattern]
40
44
 
41
45
  def translate_missing(opt = {})
42
46
  missing = i18n.missing_diff_forest opt[:locales], opt[:from]
47
+ if opt[:pattern]
48
+ pattern_re = i18n.compile_key_pattern(opt[:pattern])
49
+ missing.select_keys! { |full_key, _node| full_key =~ pattern_re }
50
+ end
43
51
  translated = i18n.translate_forest missing, from: opt[:from], backend: opt[:backend].to_sym
44
52
  i18n.data.merge! translated
45
53
  log_stderr t('i18n_tasks.translate_missing.translated', count: translated.leaves.count)
@@ -49,7 +57,7 @@ module I18n::Tasks
49
57
  cmd :add_missing,
50
58
  pos: '[locale ...]',
51
59
  desc: t('i18n_tasks.cmd.desc.add_missing'),
52
- args: [:locales, :out_format, arg(:value) + [{ default: '%{value_or_default_or_human_key}' }],
60
+ args: [:locales, :out_format, :pattern, arg(:value) + [{ default: '%{value_or_default_or_human_key}' }],
53
61
  ['--nil-value', 'Set value to nil. Takes precedence over the value argument.']]
54
62
 
55
63
  # Merge base locale first, as this may affect the value for the other locales
@@ -60,6 +68,10 @@ module I18n::Tasks
60
68
  ].reject(&:empty?).each_with_object(i18n.empty_forest) do |locales, added|
61
69
  forest = i18n.missing_keys(locales: locales, **opt.slice(:types, :base_locale))
62
70
  .set_each_value!(opt[:'nil-value'] ? nil : opt[:value])
71
+ if opt[:pattern]
72
+ pattern_re = i18n.compile_key_pattern(opt[:pattern])
73
+ forest.select_keys! { |full_key, _node| full_key =~ pattern_re }
74
+ end
63
75
  i18n.data.merge! forest
64
76
  added.merge! forest
65
77
  end.tap do |added|
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'i18n/tasks/concurrent/cached_value'
4
-
5
3
  module I18n::Tasks::Concurrent
6
4
  # A thread-safe memoized value.
7
5
  # The given computation is guaranteed to be invoked at most once.
@@ -3,7 +3,6 @@
3
3
  require 'set'
4
4
  require 'i18n/tasks/split_key'
5
5
  require 'i18n/tasks/data/tree/nodes'
6
- require 'i18n/tasks/data/tree/node'
7
6
 
8
7
  module I18n::Tasks::Data::Tree
9
8
  # Siblings represents a subtree sharing a common parent
@@ -174,15 +174,29 @@ module I18n::Tasks
174
174
  human_key = ActiveSupport::Inflector.humanize(node.key.to_s)
175
175
  full_key = node.full_key
176
176
  default = (node.data[:occurrences] || []).detect { |o| o.default_arg.presence }.try(:default_arg)
177
- StringInterpolation.interpolate_soft(
178
- val_pattern,
179
- value: node_value,
180
- human_key: human_key,
181
- key: full_key,
182
- default: default,
183
- value_or_human_key: node_value.presence || human_key,
184
- value_or_default_or_human_key: node_value.presence || default || human_key
185
- )
177
+ if default.is_a?(Hash)
178
+ default.each_with_object({}) do |(k, v), h|
179
+ h[k] = StringInterpolation.interpolate_soft(
180
+ val_pattern,
181
+ value: node_value,
182
+ human_key: human_key,
183
+ key: full_key,
184
+ default: v,
185
+ value_or_human_key: node_value.presence || human_key,
186
+ value_or_default_or_human_key: node_value.presence || v || human_key
187
+ )
188
+ end
189
+ else
190
+ StringInterpolation.interpolate_soft(
191
+ val_pattern,
192
+ value: node_value,
193
+ human_key: human_key,
194
+ key: full_key,
195
+ default: default,
196
+ value_or_human_key: node_value.presence || human_key,
197
+ value_or_default_or_human_key: node_value.presence || default || human_key
198
+ )
199
+ end
186
200
  end
187
201
  pattern_re = I18n::Tasks::KeyPatternMatching.compile_key_pattern(key_pattern) if key_pattern.present?
188
202
  keys.each do |key, node|
@@ -10,7 +10,7 @@ module I18n::Tasks
10
10
  private
11
11
 
12
12
  def path_locale_re(locale)
13
- (@path_locale_res ||= {})[locale] ||= %r{(?<=^|[/.])#{locale}(?=[/.])}
13
+ (@path_locale_res ||= {})[locale] ||= %r{(?<=^|[/.-])#{locale}(?=[/.])}
14
14
  end
15
15
  end
16
16
  end
@@ -52,15 +52,9 @@ module I18n::Tasks::PluralKeys
52
52
  end
53
53
 
54
54
  def plural_forms?(s)
55
- return false if non_plural_other?(s)
56
-
57
55
  s.present? && s.all? { |node| node.leaf? && plural_suffix?(node.key) }
58
56
  end
59
57
 
60
- def non_plural_other?(s)
61
- s.size == 1 && s.first.leaf? && (!s.first.value.is_a?(String) || !s.first.value.include?('%{count}'))
62
- end
63
-
64
58
  def plural_suffix?(key)
65
59
  PLURAL_KEY_SUFFIXES.include?(key)
66
60
  end
@@ -54,6 +54,22 @@ module I18n::Tasks::Scanners::AstMatchers
54
54
  end
55
55
  end
56
56
 
57
+ # Extract the whole hash from a node of type `:hash`
58
+ #
59
+ # @param node [AST::Node] a node of type `:hash`.
60
+ # @return [Hash] the whole hash from the node
61
+ def extract_hash(node)
62
+ return {} if node.nil?
63
+
64
+ if node.type == :hash
65
+ node.children.each_with_object({}) do |pair, h|
66
+ key = pair.children[0].children[0].to_s
67
+ value = pair.children[1].children[0]
68
+ h[key] = value
69
+ end
70
+ end
71
+ end
72
+
57
73
  # Extract a hash pair with a given literal key.
58
74
  #
59
75
  # @param node [AST::Node] a node of type `:hash`.
@@ -77,8 +77,13 @@ module I18n::Tasks::Scanners::AstMatchers
77
77
 
78
78
  key = [scope, key].join('.') unless scope == ''
79
79
  end
80
- default_arg_node = extract_hash_pair(node, 'default')
81
- default_arg = extract_string(default_arg_node.children[1]) if default_arg_node
80
+ if default_arg_node = extract_hash_pair(node, 'default')
81
+ default_arg = if default_arg_node.children[1]&.type == :hash
82
+ extract_hash(default_arg_node.children[1])
83
+ else
84
+ extract_string(default_arg_node.children[1])
85
+ end
86
+ end
82
87
 
83
88
  [key, default_arg]
84
89
  end
@@ -30,7 +30,7 @@ module I18n::Tasks
30
30
 
31
31
  ALWAYS_EXCLUDE = %w[*.jpg *.jpeg *.png *.gif *.svg *.ico *.eot *.otf *.ttf *.woff *.woff2 *.pdf *.css *.sass *.scss *.less
32
32
  *.yml *.json *.zip *.tar.gz *.swf *.flv *.mp3 *.wav *.flac *.webm *.mp4 *.ogg *.opus
33
- *.webp *.map].freeze
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
  #
@@ -2,6 +2,6 @@
2
2
 
3
3
  module I18n
4
4
  module Tasks
5
- VERSION = '1.0.10'
5
+ VERSION = '1.0.12'
6
6
  end
7
7
  end
@@ -72,11 +72,13 @@ search:
72
72
  # -
73
73
 
74
74
  ## Files or `File.fnmatch` patterns to exclude from search. Some files are always excluded regardless of this setting:
75
- ## %w(*.jpg *.png *.gif *.svg *.ico *.eot *.otf *.ttf *.woff *.woff2 *.pdf *.css *.sass *.scss *.less *.yml *.json *.map)
75
+ ## *.jpg *.jpeg *.png *.gif *.svg *.ico *.eot *.otf *.ttf *.woff *.woff2 *.pdf *.css *.sass *.scss *.less
76
+ ## *.yml *.json *.zip *.tar.gz *.swf *.flv *.mp3 *.wav *.flac *.webm *.mp4 *.ogg *.opus *.webp *.map *.xlsx
76
77
  exclude:
77
78
  - app/assets/images
78
79
  - app/assets/fonts
79
80
  - app/assets/videos
81
+ - app/assets/builds
80
82
 
81
83
  ## Alternatively, the only files or `File.fnmatch patterns` to search in `paths`:
82
84
  ## If specified, this settings takes priority over `exclude`, but `exclude` still applies.
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: i18n-tasks
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.10
4
+ version: 1.0.12
5
5
  platform: ruby
6
6
  authors:
7
7
  - glebm
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-05-08 00:00:00.000000000 Z
11
+ date: 2022-09-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -42,16 +42,22 @@ dependencies:
42
42
  name: better_html
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - "~>"
45
+ - - ">="
46
46
  - !ruby/object:Gem::Version
47
47
  version: '1.0'
48
+ - - "<"
49
+ - !ruby/object:Gem::Version
50
+ version: '3.0'
48
51
  type: :runtime
49
52
  prerelease: false
50
53
  version_requirements: !ruby/object:Gem::Requirement
51
54
  requirements:
52
- - - "~>"
55
+ - - ">="
53
56
  - !ruby/object:Gem::Version
54
57
  version: '1.0'
58
+ - - "<"
59
+ - !ruby/object:Gem::Version
60
+ version: '3.0'
55
61
  - !ruby/object:Gem::Dependency
56
62
  name: erubi
57
63
  requirement: !ruby/object:Gem::Requirement
@@ -420,6 +426,8 @@ post_install_message: |
420
426
  cp $(bundle exec i18n-tasks gem-path)/templates/config/i18n-tasks.yml config/
421
427
  # Add an RSpec for missing and unused keys:
422
428
  cp $(bundle exec i18n-tasks gem-path)/templates/rspec/i18n_spec.rb spec/
429
+ # Or for minitest:
430
+ cp $(bundle exec i18n-tasks gem-path)/templates/minitest/i18n_test.rb test/
423
431
  rdoc_options: []
424
432
  require_paths:
425
433
  - lib
@@ -437,8 +445,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
437
445
  - !ruby/object:Gem::Version
438
446
  version: '0'
439
447
  requirements: []
440
- rubygems_version: 3.2.3
441
- signing_key:
448
+ rubygems_version: 3.1.2
449
+ signing_key:
442
450
  specification_version: 4
443
451
  summary: Manage localization and translation with the awesome power of static analysis
444
452
  test_files: []