Skip to content

Commit

Permalink
Add check-consistent-interpolations
Browse files Browse the repository at this point in the history
Verify that non-base translations are using variable names defined
in the base translation.

Fix #303
  • Loading branch information
Gargron committed Oct 17, 2018
1 parent 4fbf49c commit 682adc8
Show file tree
Hide file tree
Showing 8 changed files with 118 additions and 1 deletion.
3 changes: 3 additions & 0 deletions config/locales/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ en:
%{value_or_default_or_human_key}
desc:
add_missing: add missing keys to locale data
check_consistent_interpolations: verify that all translations use correct interpolation variables
check_normalized: verify that all translation data is normalized
config: display i18n-tasks configuration
data: show locale data
Expand Down Expand Up @@ -117,3 +118,5 @@ en:
none: Every translation is in use.
usages:
none: No key usages found.
wrong_interpolations:
none: No inconsistent interpolations found.
4 changes: 4 additions & 0 deletions config/locales/ru.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ ru:
%{value_or_default_or_human_key}
desc:
add_missing: добавить недостающие ключи к переводам
check_consistent_interpolations: убедитесь, что во всех переводах используются правильные
интерполяционные переменные
check_normalized: проверить, что все файлы переводов нормализованы
config: показать конфигурацию
data: показать данные переводов
Expand Down Expand Up @@ -114,3 +116,5 @@ ru:
none: Все переводы используются.
usages:
none: Не найдено использований.
wrong_interpolations:
none: Не найдено несогласованных интерполяций.
2 changes: 2 additions & 0 deletions lib/i18n/tasks/base_task.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
require 'i18n/tasks/used_keys'
require 'i18n/tasks/ignore_keys'
require 'i18n/tasks/missing_keys'
require 'i18n/tasks/wrong_interpolations'
require 'i18n/tasks/unused_keys'
require 'i18n/tasks/translation'
require 'i18n/tasks/locale_pathname'
Expand All @@ -30,6 +31,7 @@ class BaseTask
include UsedKeys
include IgnoreKeys
include MissingKeys
include WrongInterpolations
include UnusedKeys
include Translation
include Logging
Expand Down
18 changes: 17 additions & 1 deletion lib/i18n/tasks/command/commands/health.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,23 @@ def health(opt = {})
stats = i18n.forest_stats(forest)
fail CommandError, t('i18n_tasks.health.no_keys_detected') if stats[:key_count].zero?
terminal_report.forest_stats forest, stats
[missing(opt), unused(opt), check_normalized(opt)].detect { |result| result == :exit_1 }
[
missing(opt),
unused(opt),
check_normalized(opt),
check_consistent_interpolations(opt)
].detect { |result| result == :exit_1 }
end

cmd :check_consistent_interpolations,
pos: '[locale ...]',
desc: t('i18n_tasks.cmd.desc.check_consistent_interpolations'),
args: %i[locales out_format]

def check_consistent_interpolations(opt = {})
forest = i18n.wrong_interpolations(opt.slice(:locales, :base_locale))
print_forest forest, opt, :wrong_interpolations
:exit_1 unless forest.empty?
end
end
end
Expand Down
4 changes: 4 additions & 0 deletions lib/i18n/tasks/reports/base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ def missing_title(forest)
"Missing translations (#{forest.leaves.count || '∅'})"
end

def wrong_interpolations_title(forest)
"Inconsistent interpolations (#{forest.leaves.count || '∅'})"
end

def unused_title(key_values)
"Unused keys (#{key_values.count || '∅'})"
end
Expand Down
9 changes: 9 additions & 0 deletions lib/i18n/tasks/reports/terminal.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,15 @@ def missing_keys(forest = task.missing_keys)
end
end

def wrong_interpolations(forest = task.wrong_interpolations)
if forest.present?
print_title wrong_interpolations_title(forest)
show_tree(forest)
else
print_success I18n.t('i18n_tasks.wrong_interpolations.none')
end
end

def icon(type)
glyph = missing_type_info(type)[:glyph]
{ missing_used: Rainbow(glyph).red, missing_diff: Rainbow(glyph).yellow }[type]
Expand Down
48 changes: 48 additions & 0 deletions lib/i18n/tasks/wrong_interpolations.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# frozen_string_literal: true

module I18n::Tasks
module WrongInterpolations
VARIABLE_REGEX = /%{[^}]+}/

def wrong_interpolations(locales: nil, base_locale: nil)
locales ||= self.locales
base = base_locale || self.base_locale
tree = empty_forest

data[base].key_values.each do |key, node|
next unless node.is_a?(String)

base_variables = node.scan(VARIABLE_REGEX)

(locales - [base]).each do |current_locale|
check_in_other_locale(tree, key, base_variables, current_locale)
end
end

tree
end

private

def check_in_other_locale(tree, key, base_variables, locale)
node = data[locale].first.children[key]

return if node.nil? || !node.value.is_a?(String)

compare_variables = node.value.scan(VARIABLE_REGEX)

return if same_array?(base_variables, compare_variables)

tree.merge!(select_key(key, locale))
end

def select_key(key, locale)
data[locale].select_keys(root: false) { |search_key| search_key == key }
.set_root_key!(locale, type: :wrong_interpolations)
end

def same_array?(a, b)
a.size == b.size && (a & b == a)
end
end
end
31 changes: 31 additions & 0 deletions spec/wrong_interpolations_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe 'WrongInterpolations' do
let!(:task) { I18n::Tasks::BaseTask.new }

let(:base_keys) { { 'a' => 'hello %{world}', 'b' => 'foo', 'c' => { 'd' => 'hello %{name}' }, 'e' => 'ok' } }
let(:test_keys) { { 'a' => 'hello', 'b' => 'foo %{bar}', 'c' => { 'd' => 'hola %{amigo}' }, 'e' => 'ok' } }

around do |ex|
TestCodebase.setup(
'config/i18n-tasks.yml' => { base_locale: 'en', locales: %w[es] }.to_yaml,
'config/locales/en.yml' => { 'en' => base_keys }.to_yaml,
'config/locales/es.yml' => { 'es' => test_keys }.to_yaml
)

TestCodebase.in_test_app_dir { ex.call }
TestCodebase.teardown
end

it '#wrong_interpolations' do
wrong = task.wrong_interpolations
leaves = wrong.leaves.to_a

expect(leaves.size).to eq 3
expect(leaves[0].full_key).to eq 'es.a'
expect(leaves[1].full_key).to eq 'es.b'
expect(leaves[2].full_key).to eq 'es.c.d'
end
end

0 comments on commit 682adc8

Please sign in to comment.