i18n-tasks 0.9.28 → 0.9.33
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +35 -5
- data/config/locales/en.yml +6 -0
- data/config/locales/ru.yml +6 -0
- data/i18n-tasks.gemspec +9 -6
- data/lib/i18n/tasks.rb +0 -5
- data/lib/i18n/tasks/command/commander.rb +1 -1
- data/lib/i18n/tasks/command/commands/health.rb +4 -4
- data/lib/i18n/tasks/command/commands/interpolations.rb +1 -1
- data/lib/i18n/tasks/command/commands/missing.rb +1 -1
- data/lib/i18n/tasks/command/commands/usages.rb +10 -4
- data/lib/i18n/tasks/command/dsl.rb +2 -2
- data/lib/i18n/tasks/configuration.rb +1 -0
- data/lib/i18n/tasks/data/adapter/yaml_adapter.rb +1 -1
- data/lib/i18n/tasks/data/tree/node.rb +2 -3
- data/lib/i18n/tasks/data/tree/nodes.rb +1 -2
- data/lib/i18n/tasks/data/tree/siblings.rb +12 -4
- data/lib/i18n/tasks/data/tree/traversal.rb +6 -8
- data/lib/i18n/tasks/missing_keys.rb +43 -3
- data/lib/i18n/tasks/plural_keys.rb +4 -2
- data/lib/i18n/tasks/reports/terminal.rb +4 -5
- data/lib/i18n/tasks/scanners/pattern_scanner.rb +7 -5
- data/lib/i18n/tasks/scanners/ruby_ast_scanner.rb +2 -2
- data/lib/i18n/tasks/translation.rb +4 -1
- data/lib/i18n/tasks/translators/deepl_translator.rb +6 -1
- data/lib/i18n/tasks/translators/yandex_translator.rb +61 -0
- data/lib/i18n/tasks/used_keys.rb +2 -1
- data/lib/i18n/tasks/version.rb +1 -1
- data/templates/config/i18n-tasks.yml +1 -1
- data/templates/minitest/i18n_test.rb +8 -1
- data/templates/rspec/i18n_spec.rb +9 -2
- metadata +57 -35
- data/lib/i18n/tasks/rainbow_utils.rb +0 -15
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9ac2026537e1679b2e306eddee2c97ca569d6c498d1a9850e512702626ab9c19
|
4
|
+
data.tar.gz: 49a908c2b2a9144919076a5c3948fa537486739dc9b02968366c7ec0d3ccf62b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 639a786f1b1dfa5ee217e658975ac8b01b0966a4afdea49b69fdb4d1d4ff8cf9e48aab98eae0c6475a5c71fa4e8caccee88f1239205317550a03505a015fc932
|
7
|
+
data.tar.gz: d5a7ed2e9e1f4d2bf0474eb821e00713eff0fe486ef3cc92da12bc6e227bfecc987c5d2e70538e2c4436aba8958a763c8640d46c68d5ff2fdbf18e364d3d6cbc
|
data/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# i18n-tasks [![Build Status][badge-travis]][travis] [![Coverage Status][badge-coverage]][coverage] [![
|
1
|
+
# i18n-tasks [![Build Status][badge-travis]][travis] [![Coverage Status][badge-coverage]][coverage] [![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/glebm/i18n-tasks?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
2
2
|
|
3
3
|
i18n-tasks helps you find and manage missing and unused translations.
|
4
4
|
|
@@ -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.
|
25
|
+
gem 'i18n-tasks', '~> 0.9.33'
|
26
26
|
```
|
27
27
|
|
28
28
|
Copy the default [configuration file](#configuration):
|
@@ -45,7 +45,7 @@ $ cp $(i18n-tasks gem-path)/templates/minitest/i18n_test.rb test/
|
|
45
45
|
|
46
46
|
## Usage
|
47
47
|
|
48
|
-
Run `i18n-tasks` to get the list of all the tasks with short descriptions.
|
48
|
+
Run `bundle exec i18n-tasks` to get the list of all the tasks with short descriptions.
|
49
49
|
|
50
50
|
### Check health
|
51
51
|
|
@@ -104,6 +104,17 @@ $ i18n-tasks translate-missing --backend=deepl
|
|
104
104
|
$ i18n-tasks translate-missing --backend=deepl --from=en fr nl
|
105
105
|
```
|
106
106
|
|
107
|
+
### Yandex Translate missing keys
|
108
|
+
|
109
|
+
Translate missing values with Yandex Translate ([more below on the API key](#yandex-translation-config)).
|
110
|
+
|
111
|
+
```console
|
112
|
+
$ i18n-tasks translate-missing --backend=yandex
|
113
|
+
|
114
|
+
# accepts from and locales options:
|
115
|
+
$ i18n-tasks translate-missing --from=en es fr
|
116
|
+
```
|
117
|
+
|
107
118
|
### Find usages
|
108
119
|
|
109
120
|
See where the keys are used with `i18n-tasks find`:
|
@@ -324,6 +335,16 @@ A special syntax similar to file glob patterns is used throughout i18n-tasks to
|
|
324
335
|
| `:` | matches a single key |
|
325
336
|
| `{a, b.c}` | match any in set, can use `:` and `*`, match is captured |
|
326
337
|
|
338
|
+
Example of usage:
|
339
|
+
|
340
|
+
```sh
|
341
|
+
$ bundle exec i18n-tasks mv "{:}.contents.{*}_body" "\1.attributes.\2.body"
|
342
|
+
|
343
|
+
car.contents.name_body ⮕ car.attributes.name.body
|
344
|
+
car.contents.description_body ⮕ car.attributes.description.body
|
345
|
+
truck.contents.name_body ⮕ truck.attributes.name.body
|
346
|
+
truck.contents.description_body ⮕ truck.attributes.description.body
|
347
|
+
```
|
327
348
|
|
328
349
|
#### Custom adapters
|
329
350
|
|
@@ -387,6 +408,17 @@ translation:
|
|
387
408
|
deepl_api_key: <Deep Pro API key>
|
388
409
|
```
|
389
410
|
|
411
|
+
<a name="yandex-translation-config"></a>
|
412
|
+
### Yandex Translate
|
413
|
+
|
414
|
+
`i18n-tasks translate-missing` requires a Yandex API key, get it at [Yandex](https://tech.yandex.com/translate).
|
415
|
+
|
416
|
+
```yaml
|
417
|
+
# config/i18n-tasks.yml
|
418
|
+
translation:
|
419
|
+
yandex_api_key: <Yandex API key>
|
420
|
+
```
|
421
|
+
|
390
422
|
## Interactive console
|
391
423
|
|
392
424
|
`i18n-tasks irb` starts an IRB session in i18n-tasks context. Type `guide` for more information.
|
@@ -405,8 +437,6 @@ Custom tasks can be added easily, see the examples [on the wiki](https://github.
|
|
405
437
|
[badge-travis]: https://img.shields.io/travis/glebm/i18n-tasks.svg
|
406
438
|
[coverage]: https://codeclimate.com/github/glebm/i18n-tasks
|
407
439
|
[badge-coverage]: https://api.codeclimate.com/v1/badges/5d173e90ada8df07cedc/test_coverage
|
408
|
-
[gemnasium]: https://gemnasium.com/glebm/i18n-tasks
|
409
|
-
[badge-gemnasium]: https://gemnasium.com/glebm/i18n-tasks.svg
|
410
440
|
[config]: https://github.com/glebm/i18n-tasks/blob/master/templates/config/i18n-tasks.yml
|
411
441
|
[wiki]: https://github.com/glebm/i18n-tasks/wiki "i18n-tasks wiki"
|
412
442
|
[i18n-gem]: https://github.com/svenfuchs/i18n "svenfuchs/i18n on Github"
|
data/config/locales/en.yml
CHANGED
@@ -120,3 +120,9 @@ en:
|
|
120
120
|
none: Every translation is in use.
|
121
121
|
usages:
|
122
122
|
none: No key usages found.
|
123
|
+
yandex_translate:
|
124
|
+
errors:
|
125
|
+
no_api_key: >-
|
126
|
+
Set Yandex API key via YANDEX_API_KEY environment variable or translation.yandex_api_key
|
127
|
+
in config/i18n-tasks.yml. Get the key at https://tech.yandex.com/translate.
|
128
|
+
no_results: Yandex returned no results.
|
data/config/locales/ru.yml
CHANGED
@@ -122,3 +122,9 @@ ru:
|
|
122
122
|
none: Все переводы используются.
|
123
123
|
usages:
|
124
124
|
none: Не найдено использований.
|
125
|
+
yandex_translate:
|
126
|
+
errors:
|
127
|
+
no_api_key: |-
|
128
|
+
Установить ключ API Яндекса с помощью переменной среды YANDEX_API_KEY или translation.yandex_api_key
|
129
|
+
в config / i18n-tasks.yml. Получите ключ по адресу https://tech.yandex.com/translate/.
|
130
|
+
no_results: Яндекс не дал результатов.
|
data/i18n-tasks.gemspec
CHANGED
@@ -19,13 +19,13 @@ Gem::Specification.new do |s| # rubocop:disable Metrics/BlockLength
|
|
19
19
|
TEXT
|
20
20
|
s.post_install_message = <<~TEXT
|
21
21
|
# Install default configuration:
|
22
|
-
cp $(i18n-tasks gem-path)/templates/config/i18n-tasks.yml config/
|
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
|
-
cp $(i18n-tasks gem-path)/templates/rspec/i18n_spec.rb spec/
|
24
|
+
cp $(bundle exec 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
|
-
s.required_ruby_version = '
|
28
|
+
s.required_ruby_version = '>= 2.3', '< 4.0' if s.respond_to?(:required_ruby_version=)
|
29
29
|
|
30
30
|
s.files = `git ls-files`.split($/)
|
31
31
|
s.files -= s.files.grep(%r{^(doc/|\.|spec/)}) + %w[CHANGES.md config/i18n-tasks.yml Gemfile]
|
@@ -43,12 +43,15 @@ TEXT
|
|
43
43
|
s.add_dependency 'rainbow', '>= 2.2.2', '< 4.0'
|
44
44
|
s.add_dependency 'terminal-table', '>= 1.5.1'
|
45
45
|
s.add_development_dependency 'axlsx', '~> 2.0'
|
46
|
-
s.add_development_dependency 'bundler', '~>
|
47
|
-
s.add_development_dependency 'deepl-rb', '>= 2.1.0'
|
48
|
-
s.add_development_dependency 'easy_translate', '>= 0.5.1'
|
46
|
+
s.add_development_dependency 'bundler', '~> 2.0', '>= 2.0.1'
|
49
47
|
s.add_development_dependency 'rake'
|
50
48
|
s.add_development_dependency 'rspec', '~> 3.3'
|
51
49
|
s.add_development_dependency 'rubocop', '~> 0.53.0'
|
52
50
|
s.add_development_dependency 'simplecov'
|
53
51
|
s.add_development_dependency 'yard'
|
52
|
+
|
53
|
+
# Translation backends
|
54
|
+
s.add_development_dependency 'deepl-rb', '>= 2.1.0'
|
55
|
+
s.add_development_dependency 'easy_translate', '>= 0.5.1' # Google Translate
|
56
|
+
s.add_development_dependency 'yandex-translator', '>= 0.3.3'
|
54
57
|
end
|
data/lib/i18n/tasks.rb
CHANGED
@@ -68,8 +68,3 @@ require 'i18n'
|
|
68
68
|
Dir[File.join(I18n::Tasks.gem_path, 'config', 'locales', '*.yml')].each do |locale_file|
|
69
69
|
I18n.config.load_path << locale_file
|
70
70
|
end
|
71
|
-
|
72
|
-
# Load pluralization data
|
73
|
-
require 'rails-i18n'
|
74
|
-
I18n.enforce_available_locales = false
|
75
|
-
RailsI18n::Railtie.add('rails/pluralization/*.rb')
|
@@ -17,10 +17,10 @@ module I18n::Tasks
|
|
17
17
|
fail CommandError, t('i18n_tasks.health.no_keys_detected') if stats[:key_count].zero?
|
18
18
|
terminal_report.forest_stats forest, stats
|
19
19
|
[
|
20
|
-
missing(opt),
|
21
|
-
unused(opt),
|
22
|
-
check_consistent_interpolations(opt),
|
23
|
-
check_normalized(opt)
|
20
|
+
missing(**opt),
|
21
|
+
unused(**opt),
|
22
|
+
check_consistent_interpolations(**opt),
|
23
|
+
check_normalized(**opt)
|
24
24
|
].detect { |result| result == :exit_1 }
|
25
25
|
end
|
26
26
|
end
|
@@ -12,7 +12,7 @@ module I18n::Tasks
|
|
12
12
|
args: %i[locales out_format]
|
13
13
|
|
14
14
|
def check_consistent_interpolations(opt = {})
|
15
|
-
forest = i18n.inconsistent_interpolations(opt.slice(:locales, :base_locale))
|
15
|
+
forest = i18n.inconsistent_interpolations(**opt.slice(:locales, :base_locale))
|
16
16
|
print_forest forest, opt, :inconsistent_interpolations
|
17
17
|
:exit_1 unless forest.empty?
|
18
18
|
end
|
@@ -28,7 +28,7 @@ module I18n::Tasks
|
|
28
28
|
args: %i[locales out_format missing_types]
|
29
29
|
|
30
30
|
def missing(opt = {})
|
31
|
-
forest = i18n.missing_keys(opt.slice(:locales, :base_locale, :types))
|
31
|
+
forest = i18n.missing_keys(**opt.slice(:locales, :base_locale, :types))
|
32
32
|
print_forest forest, opt, :missing_keys
|
33
33
|
:exit_1 unless forest.empty?
|
34
34
|
end
|
@@ -32,7 +32,7 @@ module I18n::Tasks
|
|
32
32
|
args: %i[locales out_format strict]
|
33
33
|
|
34
34
|
def unused(opt = {})
|
35
|
-
forest = i18n.unused_keys(opt.slice(:locales, :strict))
|
35
|
+
forest = i18n.unused_keys(**opt.slice(:locales, :strict))
|
36
36
|
print_forest forest, opt, :unused_keys
|
37
37
|
:exit_1 unless forest.empty?
|
38
38
|
end
|
@@ -40,10 +40,16 @@ module I18n::Tasks
|
|
40
40
|
cmd :remove_unused,
|
41
41
|
pos: '[locale ...]',
|
42
42
|
desc: t('i18n_tasks.cmd.desc.remove_unused'),
|
43
|
-
args: %i[locales out_format strict keep_order confirm]
|
43
|
+
args: %i[locales out_format strict keep_order confirm pattern]
|
44
|
+
|
45
|
+
def remove_unused(opt = {}) # rubocop:disable Metrics/AbcSize
|
46
|
+
unused_keys = i18n.unused_keys(**opt.slice(:locales, :strict))
|
47
|
+
|
48
|
+
if opt[:pattern]
|
49
|
+
pattern_re = i18n.compile_key_pattern(opt[:pattern])
|
50
|
+
unused_keys = unused_keys.select_keys { |full_key, _node| full_key =~ pattern_re }
|
51
|
+
end
|
44
52
|
|
45
|
-
def remove_unused(opt = {})
|
46
|
-
unused_keys = i18n.unused_keys(opt.slice(:locales, :strict))
|
47
53
|
if unused_keys.present?
|
48
54
|
terminal_report.unused_keys(unused_keys)
|
49
55
|
confirm_remove_unused!(unused_keys, opt)
|
@@ -59,6 +59,7 @@ module I18n::Tasks::Configuration # rubocop:disable Metrics/ModuleLength
|
|
59
59
|
conf = (config[:translation] || {}).with_indifferent_access
|
60
60
|
conf[:google_translate_api_key] = ENV['GOOGLE_TRANSLATE_API_KEY'] if ENV.key?('GOOGLE_TRANSLATE_API_KEY')
|
61
61
|
conf[:deepl_api_key] = ENV['DEEPL_AUTH_KEY'] if ENV.key?('DEEPL_AUTH_KEY')
|
62
|
+
conf[:yandex_api_key] = ENV['YANDEX_API_KEY'] if ENV.key?('YANDEX_API_KEY')
|
62
63
|
conf
|
63
64
|
end
|
64
65
|
end
|
@@ -9,7 +9,7 @@ module I18n::Tasks
|
|
9
9
|
# @return [Hash] locale tree
|
10
10
|
def parse(str, options)
|
11
11
|
if YAML.method(:load).arity.abs == 2
|
12
|
-
YAML.load(str, options || {})
|
12
|
+
YAML.load(str, **(options || {}))
|
13
13
|
else
|
14
14
|
# older jruby and rbx 2.2.7 do not accept options
|
15
15
|
YAML.load(str)
|
@@ -2,7 +2,6 @@
|
|
2
2
|
|
3
3
|
require 'i18n/tasks/data/tree/traversal'
|
4
4
|
require 'i18n/tasks/data/tree/siblings'
|
5
|
-
require 'i18n/tasks/rainbow_utils'
|
6
5
|
module I18n::Tasks::Data::Tree
|
7
6
|
class Node # rubocop:disable Metrics/ClassLength
|
8
7
|
include Enumerable
|
@@ -28,7 +27,7 @@ module I18n::Tasks::Data::Tree
|
|
28
27
|
end
|
29
28
|
|
30
29
|
def derive(new_attr = {})
|
31
|
-
self.class.new(attributes.merge(new_attr))
|
30
|
+
self.class.new(**attributes.merge(new_attr))
|
32
31
|
end
|
33
32
|
|
34
33
|
def children=(children)
|
@@ -164,7 +163,7 @@ module I18n::Tasks::Data::Tree
|
|
164
163
|
|
165
164
|
def inspect(level = 0)
|
166
165
|
label = if key.nil?
|
167
|
-
|
166
|
+
Rainbow('∅').faint
|
168
167
|
else
|
169
168
|
[Rainbow(key).color(1 + level % 15),
|
170
169
|
(": #{format_value_for_inspect(value)}" if leaf?),
|
@@ -1,7 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'i18n/tasks/data/tree/traversal'
|
4
|
-
require 'i18n/tasks/rainbow_utils'
|
5
4
|
module I18n::Tasks::Data::Tree
|
6
5
|
# A list of nodes
|
7
6
|
class Nodes
|
@@ -48,7 +47,7 @@ module I18n::Tasks::Data::Tree
|
|
48
47
|
if present?
|
49
48
|
map(&:inspect) * "\n"
|
50
49
|
else
|
51
|
-
|
50
|
+
Rainbow('{∅}').faint
|
52
51
|
end
|
53
52
|
end
|
54
53
|
|
@@ -11,6 +11,7 @@ module I18n::Tasks::Data::Tree
|
|
11
11
|
# siblings' keys are unique
|
12
12
|
class Siblings < Nodes # rubocop:disable Metrics/ClassLength
|
13
13
|
include ::I18n::Tasks::SplitKey
|
14
|
+
include ::I18n::Tasks::PluralKeys
|
14
15
|
|
15
16
|
attr_reader :parent, :key_to_node
|
16
17
|
|
@@ -100,12 +101,12 @@ module I18n::Tasks::Data::Tree
|
|
100
101
|
key: key_part,
|
101
102
|
parent: parent,
|
102
103
|
children: [],
|
103
|
-
warn_about_add_children_to_leaf: @
|
104
|
+
warn_about_add_children_to_leaf: @warn_about_add_children_to_leaf
|
104
105
|
)
|
105
106
|
append! child
|
106
107
|
end
|
107
108
|
unless child.children
|
108
|
-
|
109
|
+
conditionally_warn_add_children_to_leaf(child, [])
|
109
110
|
child.children = []
|
110
111
|
end
|
111
112
|
child.children.set rest, node
|
@@ -187,7 +188,7 @@ module I18n::Tasks::Data::Tree
|
|
187
188
|
if our.children
|
188
189
|
our.children.merge!(node.children)
|
189
190
|
else
|
190
|
-
|
191
|
+
conditionally_warn_add_children_to_leaf(our, node.children)
|
191
192
|
our.children = node.children
|
192
193
|
end
|
193
194
|
elsif on_leaves_merge
|
@@ -228,6 +229,13 @@ module I18n::Tasks::Data::Tree
|
|
228
229
|
end
|
229
230
|
end
|
230
231
|
|
232
|
+
def conditionally_warn_add_children_to_leaf(node, children)
|
233
|
+
return unless @warn_about_add_children_to_leaf
|
234
|
+
return if plural_forms?(children)
|
235
|
+
|
236
|
+
warn_add_children_to_leaf(node)
|
237
|
+
end
|
238
|
+
|
231
239
|
def warn_add_children_to_leaf(node)
|
232
240
|
::I18n::Tasks::Logging.log_warn "'#{node.full_key}' was a leaf, now has children (value <- scope conflict)"
|
233
241
|
end
|
@@ -265,7 +273,7 @@ module I18n::Tasks::Data::Tree
|
|
265
273
|
build_forest(opts) do |forest|
|
266
274
|
key_attrs.each do |(full_key, attr)|
|
267
275
|
fail "Invalid key #{full_key.inspect}" if full_key.end_with?('.')
|
268
|
-
node = ::I18n::Tasks::Data::Tree::Node.new(attr.merge(key: split_key(full_key).last))
|
276
|
+
node = ::I18n::Tasks::Data::Tree::Node.new(**attr.merge(key: split_key(full_key).last))
|
269
277
|
yield(full_key, node) if block
|
270
278
|
forest[full_key] = node
|
271
279
|
end
|
@@ -60,14 +60,12 @@ module I18n::Tasks
|
|
60
60
|
self
|
61
61
|
end
|
62
62
|
|
63
|
-
def key_names(
|
64
|
-
|
65
|
-
keys(opts).map { |key, _node| key }
|
63
|
+
def key_names(root: false)
|
64
|
+
keys(root: root).map { |key, _node| key }
|
66
65
|
end
|
67
66
|
|
68
|
-
def key_values(
|
69
|
-
|
70
|
-
keys(opts).map { |key, node| [key, node.value] }
|
67
|
+
def key_values(root: false)
|
68
|
+
keys(root: root).map { |key, node| [key, node.value] }
|
71
69
|
end
|
72
70
|
|
73
71
|
def root_key_values(sort = false)
|
@@ -146,12 +144,12 @@ module I18n::Tasks
|
|
146
144
|
# @return [Siblings]
|
147
145
|
def intersect_keys(other_tree, key_opts = {}, &block)
|
148
146
|
if block
|
149
|
-
select_keys(key_opts) do |key, node|
|
147
|
+
select_keys(**key_opts.slice(:root)) do |key, node|
|
150
148
|
other_node = other_tree[key]
|
151
149
|
other_node && yield(key, node, other_node)
|
152
150
|
end
|
153
151
|
else
|
154
|
-
select_keys(key_opts) { |key, _node| other_tree[key] }
|
152
|
+
select_keys(**key_opts.slice(:root)) { |key, _node| other_tree[key] }
|
155
153
|
end
|
156
154
|
end
|
157
155
|
|
@@ -58,8 +58,8 @@ module I18n::Tasks
|
|
58
58
|
|
59
59
|
def missing_plural_forest(locales, _base = base_locale)
|
60
60
|
locales.each_with_object(empty_forest) do |locale, forest|
|
61
|
-
|
62
|
-
|
61
|
+
required_keys = required_plural_keys_for_locale(locale)
|
62
|
+
next if required_keys.empty?
|
63
63
|
tree = empty_forest
|
64
64
|
plural_nodes data[locale] do |node|
|
65
65
|
children = node.children
|
@@ -76,6 +76,19 @@ module I18n::Tasks
|
|
76
76
|
end
|
77
77
|
end
|
78
78
|
|
79
|
+
def required_plural_keys_for_locale(locale)
|
80
|
+
@plural_keys_for_locale ||= {}
|
81
|
+
return @plural_keys_for_locale[locale] if @plural_keys_for_locale.key?(locale)
|
82
|
+
|
83
|
+
@plural_keys_for_locale[locale] = plural_keys_for_locale(locale)
|
84
|
+
end
|
85
|
+
|
86
|
+
# Loads rails-i18n pluralization config for the given locale.
|
87
|
+
def load_rails_i18n_pluralization!(locale)
|
88
|
+
path = File.join(Gem::Specification.find_by_name('rails-i18n').gem_dir, 'rails', 'pluralization', "#{locale}.rb")
|
89
|
+
eval(File.read(path), binding, path) # rubocop:disable Security/Eval
|
90
|
+
end
|
91
|
+
|
79
92
|
# keys present in compared_to, but not in locale
|
80
93
|
def missing_diff_tree(locale, compared_to = base_locale)
|
81
94
|
data[compared_to].select_keys do |key, _node|
|
@@ -106,7 +119,7 @@ module I18n::Tasks
|
|
106
119
|
end
|
107
120
|
|
108
121
|
def locale_key_missing?(locale, key)
|
109
|
-
!key_value?(key, locale) && !external_key?(key) && !ignore_key?(key, :missing)
|
122
|
+
!key_value?(key, locale) && !external_key?(key, locale) && !ignore_key?(key, :missing)
|
110
123
|
end
|
111
124
|
|
112
125
|
# @param [::I18n::Tasks::Data::Tree::Siblings] forest
|
@@ -137,5 +150,32 @@ module I18n::Tasks
|
|
137
150
|
end
|
138
151
|
forest
|
139
152
|
end
|
153
|
+
|
154
|
+
private
|
155
|
+
|
156
|
+
def plural_keys_for_locale(locale)
|
157
|
+
configuration = load_rails_i18n_pluralization!(locale)
|
158
|
+
if configuration[locale.to_sym].nil?
|
159
|
+
alternate_locale = alternate_locale_from(locale)
|
160
|
+
return Set.new if configuration[alternate_locale.to_sym].nil?
|
161
|
+
|
162
|
+
return set_from_rails_i18n_pluralization(configuration, alternate_locale)
|
163
|
+
end
|
164
|
+
set_from_rails_i18n_pluralization(configuration, locale)
|
165
|
+
rescue SystemCallError, IOError
|
166
|
+
Set.new
|
167
|
+
end
|
168
|
+
|
169
|
+
def alternate_locale_from(locale)
|
170
|
+
re = /(\w{2})-*(\w{2,3})*/
|
171
|
+
match = locale.match(re)
|
172
|
+
language_code = match[1]
|
173
|
+
country_code = match[2]
|
174
|
+
"#{language_code}-#{country_code.upcase}"
|
175
|
+
end
|
176
|
+
|
177
|
+
def set_from_rails_i18n_pluralization(configuration, locale)
|
178
|
+
Set.new(configuration[locale.to_sym][:i18n][:plural][:keys])
|
179
|
+
end
|
140
180
|
end
|
141
181
|
end
|
@@ -2,8 +2,10 @@
|
|
2
2
|
|
3
3
|
require 'set'
|
4
4
|
module I18n::Tasks::PluralKeys
|
5
|
-
|
6
|
-
|
5
|
+
# Ref: http://cldr.unicode.org/index/cldr-spec/plural-rules
|
6
|
+
CLDR_CATEGORY_KEYS = %w[zero one two few many other].freeze
|
7
|
+
PLURAL_KEY_SUFFIXES = Set.new CLDR_CATEGORY_KEYS
|
8
|
+
PLURAL_KEY_RE = /\.(?:#{CLDR_CATEGORY_KEYS * '|'})$/
|
7
9
|
|
8
10
|
def collapse_plural_nodes!(tree)
|
9
11
|
tree.leaves.map(&:parent).compact.uniq.each do |node|
|
@@ -1,7 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'i18n/tasks/reports/base'
|
4
|
-
require 'i18n/tasks/rainbow_utils'
|
5
4
|
require 'terminal-table'
|
6
5
|
module I18n
|
7
6
|
module Tasks
|
@@ -76,11 +75,11 @@ module I18n
|
|
76
75
|
|
77
76
|
def forest_stats(forest, stats = task.forest_stats(forest))
|
78
77
|
text = if stats[:locale_count] == 1
|
79
|
-
I18n.t('i18n_tasks.data_stats.text_single_locale', stats)
|
78
|
+
I18n.t('i18n_tasks.data_stats.text_single_locale', **stats)
|
80
79
|
else
|
81
|
-
I18n.t('i18n_tasks.data_stats.text', stats)
|
80
|
+
I18n.t('i18n_tasks.data_stats.text', **stats)
|
82
81
|
end
|
83
|
-
title = Rainbow(I18n.t('i18n_tasks.data_stats.title', stats.slice(:locales))).bright
|
82
|
+
title = Rainbow(I18n.t('i18n_tasks.data_stats.title', **stats.slice(:locales))).bright
|
84
83
|
print_info "#{Rainbow(title).cyan} #{Rainbow(text).cyan}"
|
85
84
|
end
|
86
85
|
|
@@ -170,7 +169,7 @@ module I18n
|
|
170
169
|
end
|
171
170
|
|
172
171
|
def print_title(title)
|
173
|
-
log_stderr "#{Rainbow(title.strip).bright} #{
|
172
|
+
log_stderr "#{Rainbow(title.strip).bright} #{Rainbow('|').faint} " \
|
174
173
|
"#{"i18n-tasks v#{I18n::Tasks::VERSION}"}"
|
175
174
|
end
|
176
175
|
|
@@ -12,13 +12,15 @@ module I18n::Tasks::Scanners
|
|
12
12
|
include OccurrenceFromPosition
|
13
13
|
include RubyKeyLiterals
|
14
14
|
|
15
|
-
TRANSLATE_CALL_RE = /(?<=^|[^\w'\-.]|[^\w'\-]I18n\.|I18n\.)t(
|
15
|
+
TRANSLATE_CALL_RE = /(?<=^|[^\w'\-.]|[^\w'\-]I18n\.|I18n\.)t(?:!|ranslate!?)?/
|
16
16
|
IGNORE_LINES = {
|
17
|
-
'opal' => /^\s*#(?!\si18n-tasks-use)/,
|
18
|
-
'haml' => /^\s*-\s*#(?!\si18n-tasks-use)/,
|
19
|
-
'slim' => %r{^\s*(?:-#|/)(?!\si18n-tasks-use)},
|
20
17
|
'coffee' => /^\s*#(?!\si18n-tasks-use)/,
|
21
|
-
'erb' => /^\s*<%\s*#(?!\si18n-tasks-use)
|
18
|
+
'erb' => /^\s*<%\s*#(?!\si18n-tasks-use)/,
|
19
|
+
'es6' => %r{^\s*//(?!\si18n-tasks-use)},
|
20
|
+
'haml' => /^\s*-\s*#(?!\si18n-tasks-use)/,
|
21
|
+
'js' => %r{^\s*//(?!\si18n-tasks-use)},
|
22
|
+
'opal' => /^\s*#(?!\si18n-tasks-use)/,
|
23
|
+
'slim' => %r{^\s*(?:-#|/)(?!\si18n-tasks-use)}
|
22
24
|
}.freeze
|
23
25
|
|
24
26
|
def initialize(**args)
|
@@ -15,10 +15,10 @@ module I18n::Tasks::Scanners
|
|
15
15
|
include AST::Sexp
|
16
16
|
|
17
17
|
MAGIC_COMMENT_PREFIX = /\A.\s*i18n-tasks-use\s+/
|
18
|
-
RECEIVER_MESSAGES = [nil, AST::Node.new(:const, [nil, :I18n])].product(%i[t translate])
|
18
|
+
RECEIVER_MESSAGES = [nil, AST::Node.new(:const, [nil, :I18n])].product(%i[t t! translate translate!])
|
19
19
|
|
20
20
|
def initialize(**args)
|
21
|
-
super(args)
|
21
|
+
super(**args)
|
22
22
|
@parser = ::Parser::CurrentRuby.new
|
23
23
|
@magic_comment_parser = ::Parser::CurrentRuby.new
|
24
24
|
@call_finder = RubyAstCallFinder.new(
|
@@ -2,12 +2,13 @@
|
|
2
2
|
|
3
3
|
require 'i18n/tasks/translators/deepl_translator.rb'
|
4
4
|
require 'i18n/tasks/translators/google_translator.rb'
|
5
|
+
require 'i18n/tasks/translators/yandex_translator.rb'
|
5
6
|
|
6
7
|
module I18n::Tasks
|
7
8
|
module Translation
|
8
9
|
# @param [I18n::Tasks::Tree::Siblings] forest to translate to the locales of its root nodes
|
9
10
|
# @param [String] from locale
|
10
|
-
# @param [:deepl, :google] backend
|
11
|
+
# @param [:deepl, :google, :yandex] backend
|
11
12
|
# @return [I18n::Tasks::Tree::Siblings] translated forest
|
12
13
|
def translate_forest(forest, from:, backend: :google)
|
13
14
|
case backend
|
@@ -15,6 +16,8 @@ module I18n::Tasks
|
|
15
16
|
Translators::DeeplTranslator.new(self).translate_forest(forest, from)
|
16
17
|
when :google
|
17
18
|
Translators::GoogleTranslator.new(self).translate_forest(forest, from)
|
19
|
+
when :yandex
|
20
|
+
Translators::YandexTranslator.new(self).translate_forest(forest, from)
|
18
21
|
else
|
19
22
|
fail CommandError, "invalid backend: #{backend}"
|
20
23
|
end
|
@@ -17,7 +17,12 @@ module I18n::Tasks::Translators
|
|
17
17
|
protected
|
18
18
|
|
19
19
|
def translate_values(list, from:, to:, **options)
|
20
|
-
DeepL.translate(list, to_deepl_compatible_locale(from), to_deepl_compatible_locale(to), options)
|
20
|
+
result = DeepL.translate(list, to_deepl_compatible_locale(from), to_deepl_compatible_locale(to), options)
|
21
|
+
if result.is_a?(DeepL::Resources::Text)
|
22
|
+
[result.text]
|
23
|
+
else
|
24
|
+
result.map(&:text)
|
25
|
+
end
|
21
26
|
end
|
22
27
|
|
23
28
|
def options_for_translate_values(**options)
|
@@ -0,0 +1,61 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'i18n/tasks/translators/base_translator'
|
4
|
+
|
5
|
+
module I18n::Tasks::Translators
|
6
|
+
class YandexTranslator < BaseTranslator
|
7
|
+
def initialize(*)
|
8
|
+
begin
|
9
|
+
require 'yandex-translator'
|
10
|
+
rescue LoadError
|
11
|
+
raise ::I18n::Tasks::CommandError, "Add gem 'yandex-translator' to your Gemfile to use this command"
|
12
|
+
end
|
13
|
+
super
|
14
|
+
end
|
15
|
+
|
16
|
+
protected
|
17
|
+
|
18
|
+
def translate_values(list, **options)
|
19
|
+
list.map { |item| translator.translate(item, options) }
|
20
|
+
end
|
21
|
+
|
22
|
+
def options_for_translate_values(from:, to:, **options)
|
23
|
+
options.merge(
|
24
|
+
from: to_yandex_compatible_locale(from),
|
25
|
+
to: to_yandex_compatible_locale(to)
|
26
|
+
)
|
27
|
+
end
|
28
|
+
|
29
|
+
def options_for_html
|
30
|
+
{ format: 'html' }
|
31
|
+
end
|
32
|
+
|
33
|
+
def options_for_plain
|
34
|
+
{ format: 'plain' }
|
35
|
+
end
|
36
|
+
|
37
|
+
def no_results_error_message
|
38
|
+
I18n.t('i18n_tasks.yandex_translate.errors.no_results')
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
# Convert 'es-ES' to 'es'
|
44
|
+
def to_yandex_compatible_locale(locale)
|
45
|
+
return locale unless locale.include?('-')
|
46
|
+
locale.split('-', 2).first
|
47
|
+
end
|
48
|
+
|
49
|
+
def translator
|
50
|
+
@translator ||= Yandex::Translator.new(api_key)
|
51
|
+
end
|
52
|
+
|
53
|
+
def api_key
|
54
|
+
@api_key ||= begin
|
55
|
+
key = @i18n_tasks.translation_config[:yandex_api_key]
|
56
|
+
fail ::I18n::Tasks::CommandError, I18n.t('i18n_tasks.yandex_translate.errors.no_api_key') if key.blank?
|
57
|
+
key
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
data/lib/i18n/tasks/used_keys.rb
CHANGED
@@ -25,7 +25,8 @@ module I18n::Tasks
|
|
25
25
|
}.freeze
|
26
26
|
|
27
27
|
ALWAYS_EXCLUDE = %w[*.jpg *.png *.gif *.svg *.ico *.eot *.otf *.ttf *.woff *.woff2 *.pdf *.css *.sass *.scss *.less
|
28
|
-
*.yml *.json *.zip *.tar.gz *.swf *.flv
|
28
|
+
*.yml *.json *.zip *.tar.gz *.swf *.flv *.mp3 *.wav *.flac *.webm *.mp4 *.ogg *.opus
|
29
|
+
*.webp].freeze
|
29
30
|
|
30
31
|
# Find all keys in the source and return a forest with the keys in absolute form and their occurrences.
|
31
32
|
#
|
data/lib/i18n/tasks/version.rb
CHANGED
@@ -32,7 +32,7 @@ data:
|
|
32
32
|
# This data is not considered unused and is never written to.
|
33
33
|
external:
|
34
34
|
## Example (replace %#= with %=):
|
35
|
-
# - "<%#= %x[bundle
|
35
|
+
# - "<%#= %x[bundle info vagrant --path].chomp %>/templates/locales/%{locale}.yml"
|
36
36
|
|
37
37
|
## Specify the router (see Readme for details). Valid values: conservative_router, pattern_router, or a custom class.
|
38
38
|
# router: conservative_router
|
@@ -23,7 +23,14 @@ class I18nTest < ActiveSupport::TestCase
|
|
23
23
|
non_normalized = @i18n.non_normalized_paths
|
24
24
|
error_message = "The following files need to be normalized:\n" \
|
25
25
|
"#{non_normalized.map { |path| " #{path}" }.join("\n")}\n" \
|
26
|
-
|
26
|
+
"Please run `i18n-tasks normalize' to fix"
|
27
27
|
assert_empty non_normalized, error_message
|
28
28
|
end
|
29
|
+
|
30
|
+
def test_no_inconsistent_interpolations
|
31
|
+
inconsistent_interpolations = @i18n.inconsistent_interpolations
|
32
|
+
error_message = "#{inconsistent_interpolations.leaves.count} i18n keys have inconsistent interpolations.\n" \
|
33
|
+
"Please run `i18n-tasks check-consistent-interpolations' to show them"
|
34
|
+
assert_empty inconsistent_interpolations, error_message
|
35
|
+
end
|
29
36
|
end
|
@@ -2,10 +2,11 @@
|
|
2
2
|
|
3
3
|
require 'i18n/tasks'
|
4
4
|
|
5
|
-
RSpec.describe
|
5
|
+
RSpec.describe I18n do
|
6
6
|
let(:i18n) { I18n::Tasks::BaseTask.new }
|
7
7
|
let(:missing_keys) { i18n.missing_keys }
|
8
8
|
let(:unused_keys) { i18n.unused_keys }
|
9
|
+
let(:inconsistent_interpolations) { i18n.inconsistent_interpolations }
|
9
10
|
|
10
11
|
it 'does not have missing keys' do
|
11
12
|
expect(missing_keys).to be_empty,
|
@@ -21,7 +22,13 @@ RSpec.describe 'I18n' do
|
|
21
22
|
non_normalized = i18n.non_normalized_paths
|
22
23
|
error_message = "The following files need to be normalized:\n" \
|
23
24
|
"#{non_normalized.map { |path| " #{path}" }.join("\n")}\n" \
|
24
|
-
|
25
|
+
"Please run `i18n-tasks normalize' to fix"
|
25
26
|
expect(non_normalized).to be_empty, error_message
|
26
27
|
end
|
28
|
+
|
29
|
+
it 'does not have inconsistent interpolations' do
|
30
|
+
error_message = "#{inconsistent_interpolations.leaves.count} i18n keys have inconsistent interpolations.\n" \
|
31
|
+
"Run `i18n-tasks check-consistent-interpolations' to show them"
|
32
|
+
expect(inconsistent_interpolations).to be_empty, error_message
|
33
|
+
end
|
27
34
|
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.
|
4
|
+
version: 0.9.33
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- glebm
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2020-12-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -162,42 +162,20 @@ dependencies:
|
|
162
162
|
requirements:
|
163
163
|
- - "~>"
|
164
164
|
- !ruby/object:Gem::Version
|
165
|
-
version: '
|
166
|
-
type: :development
|
167
|
-
prerelease: false
|
168
|
-
version_requirements: !ruby/object:Gem::Requirement
|
169
|
-
requirements:
|
170
|
-
- - "~>"
|
171
|
-
- !ruby/object:Gem::Version
|
172
|
-
version: '1.3'
|
173
|
-
- !ruby/object:Gem::Dependency
|
174
|
-
name: deepl-rb
|
175
|
-
requirement: !ruby/object:Gem::Requirement
|
176
|
-
requirements:
|
165
|
+
version: '2.0'
|
177
166
|
- - ">="
|
178
167
|
- !ruby/object:Gem::Version
|
179
|
-
version: 2.1
|
168
|
+
version: 2.0.1
|
180
169
|
type: :development
|
181
170
|
prerelease: false
|
182
171
|
version_requirements: !ruby/object:Gem::Requirement
|
183
172
|
requirements:
|
184
|
-
- - "
|
185
|
-
- !ruby/object:Gem::Version
|
186
|
-
version: 2.1.0
|
187
|
-
- !ruby/object:Gem::Dependency
|
188
|
-
name: easy_translate
|
189
|
-
requirement: !ruby/object:Gem::Requirement
|
190
|
-
requirements:
|
191
|
-
- - ">="
|
173
|
+
- - "~>"
|
192
174
|
- !ruby/object:Gem::Version
|
193
|
-
version: 0
|
194
|
-
type: :development
|
195
|
-
prerelease: false
|
196
|
-
version_requirements: !ruby/object:Gem::Requirement
|
197
|
-
requirements:
|
175
|
+
version: '2.0'
|
198
176
|
- - ">="
|
199
177
|
- !ruby/object:Gem::Version
|
200
|
-
version: 0.
|
178
|
+
version: 2.0.1
|
201
179
|
- !ruby/object:Gem::Dependency
|
202
180
|
name: rake
|
203
181
|
requirement: !ruby/object:Gem::Requirement
|
@@ -268,6 +246,48 @@ dependencies:
|
|
268
246
|
- - ">="
|
269
247
|
- !ruby/object:Gem::Version
|
270
248
|
version: '0'
|
249
|
+
- !ruby/object:Gem::Dependency
|
250
|
+
name: deepl-rb
|
251
|
+
requirement: !ruby/object:Gem::Requirement
|
252
|
+
requirements:
|
253
|
+
- - ">="
|
254
|
+
- !ruby/object:Gem::Version
|
255
|
+
version: 2.1.0
|
256
|
+
type: :development
|
257
|
+
prerelease: false
|
258
|
+
version_requirements: !ruby/object:Gem::Requirement
|
259
|
+
requirements:
|
260
|
+
- - ">="
|
261
|
+
- !ruby/object:Gem::Version
|
262
|
+
version: 2.1.0
|
263
|
+
- !ruby/object:Gem::Dependency
|
264
|
+
name: easy_translate
|
265
|
+
requirement: !ruby/object:Gem::Requirement
|
266
|
+
requirements:
|
267
|
+
- - ">="
|
268
|
+
- !ruby/object:Gem::Version
|
269
|
+
version: 0.5.1
|
270
|
+
type: :development
|
271
|
+
prerelease: false
|
272
|
+
version_requirements: !ruby/object:Gem::Requirement
|
273
|
+
requirements:
|
274
|
+
- - ">="
|
275
|
+
- !ruby/object:Gem::Version
|
276
|
+
version: 0.5.1
|
277
|
+
- !ruby/object:Gem::Dependency
|
278
|
+
name: yandex-translator
|
279
|
+
requirement: !ruby/object:Gem::Requirement
|
280
|
+
requirements:
|
281
|
+
- - ">="
|
282
|
+
- !ruby/object:Gem::Version
|
283
|
+
version: 0.3.3
|
284
|
+
type: :development
|
285
|
+
prerelease: false
|
286
|
+
version_requirements: !ruby/object:Gem::Requirement
|
287
|
+
requirements:
|
288
|
+
- - ">="
|
289
|
+
- !ruby/object:Gem::Version
|
290
|
+
version: 0.3.3
|
271
291
|
description: |
|
272
292
|
i18n-tasks helps you find and manage missing and unused translations.
|
273
293
|
|
@@ -334,7 +354,6 @@ files:
|
|
334
354
|
- lib/i18n/tasks/logging.rb
|
335
355
|
- lib/i18n/tasks/missing_keys.rb
|
336
356
|
- lib/i18n/tasks/plural_keys.rb
|
337
|
-
- lib/i18n/tasks/rainbow_utils.rb
|
338
357
|
- lib/i18n/tasks/references.rb
|
339
358
|
- lib/i18n/tasks/reports/base.rb
|
340
359
|
- lib/i18n/tasks/reports/terminal.rb
|
@@ -363,6 +382,7 @@ files:
|
|
363
382
|
- lib/i18n/tasks/translators/base_translator.rb
|
364
383
|
- lib/i18n/tasks/translators/deepl_translator.rb
|
365
384
|
- lib/i18n/tasks/translators/google_translator.rb
|
385
|
+
- lib/i18n/tasks/translators/yandex_translator.rb
|
366
386
|
- lib/i18n/tasks/unused_keys.rb
|
367
387
|
- lib/i18n/tasks/used_keys.rb
|
368
388
|
- lib/i18n/tasks/version.rb
|
@@ -376,25 +396,27 @@ metadata:
|
|
376
396
|
issue_tracker: https://github.com/glebm/i18n-tasks
|
377
397
|
post_install_message: |
|
378
398
|
# Install default configuration:
|
379
|
-
cp $(i18n-tasks gem-path)/templates/config/i18n-tasks.yml config/
|
399
|
+
cp $(bundle exec i18n-tasks gem-path)/templates/config/i18n-tasks.yml config/
|
380
400
|
# Add an RSpec for missing and unused keys:
|
381
|
-
cp $(i18n-tasks gem-path)/templates/rspec/i18n_spec.rb spec/
|
401
|
+
cp $(bundle exec i18n-tasks gem-path)/templates/rspec/i18n_spec.rb spec/
|
382
402
|
rdoc_options: []
|
383
403
|
require_paths:
|
384
404
|
- lib
|
385
405
|
required_ruby_version: !ruby/object:Gem::Requirement
|
386
406
|
requirements:
|
387
|
-
- - "
|
407
|
+
- - ">="
|
388
408
|
- !ruby/object:Gem::Version
|
389
409
|
version: '2.3'
|
410
|
+
- - "<"
|
411
|
+
- !ruby/object:Gem::Version
|
412
|
+
version: '4.0'
|
390
413
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
391
414
|
requirements:
|
392
415
|
- - ">="
|
393
416
|
- !ruby/object:Gem::Version
|
394
417
|
version: '0'
|
395
418
|
requirements: []
|
396
|
-
|
397
|
-
rubygems_version: 2.7.7
|
419
|
+
rubygems_version: 3.1.2
|
398
420
|
signing_key:
|
399
421
|
specification_version: 4
|
400
422
|
summary: Manage localization and translation with the awesome power of static analysis
|
@@ -1,15 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module I18n
|
4
|
-
module Tasks
|
5
|
-
module RainbowUtils
|
6
|
-
# TODO: This method can be removed after below PR is released.
|
7
|
-
# https://github.com/sickill/rainbow/pull/53
|
8
|
-
def self.faint_color(str)
|
9
|
-
presenter = Rainbow(str)
|
10
|
-
return presenter unless Rainbow.enabled
|
11
|
-
Rainbow::Presenter.new(Rainbow::StringUtils.wrap_with_sgr(presenter, [2]))
|
12
|
-
end
|
13
|
-
end
|
14
|
-
end
|
15
|
-
end
|