i18n-tasks 0.9.24 → 0.9.25

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: e43145655fa3f1bfe8346745641fbab0cbcdc6d4fce7644360f47dc22c2d1c57
4
- data.tar.gz: 3ec016b5aca6502d4a8cc73e9f1850e6d87a6469e631d27a2b9710538b696e34
3
+ metadata.gz: c701c96d03c3226bb8c9a6e2bed8477c7846645ee384a93c569c090cfe9b76ae
4
+ data.tar.gz: 5209c23392064c0d0a15cc61f2a82d0a08294e58afd7b1466b433295ae861e98
5
5
  SHA512:
6
- metadata.gz: dc3f0df2e53aef54e7fa0d1953c3d448a4ccc57c8a04f60b1494ea3500b8b98d7473548683c62f5c36795a3bd20eab16ee4d2a898f2de6ca21b6cfd64d7dd67f
7
- data.tar.gz: d744f48d0b9572e93906cddce55004eadd8a8aa867f6ca436540bedb989274077a641d83c28b5a034adb1a7106d70a2cbac069301d2febcd32eb25e44c674ab8
6
+ metadata.gz: 4a573608dff03c12f15920a84ed5c01d2377c593e43ed1cf27c0f9a1951b75fa4211be678b1ad150df7a129365f09a77e398c45d6260c87213f62985dbad58d9
7
+ data.tar.gz: 9bf7f845ef28e04b87bbbdc9b0e293ef7187b808ce7a7b690434441a725d6b61ef74759f77e26d5df756d49220f04ff6d0a716581cda040979c41d2d1d374b4c
data/README.md CHANGED
@@ -22,7 +22,7 @@ i18n-tasks can be used with any project using the ruby [i18n gem][i18n-gem] (def
22
22
  Add i18n-tasks to the Gemfile:
23
23
 
24
24
  ```ruby
25
- gem 'i18n-tasks', '~> 0.9.24'
25
+ gem 'i18n-tasks', '~> 0.9.25'
26
26
  ```
27
27
 
28
28
  Copy the default [configuration file](#configuration):
@@ -125,6 +125,9 @@ $ i18n-tasks remove-unused
125
125
  These tasks can infer [dynamic keys](#dynamic-keys) such as `t("category.\#{category.name}")` if you set
126
126
  `search.strict` to false, or pass `--no-strict` on the command line.
127
127
 
128
+ If you want to keep the ordering from the original language file when using remove-unused, pass
129
+ `-k` or `--keep-order`.
130
+
128
131
  ### Normalize data
129
132
 
130
133
  Sort the keys:
@@ -13,6 +13,7 @@ en:
13
13
  locales implicitly.
14
14
  confirm: Confirm automatically
15
15
  data_format: 'Data format: %{valid_text}.'
16
+ keep_order: Keep the order of the keys
16
17
  key_pattern: Filter by key pattern (e.g. 'common.*')
17
18
  key_pattern_to_rename: Full key (pattern) to rename. Required
18
19
  locale: :i18n_tasks.common.locale
@@ -10,6 +10,7 @@ ru:
10
10
  all_locales: Не ожидать, что маски ключа начинаются с локали. Применять маски ко всем локалям.
11
11
  confirm: Подтвердить автоматом
12
12
  data_format: 'Формат данных: %{valid_text}. %{default_text}.'
13
+ keep_order: Keep the order of the keys
13
14
  key_pattern: Маска ключа (например, common.*)
14
15
  key_pattern_to_rename: Полный ключ (шаблон) для переименования. Необходимый параметр.
15
16
  locale: 'Язык. По умолчанию: base'
@@ -11,23 +11,21 @@ Gem::Specification.new do |s| # rubocop:disable Metrics/BlockLength
11
11
  s.email = ['glex.spb@gmail.com']
12
12
  s.license = 'MIT'
13
13
  s.summary = 'Manage localization and translation with the awesome power of static analysis'
14
- s.description = <<-TEXT
15
- i18n-tasks helps you find and manage missing and unused translations.
14
+ s.description = <<~TEXT
15
+ i18n-tasks helps you find and manage missing and unused translations.
16
16
 
17
- It analyses code statically for key usages, such as `I18n.t('some.key')`, in order to report keys that are missing or unused,
18
- pre-fill missing keys (optionally from Google Translate), and remove unused keys.
17
+ It analyses code statically for key usages, such as `I18n.t('some.key')`, in order to report keys that are missing or unused,
18
+ pre-fill missing keys (optionally from Google Translate), and remove unused keys.
19
19
  TEXT
20
- s.post_install_message = <<-TEXT
21
- # Install default configuration:
22
- cp $(i18n-tasks gem-path)/templates/config/i18n-tasks.yml config/
23
- # Add an RSpec for missing and unused keys:
24
- cp $(i18n-tasks gem-path)/templates/rspec/i18n_spec.rb spec/
20
+ s.post_install_message = <<~TEXT
21
+ # Install default configuration:
22
+ cp $(i18n-tasks gem-path)/templates/config/i18n-tasks.yml config/
23
+ # Add an RSpec for missing and unused keys:
24
+ cp $(i18n-tasks gem-path)/templates/rspec/i18n_spec.rb spec/
25
25
  TEXT
26
26
  s.homepage = 'https://github.com/glebm/i18n-tasks'
27
27
  s.metadata = { 'issue_tracker' => 'https://github.com/glebm/i18n-tasks' } if s.respond_to?(:metadata=)
28
- # rubocop:disable Gemspec/RequiredRubyVersion
29
- s.required_ruby_version = '~> 2.1' if s.respond_to?(:required_ruby_version=)
30
- # rubocop:enable Gemspec/RequiredRubyVersion
28
+ s.required_ruby_version = '~> 2.3' if s.respond_to?(:required_ruby_version=)
31
29
 
32
30
  s.files = `git ls-files`.split($/)
33
31
  s.files -= s.files.grep(%r{^(doc/|\.|spec/)}) + %w[CHANGES.md config/i18n-tasks.yml Gemfile]
@@ -10,6 +10,11 @@ module I18n::Tasks
10
10
  '--[no-]strict',
11
11
  t('i18n_tasks.cmd.args.desc.strict')
12
12
 
13
+ arg :keep_order,
14
+ '-k',
15
+ '--keep-order',
16
+ t('i18n_tasks.cmd.args.desc.keep_order')
17
+
13
18
  cmd :find,
14
19
  pos: '[pattern]',
15
20
  desc: t('i18n_tasks.cmd.desc.find'),
@@ -35,13 +40,14 @@ module I18n::Tasks
35
40
  cmd :remove_unused,
36
41
  pos: '[locale ...]',
37
42
  desc: t('i18n_tasks.cmd.desc.remove_unused'),
38
- args: %i[locales out_format strict confirm]
43
+ args: %i[locales out_format strict keep_order confirm]
39
44
 
40
45
  def remove_unused(opt = {})
41
46
  unused_keys = i18n.unused_keys(opt.slice(:locales, :strict))
42
47
  if unused_keys.present?
43
48
  terminal_report.unused_keys(unused_keys)
44
49
  confirm_remove_unused!(unused_keys, opt)
50
+ i18n.data.config = i18n.data.config.merge(sort: false) if opt[:'keep-order']
45
51
  removed = i18n.data.remove_by_key!(unused_keys)
46
52
  log_stderr t('i18n_tasks.remove_unused.removed', count: unused_keys.leaves.count)
47
53
  print_forest removed, opt
@@ -47,7 +47,7 @@ module I18n::Tasks
47
47
  end
48
48
 
49
49
  def move_base_locale_to_front!(locales, base_locale)
50
- if (pos = locales.index(base_locale)) && pos > 0
50
+ if (pos = locales.index(base_locale)) && pos.positive?
51
51
  locales[pos], locales[0] = locales[0], locales[pos]
52
52
  end
53
53
  locales
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'i18n/tasks/concurrent/cached_value'
4
+
5
+ module I18n::Tasks::Concurrent
6
+ # A thread-safe cache.
7
+ # @since 0.9.25
8
+ class Cache
9
+ def initialize
10
+ @mutex = Mutex.new
11
+ @map = {}
12
+ end
13
+
14
+ # @param [Object] key
15
+ # @return [Object] Cached or computed value.
16
+ def fetch(key, &block)
17
+ @mutex.synchronize do
18
+ @map[key] ||= CachedValue.new(&block)
19
+ end.get
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'i18n/tasks/concurrent/cached_value'
4
+
5
+ module I18n::Tasks::Concurrent
6
+ # A thread-safe memoized value.
7
+ # The given computation is guaranteed to be invoked at most once.
8
+ # @since 0.9.25
9
+ class CachedValue
10
+ NULL = Object.new
11
+
12
+ # @param [Proc] computation The computation that returns the value to cache.
13
+ def initialize(&computation)
14
+ @computation = computation
15
+ @mutex = Mutex.new
16
+ @result = NULL
17
+ end
18
+
19
+ # @return [Object] Result of the computation.
20
+ def get
21
+ return @result unless @result == NULL
22
+ @mutex.synchronize do
23
+ @result = @computation.call
24
+ end
25
+ end
26
+ end
27
+ end
@@ -34,41 +34,41 @@ module I18n::Tasks
34
34
  end
35
35
 
36
36
  def guide
37
- Rainbow('i18n-tasks IRB Quick Start guide').green.bright + "\n" + <<-TEXT
38
- #{Rainbow('Data as trees').yellow}
39
- tree(locale)
40
- used_tree(key_filter: nil, strict: nil)
41
- unused_tree(locale: base_locale, strict: nil)
42
- build_tree('es' => {'hello' => 'Hola'})
37
+ Rainbow('i18n-tasks IRB Quick Start guide').green.bright + "\n" + <<~TEXT
38
+ #{Rainbow('Data as trees').yellow}
39
+ tree(locale)
40
+ used_tree(key_filter: nil, strict: nil)
41
+ unused_tree(locale: base_locale, strict: nil)
42
+ build_tree('es' => {'hello' => 'Hola'})
43
43
 
44
- #{Rainbow('Traversal').yellow}
45
- tree = missing_diff_tree('es')
46
- tree.nodes { |node| }
47
- tree.nodes.to_a
48
- tree.leaves { |node| }
49
- tree.each { |root_node| }
50
- # also levels, depth_first, and breadth_first
44
+ #{Rainbow('Traversal').yellow}
45
+ tree = missing_diff_tree('es')
46
+ tree.nodes { |node| }
47
+ tree.nodes.to_a
48
+ tree.leaves { |node| }
49
+ tree.each { |root_node| }
50
+ # also levels, depth_first, and breadth_first
51
51
 
52
- #{Rainbow('Select nodes').yellow}
53
- tree.select_nodes { |node| } # new tree with only selected nodes
52
+ #{Rainbow('Select nodes').yellow}
53
+ tree.select_nodes { |node| } # new tree with only selected nodes
54
54
 
55
- #{Rainbow('Match by full key').yellow}
56
- tree.select_keys { |key, leaf| } # new tree with only selected keys
57
- tree.grep_keys(/hello/) # grep, using ===
58
- tree.keys { |key, leaf| } # enumerate over [full_key, leaf_node]
59
- # Pass {root: true} to include root node in full_key (usually locale)
55
+ #{Rainbow('Match by full key').yellow}
56
+ tree.select_keys { |key, leaf| } # new tree with only selected keys
57
+ tree.grep_keys(/hello/) # grep, using ===
58
+ tree.keys { |key, leaf| } # enumerate over [full_key, leaf_node]
59
+ # Pass {root: true} to include root node in full_key (usually locale)
60
60
 
61
- #{Rainbow('Nodes').yellow}
62
- node = node(key, locale)
63
- node.key # only the part after the last dot
64
- node.full_key # full key. Includes root key, pass {root: false} to override.
65
- # also: value, value_or_children_hash, data, walk_to_root, walk_from_root
66
- Tree::Node.new(key: 'en')
61
+ #{Rainbow('Nodes').yellow}
62
+ node = node(key, locale)
63
+ node.key # only the part after the last dot
64
+ node.full_key # full key. Includes root key, pass {root: false} to override.
65
+ # also: value, value_or_children_hash, data, walk_to_root, walk_from_root
66
+ Tree::Node.new(key: 'en')
67
67
 
68
- #{Rainbow('Keys').yellow}
69
- t(key, locale)
70
- key_value?(key, locale)
71
- depluralize_key(key, locale) # convert 'hat.one' to 'hat'
68
+ #{Rainbow('Keys').yellow}
69
+ t(key, locale)
70
+ key_value?(key, locale)
71
+ depluralize_key(key, locale) # convert 'hat.one' to 'hat'
72
72
  TEXT
73
73
  end
74
74
  end
@@ -45,8 +45,8 @@ module I18n
45
45
  ::File.read(path, encoding: 'UTF-8')
46
46
  end
47
47
 
48
- def write_tree(path, tree)
49
- hash = tree.to_hash(true)
48
+ def write_tree(path, tree, sort = true)
49
+ hash = tree.to_hash(sort)
50
50
  adapter = self.class.adapter_name_for_path(path)
51
51
  content = adapter_dump(hash, adapter)
52
52
  # Ignore unchanged data
@@ -21,7 +21,8 @@ module I18n::Tasks
21
21
  }.freeze
22
22
 
23
23
  def initialize(config = {})
24
- self.config = config.except(:base_locale, :locales)
24
+ self.config = config.except(:base_locale, :locales)
25
+ self.config[:sort] = !config[:keep_order]
25
26
  @base_locale = config[:base_locale]
26
27
  locales = config[:locales].presence
27
28
  @locales = LocaleList.normalize_locale_list(locales || available_locales, base_locale, true)
@@ -55,17 +56,17 @@ module I18n::Tasks
55
56
  # @param [::I18n::Tasks::Data::Siblings] tree
56
57
  def set(locale, tree)
57
58
  locale = locale.to_s
58
- @trees.delete(locale) if @trees
59
+ @trees&.delete(locale)
59
60
  paths_before = Set.new(get(locale)[locale].leaves.map { |node| node.data[:path] })
60
61
  paths_after = Set.new([])
61
62
  router.route locale, tree do |path, tree_slice|
62
63
  paths_after << path
63
- write_tree path, tree_slice
64
+ write_tree path, tree_slice, config[:sort]
64
65
  end
65
66
  (paths_before - paths_after).each do |path|
66
67
  FileUtils.remove_file(path) if File.exist?(path)
67
68
  end
68
- @trees.delete(locale) if @trees
69
+ @trees&.delete(locale)
69
70
  @available_locales = nil
70
71
  end
71
72
 
@@ -179,14 +180,14 @@ module I18n::Tasks
179
180
  data.each do |key, value|
180
181
  if key.nil?
181
182
  data.delete(key)
182
- log_warn <<-TEXT
183
- Skipping a nil key found in #{path.inspect}:
184
- key: #{suffix.join('.')}.`nil`
185
- value: #{value.inspect}
186
- Nil keys are not supported by i18n.
187
- The following unquoted YAML keys result in a nil key:
188
- #{%w[null Null NULL ~].join(', ')}
189
- See http://yaml.org/type/null.html
183
+ log_warn <<~TEXT
184
+ Skipping a nil key found in #{path.inspect}:
185
+ key: #{suffix.join('.')}.`nil`
186
+ value: #{value.inspect}
187
+ Nil keys are not supported by i18n.
188
+ The following unquoted YAML keys result in a nil key:
189
+ #{%w[null Null NULL ~].join(', ')}
190
+ See http://yaml.org/type/null.html
190
191
  TEXT
191
192
  elsif value.is_a?(Hash)
192
193
  filter_nil_keys! path, value, suffix + [key]
@@ -143,7 +143,7 @@ module I18n::Tasks::Data::Tree
143
143
  end
144
144
 
145
145
  def to_siblings
146
- parent && parent.children || Siblings.new(nodes: [self])
146
+ parent&.children || Siblings.new(nodes: [self])
147
147
  end
148
148
 
149
149
  def to_hash(sort = false)
@@ -104,7 +104,7 @@ module I18n::Tasks
104
104
  to_remove = []
105
105
  each do |node|
106
106
  if block.yield(node)
107
- node.children.select_nodes!(&block) if node.children
107
+ node.children&.select_nodes!(&block)
108
108
  else
109
109
  # removing during each is unsafe
110
110
  to_remove << node
@@ -4,7 +4,7 @@ module I18n::Tasks
4
4
  module LocalePathname
5
5
  class << self
6
6
  def replace_locale(path, from, to)
7
- path && path.gsub(path_locale_re(from), to)
7
+ path&.gsub(path_locale_re(from), to)
8
8
  end
9
9
 
10
10
  private
@@ -23,10 +23,8 @@ module I18n::Tasks::Logging
23
23
  end
24
24
 
25
25
  def log_stderr(*args)
26
+ # We don't want output from different threads to get intermixed.
26
27
  MUTEX.synchronize do
27
- # 1. We don't want output from different threads to get intermixed.
28
- # 2. StringIO is currently not thread-safe (blows up) on JRuby:
29
- # https://github.com/jruby/jruby/issues/4417
30
28
  $stderr.puts(*args)
31
29
  end
32
30
  end
@@ -32,7 +32,7 @@ module I18n::Tasks::Reports
32
32
  def used_title(keys_nodes, filter)
33
33
  used_n = keys_nodes.map { |_k, node| node.data[:occurrences].size }.reduce(:+).to_i
34
34
  "#{keys_nodes.size} key#{'s' if keys_nodes.size != 1}#{" matching '#{filter}'" if filter}"\
35
- "#{" (#{used_n} usage#{'s' if used_n != 1})" if used_n > 0}"
35
+ "#{" (#{used_n} usage#{'s' if used_n != 1})" if used_n.positive?}"
36
36
  end
37
37
 
38
38
  # Sort keys by their attributes in order
@@ -1,6 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'i18n/tasks/concurrent/cached_value'
3
4
  require 'i18n/tasks/scanners/files/file_finder'
5
+
4
6
  module I18n::Tasks::Scanners::Files
5
7
  # Finds the files in the specified search paths with support for exclusion / inclusion patterns.
6
8
  # Wraps a {FileFinder} and caches the results.
@@ -11,8 +13,7 @@ module I18n::Tasks::Scanners::Files
11
13
  # @param (see FileFinder#initialize)
12
14
  def initialize(**args)
13
15
  super
14
- @mutex = Mutex.new
15
- @cached_paths = nil
16
+ @cached_value = ::I18n::Tasks::Concurrent::CachedValue.new { uncached_find_files }
16
17
  end
17
18
 
18
19
  # Traverse the paths and yield the matching ones.
@@ -25,10 +26,13 @@ module I18n::Tasks::Scanners::Files
25
26
  super
26
27
  end
27
28
 
29
+ alias uncached_find_files find_files
30
+ private :uncached_find_files
31
+
28
32
  # @note This method is cached, it will only access the filesystem on the first invocation.
29
33
  # @return (see FileFinder#find_files)
30
34
  def find_files
31
- @cached_paths || @mutex.synchronize { @cached_paths ||= super }
35
+ @cached_value.get
32
36
  end
33
37
  end
34
38
  end
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'i18n/tasks/concurrent/cache'
3
4
  require 'i18n/tasks/scanners/files/caching_file_finder'
4
5
 
5
6
  module I18n::Tasks::Scanners::Files
@@ -10,8 +11,7 @@ module I18n::Tasks::Scanners::Files
10
11
  class CachingFileFinderProvider
11
12
  # @param exclude [Array<String>]
12
13
  def initialize(exclude: [])
13
- @cache = {}
14
- @mutex = Mutex.new
14
+ @cache = ::I18n::Tasks::Concurrent::Cache.new
15
15
  @defaults = { exclude: exclude }
16
16
  end
17
17
 
@@ -20,13 +20,11 @@ module I18n::Tasks::Scanners::Files
20
20
  # @param (see FileFinder#initialize)
21
21
  # @return [CachingFileFinder]
22
22
  def get(**file_finder_args)
23
- @cache[file_finder_args] || @mutex.synchronize do
24
- @cache[file_finder_args] ||= begin
25
- args = file_finder_args.dup
26
- args[:exclude] = @defaults[:exclude] + (args[:exclude] || [])
27
- args[:exclude].uniq!
28
- CachingFileFinder.new(**args)
29
- end
23
+ @cache.fetch(file_finder_args) do
24
+ args = file_finder_args.dup
25
+ args[:exclude] = @defaults[:exclude] + (args[:exclude] || [])
26
+ args[:exclude].uniq!
27
+ CachingFileFinder.new(**args)
30
28
  end
31
29
  end
32
30
  end
@@ -1,6 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'i18n/tasks/concurrent/cache'
3
4
  require 'i18n/tasks/scanners/files/file_reader'
5
+
4
6
  module I18n::Tasks::Scanners::Files
5
7
  # Reads the files in 'rb' mode and UTF-8 encoding.
6
8
  # Wraps a {FileReader} and caches the results.
@@ -10,8 +12,7 @@ module I18n::Tasks::Scanners::Files
10
12
  class CachingFileReader < FileReader
11
13
  def initialize
12
14
  super
13
- @mutex = Mutex.new
14
- @cache = {}
15
+ @cache = ::I18n::Tasks::Concurrent::Cache.new
15
16
  end
16
17
 
17
18
  # Return the contents of the file at the given path.
@@ -21,8 +22,7 @@ module I18n::Tasks::Scanners::Files
21
22
  # @return (see FileReader#read_file)
22
23
  # @note This method is cached, it will only access the filesystem on the first invocation.
23
24
  def read_file(path)
24
- absolute_path = File.expand_path(path)
25
- @cache[absolute_path] || @mutex.synchronize { @cache[absolute_path] ||= super }
25
+ @cache.fetch(File.expand_path(path)) { super }
26
26
  end
27
27
  end
28
28
  end
@@ -41,7 +41,7 @@ module I18n
41
41
  def prefix(normalized_path, calling_method: nil)
42
42
  file_key = normalized_path.gsub(%r{(\.[^/]+)*$}, '').tr(File::SEPARATOR, DOT)
43
43
  calling_method = calling_method.call if calling_method.respond_to?(:call)
44
- if calling_method && calling_method.present?
44
+ if calling_method&.present?
45
45
  # Relative keys in mailers have a `_mailer` infix, but relative keys in controllers do not have one:
46
46
  "#{file_key.sub(/_controller$/, '')}.#{calling_method}"
47
47
  else
@@ -48,7 +48,7 @@ module I18n::Tasks::Scanners
48
48
  message = send_node.children[1]
49
49
  valid_receivers = @message_receivers[message]
50
50
  # use `any?` because `include?` checks type equality, but the receiver is a Parser::AST::Node != AST::Node.
51
- @callback.call(send_node, @method_name) if valid_receivers && valid_receivers.any? { |r| r == receiver }
51
+ @callback.call(send_node, @method_name) if valid_receivers&.any? { |r| r == receiver }
52
52
  # always invoke handler_missing to get nested translations in children
53
53
  handler_missing send_node
54
54
  nil
@@ -68,7 +68,7 @@ module I18n::Tasks
68
68
  # dump recursively
69
69
  value.map { |v| dump_value v }
70
70
  when String
71
- replace_interpolations value
71
+ replace_interpolations value unless value.empty?
72
72
  end
73
73
  end
74
74
 
@@ -82,7 +82,11 @@ module I18n::Tasks
82
82
  # implode array
83
83
  untranslated.map { |from| parse_value(from, each_translated) }
84
84
  when String
85
- restore_interpolations untranslated, each_translated.next
85
+ if untranslated.empty?
86
+ untranslated
87
+ else
88
+ restore_interpolations untranslated, each_translated.next
89
+ end
86
90
  else
87
91
  untranslated
88
92
  end
@@ -115,11 +119,11 @@ module I18n::Tasks
115
119
  end
116
120
 
117
121
  def raise_interpolation_error(untranslated, translated, e)
118
- fail CommandError.new(e, <<-TEXT.strip)
119
- Error when restoring interpolations:
120
- original: "#{untranslated}"
121
- response: "#{translated}"
122
- error: #{e.message} (#{e.class.name})
122
+ fail CommandError.new(e, <<~TEXT.strip)
123
+ Error when restoring interpolations:
124
+ original: "#{untranslated}"
125
+ response: "#{translated}"
126
+ error: #{e.message} (#{e.class.name})
123
127
  TEXT
124
128
  end
125
129
 
@@ -2,6 +2,6 @@
2
2
 
3
3
  module I18n
4
4
  module Tasks
5
- VERSION = '0.9.24'
5
+ VERSION = '0.9.25'
6
6
  end
7
7
  end
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: 0.9.24
4
+ version: 0.9.25
5
5
  platform: ruby
6
6
  authors:
7
7
  - glebm
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-08-20 00:00:00.000000000 Z
11
+ date: 2018-09-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -294,6 +294,8 @@ files:
294
294
  - lib/i18n/tasks/command/options/locales.rb
295
295
  - lib/i18n/tasks/command_error.rb
296
296
  - lib/i18n/tasks/commands.rb
297
+ - lib/i18n/tasks/concurrent/cache.rb
298
+ - lib/i18n/tasks/concurrent/cached_value.rb
297
299
  - lib/i18n/tasks/configuration.rb
298
300
  - lib/i18n/tasks/console_context.rb
299
301
  - lib/i18n/tasks/data.rb
@@ -368,7 +370,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
368
370
  requirements:
369
371
  - - "~>"
370
372
  - !ruby/object:Gem::Version
371
- version: '2.1'
373
+ version: '2.3'
372
374
  required_rubygems_version: !ruby/object:Gem::Requirement
373
375
  requirements:
374
376
  - - ">="