i18n-tasks 0.9.24 → 0.9.25

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 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
  - - ">="