i18n-tasks 0.9.25 → 0.9.26
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 +1 -1
- data/config/locales/en.yml +3 -0
- data/config/locales/ru.yml +7 -3
- data/lib/i18n/tasks/base_task.rb +2 -0
- data/lib/i18n/tasks/command/commands/eq_base.rb +3 -1
- data/lib/i18n/tasks/command/commands/health.rb +6 -1
- data/lib/i18n/tasks/command/commands/interpolations.rb +22 -0
- data/lib/i18n/tasks/commands.rb +2 -0
- data/lib/i18n/tasks/concurrent/cached_value.rb +34 -2
- data/lib/i18n/tasks/interpolations.rb +29 -0
- data/lib/i18n/tasks/reports/base.rb +4 -0
- data/lib/i18n/tasks/reports/terminal.rb +9 -0
- data/lib/i18n/tasks/translators/deepl_translator.rb +1 -1
- data/lib/i18n/tasks/translators/google_translator.rb +1 -1
- data/lib/i18n/tasks/version.rb +1 -1
- data/templates/config/i18n-tasks.yml +4 -0
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c5c06b9d6d4187eda97fce4acb55c31c8c01534814e8770ed64d3f0f052dbb26
|
4
|
+
data.tar.gz: ec0198e22e8c9b55fd87f386467cb94400a400263405efc42fc5d3696c610e21
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 89296743377a8207fa571d82c23c1ec36e71b8209f2f949cf8d541ea0ef4db87b1f69e5c28796ee6ebeeddad1c352a2d1b2f14bf685593e828c715dc74a24b18
|
7
|
+
data.tar.gz: b66aaea9115ee5015e9696d562666dbcfeae6f770f4e8558e59257557e9d138249639bdf6a9b9e73ee1acadb88b1ae386f0d1dde1e7b655ff816f15e0a229fc9
|
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.
|
25
|
+
gem 'i18n-tasks', '~> 0.9.26'
|
26
26
|
```
|
27
27
|
|
28
28
|
Copy the default [configuration file](#configuration):
|
data/config/locales/en.yml
CHANGED
@@ -33,6 +33,7 @@ en:
|
|
33
33
|
%{value_or_default_or_human_key}
|
34
34
|
desc:
|
35
35
|
add_missing: add missing keys to locale data
|
36
|
+
check_consistent_interpolations: verify that all translations use correct interpolation variables
|
36
37
|
check_normalized: verify that all translation data is normalized
|
37
38
|
config: display i18n-tasks configuration
|
38
39
|
data: show locale data
|
@@ -102,6 +103,8 @@ en:
|
|
102
103
|
Google Translate returned no results. Make sure billing information is set at https://code.google.com/apis/console.
|
103
104
|
health:
|
104
105
|
no_keys_detected: No keys detected. Check data.read in config/i18n-tasks.yml.
|
106
|
+
inconsistent_interpolations:
|
107
|
+
none: No inconsistent interpolations found.
|
105
108
|
missing:
|
106
109
|
details_title: Value in other locales or source
|
107
110
|
none: No translations are missing.
|
data/config/locales/ru.yml
CHANGED
@@ -9,7 +9,7 @@ ru:
|
|
9
9
|
desc:
|
10
10
|
all_locales: Не ожидать, что маски ключа начинаются с локали. Применять маски ко всем локалям.
|
11
11
|
confirm: Подтвердить автоматом
|
12
|
-
data_format: 'Формат данных: %{valid_text}.
|
12
|
+
data_format: 'Формат данных: %{valid_text}.'
|
13
13
|
keep_order: Keep the order of the keys
|
14
14
|
key_pattern: Маска ключа (например, common.*)
|
15
15
|
key_pattern_to_rename: Полный ключ (шаблон) для переименования. Необходимый параметр.
|
@@ -21,7 +21,7 @@ ru:
|
|
21
21
|
missing_types: 'Типы недостающих переводов: %{valid}. По умолчанию: все'
|
22
22
|
new_key_name: Новое имя, интерполирует оригинальное название как %{key}. Необходимый параметр.
|
23
23
|
nostdin: Не читать дерево из стандартного ввода
|
24
|
-
out_format: 'Формат вывода: %{valid_text}.
|
24
|
+
out_format: 'Формат вывода: %{valid_text}.'
|
25
25
|
pattern_router: 'Использовать pattern_router: ключи распределятся по файлам согласно data.write'
|
26
26
|
strict: Не угадывать динамические использования ключей, например `t("category.#{category.key}")`
|
27
27
|
translation_backend: Движок перевода (google или deepl)
|
@@ -30,6 +30,8 @@ ru:
|
|
30
30
|
%{value_or_default_or_human_key}
|
31
31
|
desc:
|
32
32
|
add_missing: добавить недостающие ключи к переводам
|
33
|
+
check_consistent_interpolations: убедитесь, что во всех переводах используются правильные
|
34
|
+
интерполяционные переменные
|
33
35
|
check_normalized: проверить, что все файлы переводов нормализованы
|
34
36
|
config: показать конфигурацию
|
35
37
|
data: показать данные переводов
|
@@ -99,12 +101,14 @@ ru:
|
|
99
101
|
в https://code.google.com/apis/console.
|
100
102
|
health:
|
101
103
|
no_keys_detected: Ключи не обнаружены. Проверьте data.read в config/i18n-tasks.yml.
|
104
|
+
inconsistent_interpolations:
|
105
|
+
none: Не найдено несогласованных интерполяций.
|
102
106
|
missing:
|
103
107
|
details_title: На других языках или в коде
|
104
108
|
none: Всё переведено.
|
105
109
|
remove_unused:
|
106
110
|
confirm:
|
107
|
-
one:
|
111
|
+
one: "%{count} перевод будут удалён из %{locales}."
|
108
112
|
other: Переводы (%{count}) будут удалены из %{locales}.
|
109
113
|
noop: Нет неиспользуемых ключей
|
110
114
|
removed: Удалены ключи (%{count})
|
data/lib/i18n/tasks/base_task.rb
CHANGED
@@ -10,6 +10,7 @@ require 'i18n/tasks/html_keys'
|
|
10
10
|
require 'i18n/tasks/used_keys'
|
11
11
|
require 'i18n/tasks/ignore_keys'
|
12
12
|
require 'i18n/tasks/missing_keys'
|
13
|
+
require 'i18n/tasks/interpolations'
|
13
14
|
require 'i18n/tasks/unused_keys'
|
14
15
|
require 'i18n/tasks/translation'
|
15
16
|
require 'i18n/tasks/locale_pathname'
|
@@ -30,6 +31,7 @@ module I18n
|
|
30
31
|
include UsedKeys
|
31
32
|
include IgnoreKeys
|
32
33
|
include MissingKeys
|
34
|
+
include Interpolations
|
33
35
|
include UnusedKeys
|
34
36
|
include Translation
|
35
37
|
include Logging
|
@@ -12,7 +12,9 @@ module I18n::Tasks
|
|
12
12
|
args: %i[locales out_format]
|
13
13
|
|
14
14
|
def eq_base(opt = {})
|
15
|
-
|
15
|
+
forest = i18n.eq_base_keys(opt)
|
16
|
+
print_forest forest, opt, :eq_base_keys
|
17
|
+
:exit_1 unless forest.empty?
|
16
18
|
end
|
17
19
|
end
|
18
20
|
end
|
@@ -16,7 +16,12 @@ module I18n::Tasks
|
|
16
16
|
stats = i18n.forest_stats(forest)
|
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)
|
24
|
+
].detect { |result| result == :exit_1 }
|
20
25
|
end
|
21
26
|
end
|
22
27
|
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module I18n::Tasks
|
4
|
+
module Command
|
5
|
+
module Commands
|
6
|
+
module Interpolations
|
7
|
+
include Command::Collection
|
8
|
+
|
9
|
+
cmd :check_consistent_interpolations,
|
10
|
+
pos: '[locale ...]',
|
11
|
+
desc: t('i18n_tasks.cmd.desc.check_consistent_interpolations'),
|
12
|
+
args: %i[locales out_format]
|
13
|
+
|
14
|
+
def check_consistent_interpolations(opt = {})
|
15
|
+
forest = i18n.inconsistent_interpolations(opt.slice(:locales, :base_locale))
|
16
|
+
print_forest forest, opt, :inconsistent_interpolations
|
17
|
+
:exit_1 unless forest.empty?
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
data/lib/i18n/tasks/commands.rb
CHANGED
@@ -5,6 +5,7 @@ require 'i18n/tasks/command/collection'
|
|
5
5
|
require 'i18n/tasks/command/commands/health'
|
6
6
|
require 'i18n/tasks/command/commands/missing'
|
7
7
|
require 'i18n/tasks/command/commands/usages'
|
8
|
+
require 'i18n/tasks/command/commands/interpolations'
|
8
9
|
require 'i18n/tasks/command/commands/eq_base'
|
9
10
|
require 'i18n/tasks/command/commands/data'
|
10
11
|
require 'i18n/tasks/command/commands/tree'
|
@@ -17,6 +18,7 @@ module I18n::Tasks
|
|
17
18
|
include Command::Commands::Health
|
18
19
|
include Command::Commands::Missing
|
19
20
|
include Command::Commands::Usages
|
21
|
+
include Command::Commands::Interpolations
|
20
22
|
include Command::Commands::EqBase
|
21
23
|
include Command::Commands::Data
|
22
24
|
include Command::Commands::Tree
|
@@ -18,10 +18,42 @@ module I18n::Tasks::Concurrent
|
|
18
18
|
|
19
19
|
# @return [Object] Result of the computation.
|
20
20
|
def get
|
21
|
-
return
|
21
|
+
return get_result_volatile unless get_result_volatile == NULL
|
22
22
|
@mutex.synchronize do
|
23
|
-
|
23
|
+
next unless get_result_volatile == NULL
|
24
|
+
set_result_volatile @computation.call
|
25
|
+
@computation = nil
|
24
26
|
end
|
27
|
+
get_result_volatile
|
25
28
|
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
# Ruby instance variable volatility is currently unspecified:
|
33
|
+
# https://bugs.ruby-lang.org/issues/11539
|
34
|
+
#
|
35
|
+
# Below are the implementations for major ruby engines, based on concurrent-ruby.
|
36
|
+
# rubocop:disable Lint/DuplicateMethods,Naming/AccessorMethodName
|
37
|
+
case RUBY_ENGINE
|
38
|
+
when 'rbx'
|
39
|
+
def get_result_volatile
|
40
|
+
Rubinius.memory_barrier
|
41
|
+
@result
|
42
|
+
end
|
43
|
+
|
44
|
+
def set_result_volatile(value)
|
45
|
+
@result = value
|
46
|
+
Rubinius.memory_barrier
|
47
|
+
end
|
48
|
+
else
|
49
|
+
def get_result_volatile
|
50
|
+
@result
|
51
|
+
end
|
52
|
+
|
53
|
+
def set_result_volatile(value)
|
54
|
+
@result = value
|
55
|
+
end
|
56
|
+
end
|
57
|
+
# rubocop:enable Lint/DuplicateMethods,Naming/AccessorMethodName
|
26
58
|
end
|
27
59
|
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module I18n::Tasks
|
4
|
+
module Interpolations
|
5
|
+
VARIABLE_REGEX = /%{[^}]+}/
|
6
|
+
|
7
|
+
def inconsistent_interpolations(locales: nil, base_locale: nil) # rubocop:disable Metrics/AbcSize
|
8
|
+
locales ||= self.locales
|
9
|
+
base_locale ||= self.base_locale
|
10
|
+
result = empty_forest
|
11
|
+
|
12
|
+
data[base_locale].key_values.each do |key, value|
|
13
|
+
next if !value.is_a?(String) || ignore_key?(key, :inconsistent_interpolations)
|
14
|
+
base_vars = Set.new(value.scan(VARIABLE_REGEX))
|
15
|
+
(locales - [base_locale]).each do |current_locale|
|
16
|
+
node = data[current_locale].first.children[key]
|
17
|
+
next unless node&.value&.is_a?(String)
|
18
|
+
vars = node.value.scan(VARIABLE_REGEX)
|
19
|
+
unless vars.size == base_vars.size && vars.all? { |v| base_vars.include?(v) }
|
20
|
+
result.merge!(node.walk_to_root.reduce(nil) { |c, p| [p.derive(children: c)] })
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
result.each { |root| root.data[:type] = :inconsistent_interpolations }
|
26
|
+
result
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -21,6 +21,10 @@ module I18n::Tasks::Reports
|
|
21
21
|
"Missing translations (#{forest.leaves.count || '∅'})"
|
22
22
|
end
|
23
23
|
|
24
|
+
def inconsistent_interpolations_title(forest)
|
25
|
+
"Inconsistent interpolations (#{forest.leaves.count || '∅'})"
|
26
|
+
end
|
27
|
+
|
24
28
|
def unused_title(key_values)
|
25
29
|
"Unused keys (#{key_values.count || '∅'})"
|
26
30
|
end
|
@@ -25,6 +25,15 @@ module I18n
|
|
25
25
|
end
|
26
26
|
end
|
27
27
|
|
28
|
+
def inconsistent_interpolations(forest = task.inconsistent_interpolations)
|
29
|
+
if forest.present?
|
30
|
+
print_title inconsistent_interpolations_title(forest)
|
31
|
+
show_tree(forest)
|
32
|
+
else
|
33
|
+
print_success I18n.t('i18n_tasks.inconsistent_interpolations.none')
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
28
37
|
def icon(type)
|
29
38
|
glyph = missing_type_info(type)[:glyph]
|
30
39
|
{ missing_used: Rainbow(glyph).red, missing_diff: Rainbow(glyph).yellow }[type]
|
@@ -61,7 +61,7 @@ module I18n::Tasks::Translators
|
|
61
61
|
|
62
62
|
def configure_api_key!
|
63
63
|
api_key = @i18n_tasks.translation_config[:deepl_api_key]
|
64
|
-
fail CommandError, I18n.t('i18n_tasks.deepl_translate.errors.no_api_key') if api_key.blank?
|
64
|
+
fail ::I18n::Tasks::CommandError, I18n.t('i18n_tasks.deepl_translate.errors.no_api_key') if api_key.blank?
|
65
65
|
DeepL.configure { |config| config.auth_key = api_key }
|
66
66
|
end
|
67
67
|
end
|
@@ -59,7 +59,7 @@ module I18n::Tasks::Translators
|
|
59
59
|
)
|
60
60
|
key ||= translation_config[:api_key]
|
61
61
|
end
|
62
|
-
fail CommandError, I18n.t('i18n_tasks.google_translate.errors.no_api_key') if key.blank?
|
62
|
+
fail ::I18n::Tasks::CommandError, I18n.t('i18n_tasks.google_translate.errors.no_api_key') if key.blank?
|
63
63
|
key
|
64
64
|
end
|
65
65
|
end
|
data/lib/i18n/tasks/version.rb
CHANGED
@@ -111,6 +111,10 @@ search:
|
|
111
111
|
# fr,es:
|
112
112
|
# - common.brand
|
113
113
|
|
114
|
+
## Exclude these keys from the `i18n-tasks check-consistent-interpolations` report:
|
115
|
+
# ignore_inconsistent_interpolations:
|
116
|
+
# - 'activerecord.attributes.*'
|
117
|
+
|
114
118
|
## Ignore these keys completely:
|
115
119
|
# ignore:
|
116
120
|
# - kaminari.*
|
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.26
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- glebm
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-
|
11
|
+
date: 2018-10-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -282,6 +282,7 @@ files:
|
|
282
282
|
- lib/i18n/tasks/command/commands/data.rb
|
283
283
|
- lib/i18n/tasks/command/commands/eq_base.rb
|
284
284
|
- lib/i18n/tasks/command/commands/health.rb
|
285
|
+
- lib/i18n/tasks/command/commands/interpolations.rb
|
285
286
|
- lib/i18n/tasks/command/commands/meta.rb
|
286
287
|
- lib/i18n/tasks/command/commands/missing.rb
|
287
288
|
- lib/i18n/tasks/command/commands/tree.rb
|
@@ -312,6 +313,7 @@ files:
|
|
312
313
|
- lib/i18n/tasks/data/tree/traversal.rb
|
313
314
|
- lib/i18n/tasks/html_keys.rb
|
314
315
|
- lib/i18n/tasks/ignore_keys.rb
|
316
|
+
- lib/i18n/tasks/interpolations.rb
|
315
317
|
- lib/i18n/tasks/key_pattern_matching.rb
|
316
318
|
- lib/i18n/tasks/locale_list.rb
|
317
319
|
- lib/i18n/tasks/locale_pathname.rb
|