i18n-tasks 0.9.27 → 0.9.32
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 +4 -4
- data/README.md +35 -5
- data/config/locales/en.yml +6 -0
- data/config/locales/ru.yml +10 -0
- data/i18n-tasks.gemspec +10 -6
- data/lib/i18n/tasks.rb +1 -0
- 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/file_formats.rb +2 -0
- 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 +69 -8
- data/lib/i18n/tasks/plural_keys.rb +23 -2
- data/lib/i18n/tasks/reports/terminal.rb +6 -10
- 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 +71 -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: bcf38124b967eb00a21ca02f9e894a22941d95e590024971144131cd61856f70
|
4
|
+
data.tar.gz: 9ffb6f291f36f0015ad22ad26981d7b605dad695f723517bb928287cd091ecaa
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8c27ffd3ab866c82237e99b1bea2afd444b2e9e82d0ef4b48031d46da697c079273ba6a88c4beb20a3795044096a614523aab289a46f86afc6f7e66e8719ed1e
|
7
|
+
data.tar.gz: fcb4deae9fdcadef52e7e4a6b85871fcbd33b437bc4a7a11f2c4ad42d60f2b835596bbaa86fe6ad4d30382195fd884c0728aa6fdf35fdb1b78cedb2f617bac2a
|
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] [](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.32'
|
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
@@ -69,6 +69,8 @@ ru:
|
|
69
69
|
invalid_format: 'Неизвестный формат %{invalid}. Форматы: %{valid}.'
|
70
70
|
invalid_locale: Неверный язык %{invalid}
|
71
71
|
invalid_missing_type:
|
72
|
+
few: 'Неизвестные типы: %{invalid}. Типы: %{valid}.'
|
73
|
+
many: 'Неизвестные типы: %{invalid}. Типы: %{valid}.'
|
72
74
|
one: 'Неизвестный тип %{invalid}. Типы: %{valid}.'
|
73
75
|
other: 'Неизвестные типы: %{invalid}. Типы: %{valid}.'
|
74
76
|
pass_forest: Передайте дерево
|
@@ -108,6 +110,8 @@ ru:
|
|
108
110
|
none: Всё переведено.
|
109
111
|
remove_unused:
|
110
112
|
confirm:
|
113
|
+
few: Переводы (%{count}) будут удалены из %{locales}.
|
114
|
+
many: Переводы (%{count}) будут удалены из %{locales}.
|
111
115
|
one: "%{count} перевод будут удалён из %{locales}."
|
112
116
|
other: Переводы (%{count}) будут удалены из %{locales}.
|
113
117
|
noop: Нет неиспользуемых ключей
|
@@ -118,3 +122,9 @@ ru:
|
|
118
122
|
none: Все переводы используются.
|
119
123
|
usages:
|
120
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]
|
@@ -39,15 +39,19 @@ TEXT
|
|
39
39
|
s.add_dependency 'highline', '>= 2.0.0'
|
40
40
|
s.add_dependency 'i18n'
|
41
41
|
s.add_dependency 'parser', '>= 2.2.3.0'
|
42
|
+
s.add_dependency 'rails-i18n'
|
42
43
|
s.add_dependency 'rainbow', '>= 2.2.2', '< 4.0'
|
43
44
|
s.add_dependency 'terminal-table', '>= 1.5.1'
|
44
45
|
s.add_development_dependency 'axlsx', '~> 2.0'
|
45
|
-
s.add_development_dependency 'bundler', '~>
|
46
|
-
s.add_development_dependency 'deepl-rb', '>= 2.1.0'
|
47
|
-
s.add_development_dependency 'easy_translate', '>= 0.5.1'
|
46
|
+
s.add_development_dependency 'bundler', '~> 2.0', '>= 2.0.1'
|
48
47
|
s.add_development_dependency 'rake'
|
49
48
|
s.add_development_dependency 'rspec', '~> 3.3'
|
50
49
|
s.add_development_dependency 'rubocop', '~> 0.53.0'
|
51
50
|
s.add_development_dependency 'simplecov'
|
52
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'
|
53
57
|
end
|
data/lib/i18n/tasks.rb
CHANGED
@@ -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
|
|
@@ -2,21 +2,22 @@
|
|
2
2
|
|
3
3
|
require 'set'
|
4
4
|
module I18n::Tasks
|
5
|
-
module MissingKeys
|
6
|
-
MISSING_TYPES =
|
7
|
-
used
|
8
|
-
diff
|
9
|
-
|
5
|
+
module MissingKeys # rubocop:disable Metrics/ModuleLength
|
6
|
+
MISSING_TYPES = %w[
|
7
|
+
used
|
8
|
+
diff
|
9
|
+
plural
|
10
|
+
].freeze
|
10
11
|
|
11
12
|
def self.missing_keys_types
|
12
|
-
@missing_keys_types ||= MISSING_TYPES
|
13
|
+
@missing_keys_types ||= MISSING_TYPES
|
13
14
|
end
|
14
15
|
|
15
16
|
def missing_keys_types
|
16
17
|
MissingKeys.missing_keys_types
|
17
18
|
end
|
18
19
|
|
19
|
-
# @param types [:used, :diff] all if `nil`.
|
20
|
+
# @param types [:used, :diff, :plural] all if `nil`.
|
20
21
|
# @return [Siblings]
|
21
22
|
def missing_keys(locales: nil, types: nil, base_locale: nil)
|
22
23
|
locales ||= self.locales
|
@@ -55,6 +56,39 @@ module I18n::Tasks
|
|
55
56
|
end
|
56
57
|
end
|
57
58
|
|
59
|
+
def missing_plural_forest(locales, _base = base_locale)
|
60
|
+
locales.each_with_object(empty_forest) do |locale, forest|
|
61
|
+
required_keys = required_plural_keys_for_locale(locale)
|
62
|
+
next if required_keys.empty?
|
63
|
+
tree = empty_forest
|
64
|
+
plural_nodes data[locale] do |node|
|
65
|
+
children = node.children
|
66
|
+
present_keys = Set.new(children.map { |c| c.key.to_sym })
|
67
|
+
next if present_keys.superset?(required_keys)
|
68
|
+
tree[node.full_key] = node.derive(
|
69
|
+
value: children.to_hash,
|
70
|
+
children: nil,
|
71
|
+
data: node.data.merge(missing_keys: (required_keys - present_keys).to_a)
|
72
|
+
)
|
73
|
+
end
|
74
|
+
tree.set_root_key!(locale, type: :missing_plural)
|
75
|
+
forest.merge!(tree)
|
76
|
+
end
|
77
|
+
end
|
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
|
+
|
58
92
|
# keys present in compared_to, but not in locale
|
59
93
|
def missing_diff_tree(locale, compared_to = base_locale)
|
60
94
|
data[compared_to].select_keys do |key, _node|
|
@@ -85,7 +119,7 @@ module I18n::Tasks
|
|
85
119
|
end
|
86
120
|
|
87
121
|
def locale_key_missing?(locale, key)
|
88
|
-
!key_value?(key, locale) && !external_key?(key) && !ignore_key?(key, :missing)
|
122
|
+
!key_value?(key, locale) && !external_key?(key, locale) && !ignore_key?(key, :missing)
|
89
123
|
end
|
90
124
|
|
91
125
|
# @param [::I18n::Tasks::Data::Tree::Siblings] forest
|
@@ -116,5 +150,32 @@ module I18n::Tasks
|
|
116
150
|
end
|
117
151
|
forest
|
118
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
|
119
180
|
end
|
120
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|
|
@@ -31,10 +33,29 @@ module I18n::Tasks::PluralKeys
|
|
31
33
|
end
|
32
34
|
end
|
33
35
|
|
36
|
+
# @param [::I18n::Tasks::Data::Tree::Traversal] tree
|
37
|
+
# @yieldparam node [::I18n::Tasks::Data::Tree::Node] plural node
|
38
|
+
def plural_nodes(tree)
|
39
|
+
return to_enum(:plural_nodes, tree) unless block_given?
|
40
|
+
visited = Set.new
|
41
|
+
tree.leaves do |node|
|
42
|
+
parent = node.parent
|
43
|
+
next if !parent || visited.include?(parent)
|
44
|
+
yield parent if plural_forms?(parent.children)
|
45
|
+
visited.add(parent)
|
46
|
+
end
|
47
|
+
self
|
48
|
+
end
|
49
|
+
|
34
50
|
def plural_forms?(s)
|
51
|
+
return false if non_plural_other?(s)
|
35
52
|
s.present? && s.all? { |node| node.leaf? && plural_suffix?(node.key) }
|
36
53
|
end
|
37
54
|
|
55
|
+
def non_plural_other?(s)
|
56
|
+
s.size == 1 && s.first.leaf? && (!s.first.value.is_a?(String) || !s.first.value.include?('%{count}'))
|
57
|
+
end
|
58
|
+
|
38
59
|
def plural_suffix?(key)
|
39
60
|
PLURAL_KEY_SUFFIXES.include?(key)
|
40
61
|
end
|
@@ -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
|
@@ -34,11 +33,6 @@ module I18n
|
|
34
33
|
end
|
35
34
|
end
|
36
35
|
|
37
|
-
def icon(type)
|
38
|
-
glyph = missing_type_info(type)[:glyph]
|
39
|
-
{ missing_used: Rainbow(glyph).red, missing_diff: Rainbow(glyph).yellow }[type]
|
40
|
-
end
|
41
|
-
|
42
36
|
def used_keys(used_tree = task.used_tree)
|
43
37
|
# For the used tree we may have usage nodes that are not leaves as references.
|
44
38
|
keys_nodes = used_tree.nodes.select { |node| node.data[:occurrences].present? }.map do |node|
|
@@ -81,11 +75,11 @@ module I18n
|
|
81
75
|
|
82
76
|
def forest_stats(forest, stats = task.forest_stats(forest))
|
83
77
|
text = if stats[:locale_count] == 1
|
84
|
-
I18n.t('i18n_tasks.data_stats.text_single_locale', stats)
|
78
|
+
I18n.t('i18n_tasks.data_stats.text_single_locale', **stats)
|
85
79
|
else
|
86
|
-
I18n.t('i18n_tasks.data_stats.text', stats)
|
80
|
+
I18n.t('i18n_tasks.data_stats.text', **stats)
|
87
81
|
end
|
88
|
-
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
|
89
83
|
print_info "#{Rainbow(title).cyan} #{Rainbow(text).cyan}"
|
90
84
|
end
|
91
85
|
|
@@ -114,6 +108,8 @@ module I18n
|
|
114
108
|
def missing_key_info(leaf)
|
115
109
|
if leaf[:type] == :missing_used
|
116
110
|
first_occurrence leaf
|
111
|
+
elsif leaf[:type] == :missing_plural
|
112
|
+
leaf[:data][:missing_keys].join(', ')
|
117
113
|
else
|
118
114
|
"#{Rainbow(leaf[:data][:missing_diff_locale]).cyan} "\
|
119
115
|
"#{format_value(leaf[:value].is_a?(String) ? leaf[:value].strip : leaf[:value])}"
|
@@ -173,7 +169,7 @@ module I18n
|
|
173
169
|
end
|
174
170
|
|
175
171
|
def print_title(title)
|
176
|
-
log_stderr "#{Rainbow(title.strip).bright} #{
|
172
|
+
log_stderr "#{Rainbow(title.strip).bright} #{Rainbow('|').faint} " \
|
177
173
|
"#{"i18n-tasks v#{I18n::Tasks::VERSION}"}"
|
178
174
|
end
|
179
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).map(&:text)
|
20
|
+
result = DeepL.translate(list, to_deepl_compatible_locale(from), to_deepl_compatible_locale(to), options).map(&:text)
|
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.32
|
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-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -94,6 +94,20 @@ dependencies:
|
|
94
94
|
- - ">="
|
95
95
|
- !ruby/object:Gem::Version
|
96
96
|
version: 2.2.3.0
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: rails-i18n
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :runtime
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
97
111
|
- !ruby/object:Gem::Dependency
|
98
112
|
name: rainbow
|
99
113
|
requirement: !ruby/object:Gem::Requirement
|
@@ -148,42 +162,20 @@ dependencies:
|
|
148
162
|
requirements:
|
149
163
|
- - "~>"
|
150
164
|
- !ruby/object:Gem::Version
|
151
|
-
version: '
|
152
|
-
type: :development
|
153
|
-
prerelease: false
|
154
|
-
version_requirements: !ruby/object:Gem::Requirement
|
155
|
-
requirements:
|
156
|
-
- - "~>"
|
157
|
-
- !ruby/object:Gem::Version
|
158
|
-
version: '1.3'
|
159
|
-
- !ruby/object:Gem::Dependency
|
160
|
-
name: deepl-rb
|
161
|
-
requirement: !ruby/object:Gem::Requirement
|
162
|
-
requirements:
|
165
|
+
version: '2.0'
|
163
166
|
- - ">="
|
164
167
|
- !ruby/object:Gem::Version
|
165
|
-
version: 2.1
|
168
|
+
version: 2.0.1
|
166
169
|
type: :development
|
167
170
|
prerelease: false
|
168
171
|
version_requirements: !ruby/object:Gem::Requirement
|
169
172
|
requirements:
|
170
|
-
- - "
|
171
|
-
- !ruby/object:Gem::Version
|
172
|
-
version: 2.1.0
|
173
|
-
- !ruby/object:Gem::Dependency
|
174
|
-
name: easy_translate
|
175
|
-
requirement: !ruby/object:Gem::Requirement
|
176
|
-
requirements:
|
177
|
-
- - ">="
|
173
|
+
- - "~>"
|
178
174
|
- !ruby/object:Gem::Version
|
179
|
-
version: 0
|
180
|
-
type: :development
|
181
|
-
prerelease: false
|
182
|
-
version_requirements: !ruby/object:Gem::Requirement
|
183
|
-
requirements:
|
175
|
+
version: '2.0'
|
184
176
|
- - ">="
|
185
177
|
- !ruby/object:Gem::Version
|
186
|
-
version: 0.
|
178
|
+
version: 2.0.1
|
187
179
|
- !ruby/object:Gem::Dependency
|
188
180
|
name: rake
|
189
181
|
requirement: !ruby/object:Gem::Requirement
|
@@ -254,6 +246,48 @@ dependencies:
|
|
254
246
|
- - ">="
|
255
247
|
- !ruby/object:Gem::Version
|
256
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
|
257
291
|
description: |
|
258
292
|
i18n-tasks helps you find and manage missing and unused translations.
|
259
293
|
|
@@ -320,7 +354,6 @@ files:
|
|
320
354
|
- lib/i18n/tasks/logging.rb
|
321
355
|
- lib/i18n/tasks/missing_keys.rb
|
322
356
|
- lib/i18n/tasks/plural_keys.rb
|
323
|
-
- lib/i18n/tasks/rainbow_utils.rb
|
324
357
|
- lib/i18n/tasks/references.rb
|
325
358
|
- lib/i18n/tasks/reports/base.rb
|
326
359
|
- lib/i18n/tasks/reports/terminal.rb
|
@@ -349,6 +382,7 @@ files:
|
|
349
382
|
- lib/i18n/tasks/translators/base_translator.rb
|
350
383
|
- lib/i18n/tasks/translators/deepl_translator.rb
|
351
384
|
- lib/i18n/tasks/translators/google_translator.rb
|
385
|
+
- lib/i18n/tasks/translators/yandex_translator.rb
|
352
386
|
- lib/i18n/tasks/unused_keys.rb
|
353
387
|
- lib/i18n/tasks/used_keys.rb
|
354
388
|
- lib/i18n/tasks/version.rb
|
@@ -362,25 +396,27 @@ metadata:
|
|
362
396
|
issue_tracker: https://github.com/glebm/i18n-tasks
|
363
397
|
post_install_message: |
|
364
398
|
# Install default configuration:
|
365
|
-
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/
|
366
400
|
# Add an RSpec for missing and unused keys:
|
367
|
-
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/
|
368
402
|
rdoc_options: []
|
369
403
|
require_paths:
|
370
404
|
- lib
|
371
405
|
required_ruby_version: !ruby/object:Gem::Requirement
|
372
406
|
requirements:
|
373
|
-
- - "
|
407
|
+
- - ">="
|
374
408
|
- !ruby/object:Gem::Version
|
375
409
|
version: '2.3'
|
410
|
+
- - "<"
|
411
|
+
- !ruby/object:Gem::Version
|
412
|
+
version: '4.0'
|
376
413
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
377
414
|
requirements:
|
378
415
|
- - ">="
|
379
416
|
- !ruby/object:Gem::Version
|
380
417
|
version: '0'
|
381
418
|
requirements: []
|
382
|
-
|
383
|
-
rubygems_version: 2.7.7
|
419
|
+
rubygems_version: 3.1.2
|
384
420
|
signing_key:
|
385
421
|
specification_version: 4
|
386
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
|