diff --git a/.travis.yml b/.travis.yml
index 4bfaa152..58b8ec9e 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,9 +1,9 @@
language: ruby
rvm:
-- 2.1.1
+- 2.1.3
- 2.0.0
- 1.9.3
-- jruby-1.7.13
+- jruby
- rbx-2.2.10
env:
global:
diff --git a/CHANGES.md b/CHANGES.md
index 6187030f..9f20234e 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -1,3 +1,19 @@
+## 0.7.8
+
+* Fix Google Translate issues with non-string keys [#100](https://github.com/glebm/i18n-tasks/pull/100)
+* Fix an issue with certain HAML not being parsed [#96](https://github.com/glebm/i18n-tasks/issues/96) [#102](https://github.com/glebm/i18n-tasks/pull/102)
+* Fix other minor issues
+
+## 0.7.7
+
+* Fix regression: keys are sorted once again [#92](https://github.com/glebm/i18n-tasks/issues/92).
+
+## 0.7.6
+
+* Add a post-install notice with setup commands
+* Fix a small typo in the config template [#91](https://github.com/glebm/i18n-tasks/pull/91).
+* Fix `find` crashing on relative keys (regression)
+
## 0.7.5
Dynamic key usage inference fixes by [Mikko Koski](https://github.com/rap1ds):
diff --git a/README.md b/README.md
index 85783186..ea28dc09 100644
--- a/README.md
+++ b/README.md
@@ -1,31 +1,28 @@
-# i18n-tasks [![Build Status][badge-travis]][travis] [![Coverage Status][badge-coverage]][coverage] [![Code Climate][badge-code-climate]][code-climate] [![Gemnasium][badge-gemnasium]][gemnasium]
+# i18n-tasks [![Build Status][badge-travis]][travis] [![Coverage Status][badge-coverage]][coverage] [![Code Climate][badge-code-climate]][code-climate] [![Gemnasium][badge-gemnasium]][gemnasium] [![Gitter](https://badges.gitter.im/Join Chat.svg)](https://gitter.im/glebm/i18n-tasks?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
i18n-tasks helps you find and manage missing and unused translations.
-## What?
-
-i18n-tasks scans calls such as `I18n.t('some.key')` and provides reports on key usage, missing, and unused keys.
-i18n-tasks can also can pre-fill missing keys, including from Google Translate, and it can remove unused keys as well.
+
-## Why?
+This gem analyses code statically for key usages, such as `I18n.t('some.key')`, in order to:
-The default approach to locale data management with gems such as [i18n][i18n-gem] is flawed.
-If you use a key that does not exist, this will only blow up at runtime. Keys left over from removed code accumulate
-in the resource files and introduce unnecessary overhead on the translators. Translation files can quickly turn to disarray.
+* Report keys that are missing or unused.
+* Pre-fill missing keys, optionally from Google Translate.
+* Remove unused keys.
-i18n-tasks improves this by analysing code statically, without running it. It scans calls such as `I18n.t('some.key')` and provides reports on key usage, missing, and unused keys.
-It can also pre-fill missing keys, including from Google Translate, and it can remove unused keys as well.
+Thus addressing the two main problems of [i18n gem][i18n-gem] design:
-i18n-tasks can be used with any project using [i18n][i18n-gem] (default in Rails), or similar, even if it isn't ruby.
-
-
+* Missing keys only blow up at runtime.
+* Keys no longer in use may accumulate and introduce overhead, without you knowing it.
## Installation
-Add to Gemfile:
+i18n-tasks can be used with any project using [i18n][i18n-gem] (default in Rails), or similar, even if it isn't ruby.
+
+Add it to the Gemfile:
```ruby
-gem 'i18n-tasks', '~> 0.7.5'
+gem 'i18n-tasks', '~> 0.7.8'
```
Copy default [configuration file](#configuration) (optional):
@@ -117,7 +114,7 @@ Sort the keys:
$ i18n-tasks normalize
```
-Sort the keys, and move them to the respective files as defined by (`config.write`)[#multiple-locale-files]:
+Sort the keys, and move them to the respective files as defined by [`config.write`](#multiple-locale-files):
```console
$ i18n-tasks normalize -p
@@ -411,7 +408,7 @@ Add a custom task like the ones defined by the gem:
```ruby
# my_commands.rb
-class MyCommands
+module MyCommands
include ::I18n::Tasks::Command::Collection
cmd :my_task, desc: 'my custom task'
def my_task(opts = {})
@@ -422,7 +419,7 @@ end
```yaml
# config/i18n-tasks.yml
<%
- require 'my_commands'
+ require './my_commands'
I18n::Tasks::Commands.send :include, MyCommands
%>
```
diff --git a/bin/i18n-tasks b/bin/i18n-tasks
index bc3945fc..471bb404 100755
--- a/bin/i18n-tasks
+++ b/bin/i18n-tasks
@@ -13,10 +13,10 @@ require 'i18n/tasks/commands'
require 'slop'
err = proc { |message, exit_code|
- if STDERR.isatty
- STDERR.puts Term::ANSIColor.yellow('i18n-tasks: ' + message)
+ if $stderr.isatty
+ $stderr.puts Term::ANSIColor.yellow('i18n-tasks: ' + message)
else
- STDERR.puts message
+ $stderr.puts message
end
exit exit_code
}
diff --git a/config/i18n-tasks.yml b/config/i18n-tasks.yml
index cfae6019..725418ac 100644
--- a/config/i18n-tasks.yml
+++ b/config/i18n-tasks.yml
@@ -1,5 +1,8 @@
# i18n-tasks works on itself! this is the internal config
+# This is not the default config for new apps, but is the internal config for i18n-tasks to analyze itself.
+# You can find the default config here: https://github.com/glebm/i18n-tasks/blob/master/templates/config/i18n-tasks.yml
+
base_locale: en
## i18n-tasks detects locales automatically from the existing locale files
## uncomment to set locales explicitly
@@ -22,7 +25,7 @@ data:
# key => file routes, matched top to bottom
write:
## E.g., write devise and simple form keys to their respective files
- # - ['{devise, simple_form}.*', 'config/locales/\1.%{locale.yml}']
+ # - ['{devise, simple_form}.*', 'config/locales/\1.%{locale}.yml']
# Catch-all
- config/locales/%{locale}.yml
# `i18n-tasks normalize -p` will force move the keys according to these rules
@@ -59,10 +62,6 @@ search:
## Or, File.fnmatch patterns to include
# include: ["*.rb", "*.html.slim"]
- ## Lines starting with # or / are ignored by default
- # ignore_lines:
- # - "^\\s*[#/](?!\\si18n-tasks-use)"
-
## Google Translate
# translation:
# # Get an API key and set billing info at https://code.google.com/apis/console to use Google Translate
diff --git a/config/locales/en.yml b/config/locales/en.yml
index 0507de9b..f010fe10 100644
--- a/config/locales/en.yml
+++ b/config/locales/en.yml
@@ -1,102 +1,103 @@
---
en:
i18n_tasks:
- common:
- locale: Locale
- type: Type
- key: Key
- value: Value
- base_value: Base Value
- details: Details
- continue_q: Continue?
- n_more: "%{count} more"
- google_translate:
- errors:
- no_results: Google Translate returned no results. Make sure billing information is set at
- https://code.google.com/apis/console.
- remove_unused:
- confirm:
- one: One translations will be removed from %{locales}.
- other: "%{count} translation will be removed from %{locales}."
- removed: Removed %{count} keys
- noop: No unused keys to remove
- translate_missing:
- translated: Translated %{count} keys
add_missing:
added: Added %{count} keys
- unused:
- none: Every translation is in use.
- missing:
- none: No translations are missing.
- usages:
- none: No key usages found.
- health:
- no_keys_detected: No keys detected. Check data.read in config/i18n-tasks.yml.
- data_stats:
- title: Forest (%{locales})
- text: has %{key_count} keys across %{locale_count} locales. On average, values are %{value_chars_avg}
- characters long, keys have %{key_segments_avg} segments, a locale has %{per_locale_avg} keys.
- text_single_locale: has %{key_count} keys in total. On average, values are %{value_chars_avg}
- characters long, keys have %{key_segments_avg} segments.
cmd:
- encourage:
- - Good job!
- - Well done!
- - Perfect!
+ args:
+ default_all: 'Default: all'
+ default_text: 'Default: %{value}'
+ desc:
+ confirm: Confirm automatically
+ data_format: 'Data format: %{valid_text}. %{default_text}.'
+ key_pattern: Filter by key pattern (e.g. 'common.*')
+ key_pattern_to_rename: Full key (pattern) to rename. Required
+ locale: 'Locale. Default: base'
+ locale_to_translate_from: 'Locale to translate from (default: base)'
+ locales_filter: 'Comma-separated list of locale(s) to process. Default: all. Special: base.'
+ missing_types: 'Filter by types: %{valid}. Default: all'
+ new_key_name: New name, interpolates original name as %{key}. Required
+ nostdin: Do not read from stdin
+ out_format: 'Output format: %{valid_text}. %{default_text}.'
+ pattern_router: 'Use pattern router: keys moved per config data.write'
+ strict: Do not infer dynamic key usage such as `t("category.\#{category.name}")`
+ value: 'Value. Interpolates: %{value}, %{human_key}, %{value_or_human_key}'
desc:
- normalize: 'normalize translation data: sort and move to the right files'
+ add_missing: add missing keys to locale data
+ config: display i18n-tasks configuration
data: show locale data
data_merge: merge locale data with trees
- data_write: replace locale data with tree
data_remove: remove keys present in tree from data
- health: is everything OK?
+ data_write: replace locale data with tree
+ eq_base: show translations equal to base value
find: show where keys are used in the code
- unused: show unused translations
+ gem_path: show path to the gem
+ health: is everything OK?
+ irb: start REPL session within i18n-tasks context
missing: show missing translations
- translate_missing: translate missing keys with Google Translate
- add_missing: add missing keys to locale data
+ normalize: 'normalize translation data: sort and move to the right files'
remove_unused: remove unused keys
- eq_base: show translations equal to base value
- tree_translate: Google Translate a tree to root locales
- tree_merge: merge trees
+ translate_missing: translate missing keys with Google Translate
+ tree_convert: convert tree between formats
tree_filter: filter tree by key pattern
+ tree_merge: merge trees
tree_rename_key: rename tree node
- tree_subtract: tree A minus the keys in tree B
tree_set_value: set values of keys, optionally match a pattern
- tree_convert: convert tree between formats
- config: display i18n-tasks configuration
- gem_path: show path to the gem
- irb: start REPL session within i18n-tasks context
+ tree_subtract: tree A minus the keys in tree B
+ tree_translate: Google Translate a tree to root locales
+ unused: show unused translations
xlsx_report: save missing and unused translations to an Excel file
- args:
- default_text: 'Default: %{value}'
- default_all: 'Default: all'
- desc:
- out_format: 'Output format: %{valid_text}. %{default_text}.'
- data_format: 'Data format: %{valid_text}. %{default_text}.'
- keys: List of keys separated by commas (,), spaces, or newlines.
- locales_filter: 'Comma-separated list of locale(s) to process. Default: all. Special: base.'
- locale: 'Locale. Default: base'
- locale_to_translate_from: 'Locale to translate from (default: base)'
- confirm: Confirm automatically
- nostdin: Do not read from stdin
- strict: Do not infer dynamic key usage such as `t("category.\#{category.name}")`
- missing_types: 'Filter by types: %{valid}. Default: all'
- key_pattern: Filter by key pattern (e.g. 'common.*')
- key_pattern_to_rename: Full key (pattern) to rename. Required
- new_key_name: New name, interpolates original name as %{key}. Required
- value: 'Value. Interpolates: %{value}, %{human_key}, %{value_or_human_key}'
- pattern_router: 'Use pattern router: keys moved per config data.write'
- enum_opt:
- desc: "%{valid_text}. %{default_text}"
- invalid: "%{invalid} is not one of: %{valid}."
+ encourage:
+ - Good job!
+ - Well done!
+ - Perfect!
enum_list_opt:
desc: 'Comma-separated list of: %{valid_text}. %{default_text}'
invalid: "%{invalid} is not in: %{valid}."
+ enum_opt:
+ desc: "%{valid_text}. %{default_text}"
+ invalid: "%{invalid} is not one of: %{valid}."
errors:
- pass_forest: Pass locale forest
- invalid_locale: Invalid locale %{invalid}
invalid_format: 'Unknown format %{invalid}. Valid: %{valid}.'
+ invalid_locale: Invalid locale %{invalid}
invalid_missing_type:
one: 'Unknown type %{invalid}. Valid: %{valid}.'
other: 'Unknown types: %{invalid}. Valid: %{valid}.'
+ pass_forest: Pass locale forest
+ common:
+ base_value: Base Value
+ continue_q: Continue?
+ details: Details
+ key: Key
+ locale: Locale
+ n_more: "%{count} more"
+ type: Type
+ value: Value
+ data_stats:
+ text: has %{key_count} keys across %{locale_count} locales. On average, values are %{value_chars_avg}
+ characters long, keys have %{key_segments_avg} segments, a locale has %{per_locale_avg} keys.
+ text_single_locale: has %{key_count} keys in total. On average, values are %{value_chars_avg}
+ characters long, keys have %{key_segments_avg} segments.
+ title: Forest (%{locales})
+ google_translate:
+ errors:
+ no_api_key: Set Google API key via GOOGLE_TRANSLATE_API_KEY environment variable or translation.api_key
+ in config/i18n-tasks.yml. Get the key at https://code.google.com/apis/console.
+ no_results: Google Translate returned no results. Make sure billing information is set at
+ https://code.google.com/apis/console.
+ health:
+ no_keys_detected: No keys detected. Check data.read in config/i18n-tasks.yml.
+ missing:
+ none: No translations are missing.
+ remove_unused:
+ confirm:
+ one: One translations will be removed from %{locales}.
+ other: "%{count} translation will be removed from %{locales}."
+ noop: No unused keys to remove
+ removed: Removed %{count} keys
+ translate_missing:
+ translated: Translated %{count} keys
+ unused:
+ none: Every translation is in use.
+ usages:
+ none: No key usages found.
diff --git a/config/locales/ru.yml b/config/locales/ru.yml
index 56d630c9..e103e3bd 100644
--- a/config/locales/ru.yml
+++ b/config/locales/ru.yml
@@ -1,103 +1,104 @@
---
ru:
i18n_tasks:
- common:
- locale: "Язык"
- type: "Тип"
- key: "Ключ"
- value: "Значение"
- base_value: "Исходное значение"
- details: "Детали"
- continue_q: "Продолжить?"
- n_more: "ещё %{count}"
- google_translate:
- errors:
- no_results: Google Translate не дал результатов. Убедитесь в том, что платежная информация
- добавлена в в https://code.google.com/apis/console.
- remove_unused:
- confirm:
- one: "Один перевод будут удалён из %{locales}."
- other: "Переводы (%{count}) будут удалены из %{locales}."
- removed: "Удалены ключи (%{count})"
- noop: "Нет неиспользуемых ключей"
- translate_missing:
- translated: "Переведены ключи (%{count})"
add_missing:
added: "Добавлены ключи (%{count})"
- unused:
- none: "Все переводы используются."
- missing:
- none: "Всё переведено."
- usages:
- none: "Не найдено использований."
- health:
- no_keys_detected: "Ключи не обнаружены. Проверьте data.read в config/i18n-tasks.yml."
- data_stats:
- title: "Данные (%{locales}):"
- text: "%{key_count} ключей в %{locale_count} языках. В среднем, длина строки: %{value_chars_avg},
- сегменты ключей: %{key_segments_avg}, ключей в языке %{per_locale_avg}."
- text_single_locale: "%{key_count} ключей. В среднем, длина строки: %{value_chars_avg}, сегменты
- ключей: %{key_segments_avg}."
cmd:
- encourage:
- - "Хорошая работа!"
- - "Отлично!"
- - "Прекрасно!"
+ args:
+ default_all: "По умолчанию: все"
+ default_text: "По умолчанию: %{value}"
+ desc:
+ confirm: "Подтвердить автоматом"
+ data_format: "Формат данных: %{valid_text}. %{default_text}."
+ key_pattern: "Маска ключа (например, common.*)"
+ key_pattern_to_rename: "Полный ключ (шаблон) для переименования. Необходимый параметр."
+ locale: "Язык. По умолчанию: base"
+ locale_to_translate_from: "Язык, с которого переводить (по умолчанию: base)"
+ locales_filter: "Список языков для обработки, разделенный запятыми (,). По умолчанию: все.
+ Специальное значение: base."
+ missing_types: "Типы недостающих переводов: %{valid}. По умолчанию: все"
+ new_key_name: "Новое имя, интерполирует оригинальное название как %{key}. Необходимый параметр."
+ nostdin: "Не читать дерево из стандартного ввода"
+ out_format: "Формат вывода: %{valid_text}. %{default_text}."
+ pattern_router: "Использовать pattern_router: ключи распределятся по файлам согласно data.write"
+ strict: Не угадывать динамические использования ключей, например `t("category.#{category.key}")`
+ value: "Значение, интерполируется с %{value}, %{human_key}, %{value_or_human_key}"
desc:
- normalize: "нормализовать файлы переводов (сортировка и распределение)"
+ add_missing: "добавить недостающие ключи к переводам"
+ config: "показать конфигурацию"
data: "показать данные переводов"
data_merge: "добавить дерево к переводам"
- data_write: "заменить переводы деревом"
data_remove: "удалить ключи, которые есть в дереве, из данных"
- health: "Всё ОК?"
+ data_write: "заменить переводы деревом"
+ eq_base: "показать переводы, равные значениям в основном языке"
find: "показать, где ключи используются в коде"
- unused: "показать неиспользуемые переводы"
+ gem_path: "показать путь к ruby gem"
+ health: "Всё ОК?"
+ irb: "начать REPL сессию в контексте i18n-tasks"
missing: "показать недостающие переводы"
- translate_missing: "перевести недостающие переводы с Google Translate"
- add_missing: "добавить недостающие ключи к переводам"
+ normalize: "нормализовать файлы переводов (сортировка и распределение)"
remove_unused: "удалить неиспользуемые ключи"
- eq_base: "показать переводы, равные значениям в основном языке"
- tree_merge: "объединенить деревья"
+ translate_missing: "перевести недостающие переводы с Google Translate"
+ tree_convert: "преобразовать дерево между форматами"
tree_filter: "фильтровать дерево по ключу"
+ tree_merge: "объединенить деревья"
tree_rename_key: "переименовать узел дерева"
- tree_subtract: "дерево A минус ключи в дереве B"
tree_set_value: "заменить значения ключей"
- tree_convert: "преобразовать дерево между форматами"
- config: "показать конфигурацию"
- gem_path: "показать путь к ruby gem"
- irb: "начать REPL сессию в контексте i18n-tasks"
- xlsx_report: "сохранить недостающие и неиспользуемые переводы в Excel-файл"
+ tree_subtract: "дерево A минус ключи в дереве B"
tree_translate: "Перевести дерево при помощи Google Translate на язык корневых узлов"
- args:
- default_text: "По умолчанию: %{value}"
- default_all: "По умолчанию: все"
- desc:
- out_format: "Формат вывода: %{valid_text}. %{default_text}."
- data_format: "Формат данных: %{valid_text}. %{default_text}."
- keys: "Список ключей, разделенных запятыми (,), пробелами или символами новой строки."
- locales_filter: "Список языков для обработки, разделенный запятыми (,). По умолчанию: все.
- Специальное значение: base."
- locale_to_translate_from: "Язык, с которого переводить (по умолчанию: base)"
- locale: "Язык. По умолчанию: base"
- confirm: "Подтвердить автоматом"
- nostdin: "Не читать дерево из стандартного ввода"
- strict: Не угадывать динамические использования ключей, например `t("category.#{category.key}")`
- missing_types: "Типы недостающих переводов: %{valid}. По умолчанию: все"
- key_pattern: "Маска ключа (например, common.*)"
- key_pattern_to_rename: "Полный ключ (шаблон) для переименования. Необходимый параметр."
- new_key_name: "Новое имя, интерполирует оригинальное название как %{key}. Необходимый параметр."
- value: "Значение, интерполируется с %{value}, %{human_key}, %{value_or_human_key}"
- pattern_router: "Использовать pattern_router: ключи распределятся по файлам согласно data.write"
- enum_opt:
- desc: "%{valid_text}. %{default_text}"
- invalid: "%{invalid} не является одним из: %{valid}."
+ unused: "показать неиспользуемые переводы"
+ xlsx_report: "сохранить недостающие и неиспользуемые переводы в Excel-файл"
+ encourage:
+ - "Хорошая работа!"
+ - "Отлично!"
+ - "Прекрасно!"
enum_list_opt:
desc: "Разделенных запятыми список: %{valid_text}. %{default_text}"
invalid: "%{invalid} не в: %{valid}."
+ enum_opt:
+ desc: "%{valid_text}. %{default_text}"
+ invalid: "%{invalid} не является одним из: %{valid}."
errors:
- pass_forest: "Передайте дерево"
- invalid_locale: "Неверный язык %{invalid}"
invalid_format: "Неизвестный формат %{invalid}. Форматы: %{valid}."
+ invalid_locale: "Неверный язык %{invalid}"
invalid_missing_type:
one: "Неизвестный тип %{invalid}. Типы: %{valid}."
other: "Неизвестные типы: %{invalid}. Типы: %{valid}."
+ pass_forest: "Передайте дерево"
+ common:
+ base_value: "Исходное значение"
+ continue_q: "Продолжить?"
+ details: "Детали"
+ key: "Ключ"
+ locale: "Язык"
+ n_more: "ещё %{count}"
+ type: "Тип"
+ value: "Значение"
+ data_stats:
+ text: "%{key_count} ключей в %{locale_count} языках. В среднем, длина строки: %{value_chars_avg},
+ сегменты ключей: %{key_segments_avg}, ключей в языке %{per_locale_avg}."
+ text_single_locale: "%{key_count} ключей. В среднем, длина строки: %{value_chars_avg}, сегменты
+ ключей: %{key_segments_avg}."
+ title: "Данные (%{locales}):"
+ google_translate:
+ errors:
+ no_api_key: Задайте ключ API Google через переменную окружения GOOGLE_TRANSLATE_API_KEY
+ или translation.api_key в config/i18n-tasks.yml. Получите ключ через https://code.google.com/apis/console.
+ no_results: Google Translate не дал результатов. Убедитесь в том, что платежная информация
+ добавлена в https://code.google.com/apis/console.
+ health:
+ no_keys_detected: "Ключи не обнаружены. Проверьте data.read в config/i18n-tasks.yml."
+ missing:
+ none: "Всё переведено."
+ remove_unused:
+ confirm:
+ one: "Один перевод будут удалён из %{locales}."
+ other: "Переводы (%{count}) будут удалены из %{locales}."
+ noop: "Нет неиспользуемых ключей"
+ removed: "Удалены ключи (%{count})"
+ translate_missing:
+ translated: "Переведены ключи (%{count})"
+ unused:
+ none: "Все переводы используются."
+ usages:
+ none: "Не найдено использований."
diff --git a/i18n-tasks.gemspec b/i18n-tasks.gemspec
index 10cfa8db..be0b72f1 100644
--- a/i18n-tasks.gemspec
+++ b/i18n-tasks.gemspec
@@ -9,12 +9,18 @@ Gem::Specification.new do |s|
s.authors = ['glebm']
s.email = ['glex.spb@gmail.com']
s.summary = %q{Manage localization and translation with the awesome power of static analysis}
- s.description = %q{
+ s.description = <<-TEXT
i18n-tasks helps you find and manage missing and unused translations.
-It scans calls such as `I18n.t('some.key')` and provides reports on key usage, missing, and unused keys.
-It can also can pre-fill missing keys, including from Google Translate, and it can remove unused keys as well.
-}
+It analyses code statically for key usages, such as `I18n.t('some.key')`, in order to report keys that are missing or unused,
+pre-fill missing keys (optionally from Google Translate), and remove unused keys.
+TEXT
+ s.post_install_message = <<-TEXT
+# Install default configuration:
+cp $(i18n-tasks gem-path)/templates/config/i18n-tasks.yml config/
+# Add an RSpec for missing and unused keys:
+cp $(i18n-tasks gem-path)/templates/rspec/i18n_spec.rb spec/
+TEXT
s.homepage = 'https://github.com/glebm/i18n-tasks'
if s.respond_to?(:metadata=)
s.metadata = { 'issue_tracker' => 'https://github.com/glebm/i18n-tasks' }
diff --git a/lib/i18n/tasks/command/collection.rb b/lib/i18n/tasks/command/collection.rb
index 6e5b3a66..2e6e3b95 100644
--- a/lib/i18n/tasks/command/collection.rb
+++ b/lib/i18n/tasks/command/collection.rb
@@ -7,7 +7,7 @@ module Command
module Collection
def self.included(base)
base.module_eval do
- extend Command::DSL
+ include Command::DSL
include Command::Options::Common
include Command::Options::Locales
include Command::Options::Trees
diff --git a/lib/i18n/tasks/command/commands/data.rb b/lib/i18n/tasks/command/commands/data.rb
index c71520bc..c6d45517 100644
--- a/lib/i18n/tasks/command/commands/data.rb
+++ b/lib/i18n/tasks/command/commands/data.rb
@@ -7,13 +7,13 @@ module Data
cmd_opt :pattern_router, {
short: :p,
long: :pattern_router,
- desc: proc { I18n.t('i18n_tasks.cmd.args.desc.pattern_router') },
+ desc: t('i18n_tasks.cmd.args.desc.pattern_router'),
conf: {argument: false, optional: true}
}
cmd :normalize,
args: '[locale ...]',
- desc: proc { I18n.t('i18n_tasks.cmd.desc.normalize') },
+ desc: t('i18n_tasks.cmd.desc.normalize'),
opt: cmd_opts(:locales, :pattern_router)
def normalize(opt = {})
@@ -22,7 +22,7 @@ def normalize(opt = {})
cmd :data,
args: '[locale ...]',
- desc: proc { I18n.t('i18n_tasks.cmd.desc.data') },
+ desc: t('i18n_tasks.cmd.desc.data'),
opt: cmd_opts(:locales, :out_format)
def data(opt = {})
@@ -31,7 +31,7 @@ def data(opt = {})
cmd :data_merge,
args: '[tree ...]',
- desc: proc { I18n.t('i18n_tasks.cmd.desc.data_merge') },
+ desc: t('i18n_tasks.cmd.desc.data_merge'),
opt: cmd_opts(:data_format, :nostdin)
def data_merge(opt = {})
@@ -42,7 +42,7 @@ def data_merge(opt = {})
cmd :data_write,
args: '[tree]',
- desc: proc { I18n.t('i18n_tasks.cmd.desc.data_write') },
+ desc: t('i18n_tasks.cmd.desc.data_write'),
opt: cmd_opts(:data_format, :nostdin)
def data_write(opt = {})
@@ -53,7 +53,7 @@ def data_write(opt = {})
cmd :data_remove,
args: '[tree]',
- desc: proc { I18n.t('i18n_tasks.cmd.desc.data_remove') },
+ desc: t('i18n_tasks.cmd.desc.data_remove'),
opt: cmd_opts(:data_format, :nostdin)
def data_remove(opt = {})
diff --git a/lib/i18n/tasks/command/commands/eq_base.rb b/lib/i18n/tasks/command/commands/eq_base.rb
index 662bfe91..6cd00a40 100644
--- a/lib/i18n/tasks/command/commands/eq_base.rb
+++ b/lib/i18n/tasks/command/commands/eq_base.rb
@@ -6,7 +6,7 @@ module EqBase
cmd :eq_base,
args: '[locale ...]',
- desc: proc { I18n.t('i18n_tasks.cmd.desc.eq_base') },
+ desc: t('i18n_tasks.cmd.desc.eq_base'),
opt: cmd_opts(:locales, :out_format)
def eq_base(opt = {})
diff --git a/lib/i18n/tasks/command/commands/health.rb b/lib/i18n/tasks/command/commands/health.rb
index f6c42172..693cfad3 100644
--- a/lib/i18n/tasks/command/commands/health.rb
+++ b/lib/i18n/tasks/command/commands/health.rb
@@ -6,14 +6,14 @@ module Health
cmd :health,
args: '[locale ...]',
- desc: proc { I18n.t('i18n_tasks.cmd.desc.health') },
+ desc: t('i18n_tasks.cmd.desc.health'),
opt: cmd_opts(:locales, :out_format)
def health(opt = {})
forest = i18n.data_forest(opt[:locales])
stats = i18n.forest_stats(forest)
if stats[:key_count].zero?
- raise CommandError.new I18n.t('i18n_tasks.health.no_keys_detected')
+ raise CommandError.new t('i18n_tasks.health.no_keys_detected')
end
terminal_report.forest_stats forest, stats
missing opt
diff --git a/lib/i18n/tasks/command/commands/meta.rb b/lib/i18n/tasks/command/commands/meta.rb
index 99ae424f..a789db2e 100644
--- a/lib/i18n/tasks/command/commands/meta.rb
+++ b/lib/i18n/tasks/command/commands/meta.rb
@@ -6,7 +6,7 @@ module Meta
cmd :config,
args: '[section ...]',
- desc: proc { I18n.t('i18n_tasks.cmd.desc.config') }
+ desc: t('i18n_tasks.cmd.desc.config')
def config(opts = {})
cfg = i18n.config_for_inspect
@@ -17,13 +17,13 @@ def config(opts = {})
puts cfg
end
- cmd :gem_path, desc: proc { I18n.t('i18n_tasks.cmd.desc.gem_path') }
+ cmd :gem_path, desc: t('i18n_tasks.cmd.desc.gem_path')
def gem_path
puts I18n::Tasks.gem_path
end
- cmd :irb, desc: I18n.t('i18n_tasks.cmd.desc.irb')
+ cmd :irb, desc: t('i18n_tasks.cmd.desc.irb')
def irb
require 'i18n/tasks/console_context'
diff --git a/lib/i18n/tasks/command/commands/missing.rb b/lib/i18n/tasks/command/commands/missing.rb
index f969dda5..fbab1ffd 100644
--- a/lib/i18n/tasks/command/commands/missing.rb
+++ b/lib/i18n/tasks/command/commands/missing.rb
@@ -7,12 +7,12 @@ module Missing
enum_opt :missing_types, I18n::Tasks::MissingKeys.missing_keys_types
cmd_opt :missing_types, enum_list_opt_attr(
:t, :types=, enum_opt(:missing_types),
- proc { |valid, default| I18n.t('i18n_tasks.cmd.args.desc.missing_types', valid: valid, default: default) },
- proc { |invalid, valid| I18n.t('i18n_tasks.cmd.errors.invalid_missing_type', invalid: invalid * ', ', valid: valid * ', ', count: invalid.length) })
+ proc { |valid, default| t('i18n_tasks.cmd.args.desc.missing_types', valid: valid, default: default) },
+ proc { |invalid, valid| t('i18n_tasks.cmd.errors.invalid_missing_type', invalid: invalid * ', ', valid: valid * ', ', count: invalid.length) })
cmd :missing,
args: '[locale ...]',
- desc: proc { I18n.t('i18n_tasks.cmd.desc.missing') },
+ desc: t('i18n_tasks.cmd.desc.missing'),
opt: cmd_opts(:locales, :out_format, :missing_types)
def missing(opt = {})
@@ -21,14 +21,14 @@ def missing(opt = {})
cmd :translate_missing,
args: '[locale ...]',
- desc: proc { I18n.t('i18n_tasks.cmd.desc.translate_missing') },
+ desc: t('i18n_tasks.cmd.desc.translate_missing'),
opt: cmd_opts(:locales, :locale_to_translate_from) << cmd_opt(:out_format).except(:short)
def translate_missing(opt = {})
missing = i18n.missing_diff_forest opt[:locales], opt[:from]
translated = i18n.google_translate_forest missing, opt[:from]
i18n.data.merge! translated
- log_stderr I18n.t('i18n_tasks.translate_missing.translated', count: translated.leaves.count)
+ log_stderr t('i18n_tasks.translate_missing.translated', count: translated.leaves.count)
print_forest translated, opt
end
@@ -36,14 +36,14 @@ def translate_missing(opt = {})
cmd :add_missing,
args: '[locale ...]',
- desc: proc { I18n.t('i18n_tasks.cmd.desc.add_missing') },
+ desc: t('i18n_tasks.cmd.desc.add_missing'),
opt: cmd_opts(:locales, :out_format) <<
- cmd_opt(:value).merge(desc: proc { "#{cmd_opt(:value)[:desc].call}. #{I18n.t('i18n_tasks.cmd.args.default_text', value: DEFAULT_ADD_MISSING_VALUE)}" })
+ cmd_opt(:value).merge(desc: proc { "#{cmd_opt(:value)[:desc].call}. #{t('i18n_tasks.cmd.args.default_text', value: DEFAULT_ADD_MISSING_VALUE)}" })
def add_missing(opt = {})
forest = i18n.missing_keys(opt).set_each_value!(opt[:value] || DEFAULT_ADD_MISSING_VALUE)
i18n.data.merge! forest
- log_stderr I18n.t('i18n_tasks.add_missing.added', count: forest.leaves.count)
+ log_stderr t('i18n_tasks.add_missing.added', count: forest.leaves.count)
print_forest forest, opt
end
end
diff --git a/lib/i18n/tasks/command/commands/tree.rb b/lib/i18n/tasks/command/commands/tree.rb
index 7af60888..df8e7490 100644
--- a/lib/i18n/tasks/command/commands/tree.rb
+++ b/lib/i18n/tasks/command/commands/tree.rb
@@ -6,7 +6,7 @@ module Tree
cmd :tree_translate,
args: '[tree]',
- desc: proc { I18n.t('i18n_tasks.cmd.desc.tree_translate') },
+ desc: t('i18n_tasks.cmd.desc.tree_translate'),
opt: cmd_opts(:locale_to_translate_from) << cmd_opt(:data_format).except(:short)
def tree_translate(opts = {})
@@ -18,7 +18,7 @@ def tree_translate(opts = {})
cmd :tree_merge,
args: '[tree ...]',
- desc: proc { I18n.t('i18n_tasks.cmd.desc.tree_merge') },
+ desc: t('i18n_tasks.cmd.desc.tree_merge'),
opt: cmd_opts(:data_format, :nostdin)
def tree_merge(opts = {})
@@ -27,7 +27,7 @@ def tree_merge(opts = {})
cmd :tree_filter,
args: '[pattern] [tree]',
- desc: proc { I18n.t('i18n_tasks.cmd.desc.tree_filter') },
+ desc: t('i18n_tasks.cmd.desc.tree_filter'),
opt: cmd_opts(:data_format, :pattern)
def tree_filter(opt = {})
@@ -42,12 +42,12 @@ def tree_filter(opt = {})
cmd :tree_rename_key,
args: ' [tree]',
- desc: proc { I18n.t('i18n_tasks.cmd.desc.tree_rename_key') },
+ desc: t('i18n_tasks.cmd.desc.tree_rename_key'),
opt: [
cmd_opt(:pattern).merge(short: :k, long: :key=, desc: proc {
- I18n.t('i18n_tasks.cmd.args.desc.key_pattern_to_rename') }),
+ t('i18n_tasks.cmd.args.desc.key_pattern_to_rename') }),
cmd_opt(:pattern).merge(short: :n, long: :name=, desc: proc {
- I18n.t('i18n_tasks.cmd.args.desc.new_key_name') })
+ t('i18n_tasks.cmd.args.desc.new_key_name') })
] + cmd_opts(:data_format)
def tree_rename_key(opt = {})
@@ -62,7 +62,7 @@ def tree_rename_key(opt = {})
cmd :tree_subtract,
args: '[tree A] [tree B ...]',
- desc: proc { I18n.t('i18n_tasks.cmd.desc.tree_subtract') },
+ desc: t('i18n_tasks.cmd.desc.tree_subtract'),
opt: cmd_opts(:data_format, :nostdin)
def tree_subtract(opt = {})
@@ -73,7 +73,7 @@ def tree_subtract(opt = {})
cmd :tree_set_value,
args: '[value] [tree]',
- desc: proc { I18n.t('i18n_tasks.cmd.desc.tree_set_value') },
+ desc: t('i18n_tasks.cmd.desc.tree_set_value'),
opt: cmd_opts(:value, :data_format, :nostdin, :pattern)
def tree_set_value(opt = {})
@@ -87,7 +87,7 @@ def tree_set_value(opt = {})
cmd :tree_convert,
args: '',
- desc: proc { I18n.t('i18n_tasks.cmd.desc.tree_convert') },
+ desc: t('i18n_tasks.cmd.desc.tree_convert'),
opt: [cmd_opt(:data_format).merge(short: :f, long: :from=),
cmd_opt(:out_format).merge(short: :t, long: :to=)]
diff --git a/lib/i18n/tasks/command/commands/usages.rb b/lib/i18n/tasks/command/commands/usages.rb
index 143f036c..3130a13d 100644
--- a/lib/i18n/tasks/command/commands/usages.rb
+++ b/lib/i18n/tasks/command/commands/usages.rb
@@ -7,12 +7,12 @@ module Usages
cmd_opt :strict, {
short: :s,
long: :strict,
- desc: proc { I18n.t('i18n_tasks.cmd.args.desc.strict') }
+ desc: t('i18n_tasks.cmd.args.desc.strict')
}
cmd :find,
args: '[pattern]',
- desc: proc { I18n.t('i18n_tasks.cmd.desc.find') },
+ desc: t('i18n_tasks.cmd.desc.find'),
opt: cmd_opts(:out_format, :pattern)
def find(opt = {})
@@ -22,7 +22,7 @@ def find(opt = {})
cmd :unused,
args: '[locale ...]',
- desc: proc { I18n.t('i18n_tasks.cmd.desc.unused') },
+ desc: t('i18n_tasks.cmd.desc.unused'),
opt: cmd_opts(:locales, :out_format, :strict)
def unused(opt = {})
@@ -31,7 +31,7 @@ def unused(opt = {})
cmd :remove_unused,
args: '[locale ...]',
- desc: proc { I18n.t('i18n_tasks.cmd.desc.remove_unused') },
+ desc: t('i18n_tasks.cmd.desc.remove_unused'),
opt: cmd_opts(:locales, :out_format, :strict, :confirm)
def remove_unused(opt = {})
@@ -40,10 +40,10 @@ def remove_unused(opt = {})
terminal_report.unused_keys(unused_keys)
confirm_remove_unused!(unused_keys, opt)
removed = i18n.data.remove_by_key!(unused_keys)
- log_stderr I18n.t('i18n_tasks.remove_unused.removed', count: unused_keys.leaves.count)
+ log_stderr t('i18n_tasks.remove_unused.removed', count: unused_keys.leaves.count)
print_forest removed, opt
else
- log_stderr bold green I18n.t('i18n_tasks.remove_unused.noop')
+ log_stderr bold green t('i18n_tasks.remove_unused.noop')
end
end
@@ -53,8 +53,8 @@ def confirm_remove_unused!(unused_keys, opt)
return if ENV['CONFIRM'] || opt[:confirm]
locales = bold(opt[:locales] * ', ')
msg = [
- red(I18n.t('i18n_tasks.remove_unused.confirm', count: unused_keys.leaves.count, locales: locales)),
- yellow(I18n.t('i18n_tasks.common.continue_q')),
+ red(t('i18n_tasks.remove_unused.confirm', count: unused_keys.leaves.count, locales: locales)),
+ yellow(t('i18n_tasks.common.continue_q')),
yellow('(yes/no)')
] * ' '
exit 1 unless agree msg
diff --git a/lib/i18n/tasks/command/commands/xlsx.rb b/lib/i18n/tasks/command/commands/xlsx.rb
index 71f62719..5b50b4b3 100644
--- a/lib/i18n/tasks/command/commands/xlsx.rb
+++ b/lib/i18n/tasks/command/commands/xlsx.rb
@@ -6,7 +6,7 @@ module XLSX
cmd :xlsx_report,
args: '[locale...]',
- desc: proc { I18n.t('i18n_tasks.cmd.desc.xlsx_report') },
+ desc: t('i18n_tasks.cmd.desc.xlsx_report'),
opt: [cmd_opt(:locales),
{short: :p, long: :path=, desc: 'Destination path', conf: {default: 'tmp/i18n-report.xlsx'}}]
diff --git a/lib/i18n/tasks/command/dsl.rb b/lib/i18n/tasks/command/dsl.rb
index d8c6cf40..393f4d7e 100644
--- a/lib/i18n/tasks/command/dsl.rb
+++ b/lib/i18n/tasks/command/dsl.rb
@@ -5,22 +5,37 @@
module I18n::Tasks
module Command
module DSL
- include DSL::Cmd
- include DSL::CmdOpt
- include DSL::EnumOpt
-
- def self.extended(base)
- base.instance_variable_set :@dsl, HashWithIndifferentAccess.new { |h, k|
- h[k] = HashWithIndifferentAccess.new
- }
+ def self.included(base)
+ base.module_eval do
+ @dsl = HashWithIndifferentAccess.new { |h, k|
+ h[k] = HashWithIndifferentAccess.new
+ }
+ extend ClassMethods
+ end
end
- def included(base)
- base.instance_variable_get(:@dsl).deep_merge!(@dsl)
+ def t(*args)
+ I18n.t(*args)
end
- def dsl(key)
- @dsl[key]
+ module ClassMethods
+ include DSL::Cmd
+ include DSL::CmdOpt
+ include DSL::EnumOpt
+
+ def dsl(key)
+ @dsl[key]
+ end
+
+ # late-bound I18n.t for module bodies
+ def t(*args)
+ proc { I18n.t(*args) }
+ end
+
+ # if class is a module, merge DSL definitions when it is included
+ def included(base)
+ base.instance_variable_get(:@dsl).deep_merge!(@dsl)
+ end
end
end
end
diff --git a/lib/i18n/tasks/command/options/common.rb b/lib/i18n/tasks/command/options/common.rb
index 4370758d..8781e109 100644
--- a/lib/i18n/tasks/command/options/common.rb
+++ b/lib/i18n/tasks/command/options/common.rb
@@ -5,7 +5,7 @@ module I18n::Tasks
module Command
module Options
module Common
- extend Command::DSL
+ include Command::DSL
include Options::EnumOpt
include Options::ListOpt
@@ -14,28 +14,28 @@ module Common
cmd_opt :nostdin, {
short: :S,
long: :nostdin,
- desc: proc { I18n.t('i18n_tasks.cmd.args.desc.nostdin') },
+ desc: t('i18n_tasks.cmd.args.desc.nostdin'),
conf: {default: false}
}
cmd_opt :confirm, {
short: :y,
long: :confirm,
- desc: proc { I18n.t('i18n_tasks.cmd.args.desc.confirm') },
+ desc: t('i18n_tasks.cmd.args.desc.confirm'),
conf: {default: false}
}
cmd_opt :pattern, {
short: :p,
long: :pattern=,
- desc: proc { I18n.t('i18n_tasks.cmd.args.desc.key_pattern') },
+ desc: t('i18n_tasks.cmd.args.desc.key_pattern'),
conf: {argument: true, optional: false}
}
cmd_opt :value, {
short: :v,
long: :value=,
- desc: proc { I18n.t('i18n_tasks.cmd.args.desc.value') },
+ desc: t('i18n_tasks.cmd.args.desc.value'),
conf: {argument: true, optional: false}
}
diff --git a/lib/i18n/tasks/command/options/locales.rb b/lib/i18n/tasks/command/options/locales.rb
index 219db299..f524a60c 100644
--- a/lib/i18n/tasks/command/options/locales.rb
+++ b/lib/i18n/tasks/command/options/locales.rb
@@ -2,12 +2,12 @@ module I18n::Tasks
module Command
module Options
module Locales
- extend Command::DSL
+ include Command::DSL
cmd_opt :locales, {
short: :l,
long: :locales=,
- desc: proc { I18n.t('i18n_tasks.cmd.args.desc.locales_filter') },
+ desc: t('i18n_tasks.cmd.args.desc.locales_filter'),
conf: {as: Array, delimiter: /\s*[+:,]\s*/, default: 'all', argument: true, optional: false},
parse: :parse_locales
}
@@ -15,7 +15,7 @@ module Locales
cmd_opt :locale, {
short: :l,
long: :locale=,
- desc: proc { I18n.t('i18n_tasks.cmd.args.desc.locale') },
+ desc: t('i18n_tasks.cmd.args.desc.locale'),
conf: {default: 'base', argument: true, optional: false},
parse: :parse_locale
}
@@ -23,7 +23,7 @@ module Locales
cmd_opt :locale_to_translate_from, cmd_opt(:locale).merge(
short: :f,
long: :from=,
- desc: proc { I18n.t('i18n_tasks.cmd.args.desc.locale_to_translate_from') })
+ desc: t('i18n_tasks.cmd.args.desc.locale_to_translate_from'))
def parse_locales(opt, key = :locales)
argv = Array(opt[:arguments]) + Array(opt[key])
diff --git a/lib/i18n/tasks/command/options/trees.rb b/lib/i18n/tasks/command/options/trees.rb
index b2ff23cc..db5ceddf 100644
--- a/lib/i18n/tasks/command/options/trees.rb
+++ b/lib/i18n/tasks/command/options/trees.rb
@@ -2,7 +2,7 @@ module I18n::Tasks
module Command
module Options
module Trees
- extend Command::DSL
+ include Command::DSL
format_opt = proc { |type|
enum_opt_attr :f, :format=, enum_opt(type),
proc { |valid, default|
@@ -29,7 +29,7 @@ def print_forest(forest, opt, version = :show_tree)
when 'keys'
puts forest.key_names(root: true)
when *enum_opt(:data_format)
- puts i18n.data.adapter_dump forest, format
+ puts i18n.data.adapter_dump forest.to_hash(true), format
end
end
diff --git a/lib/i18n/tasks/commands.rb b/lib/i18n/tasks/commands.rb
index 44c309a8..937a3d4f 100644
--- a/lib/i18n/tasks/commands.rb
+++ b/lib/i18n/tasks/commands.rb
@@ -13,7 +13,7 @@
module I18n::Tasks
class Commands < Command::Commander
- extend Command::DSL
+ include Command::DSL
include Command::Commands::Health
include Command::Commands::Missing
include Command::Commands::Usages
diff --git a/lib/i18n/tasks/console_context.rb b/lib/i18n/tasks/console_context.rb
index 60c4fd81..330946d6 100644
--- a/lib/i18n/tasks/console_context.rb
+++ b/lib/i18n/tasks/console_context.rb
@@ -18,7 +18,7 @@ def start
IRB.setup nil
ctx = IRB::Irb.new.context
IRB.conf[:MAIN_CONTEXT] = ctx
- STDERR.puts Messages.banner
+ $stderr.puts Messages.banner
require 'irb/ext/multi-irb'
IRB.irb nil, new
end
diff --git a/lib/i18n/tasks/data/file_formats.rb b/lib/i18n/tasks/data/file_formats.rb
index e3f5839c..34c0d536 100644
--- a/lib/i18n/tasks/data/file_formats.rb
+++ b/lib/i18n/tasks/data/file_formats.rb
@@ -40,7 +40,7 @@ def load_file(path)
def write_tree(path, tree)
::FileUtils.mkpath(File.dirname path)
::File.open(path, 'w') { |f|
- f.write adapter_dump(tree.to_hash, self.class.adapter_name_for_path(path))
+ f.write adapter_dump(tree.to_hash(true), self.class.adapter_name_for_path(path))
}
end
diff --git a/lib/i18n/tasks/data/tree/node.rb b/lib/i18n/tasks/data/tree/node.rb
index fe2e9ed3..be4914dd 100644
--- a/lib/i18n/tasks/data/tree/node.rb
+++ b/lib/i18n/tasks/data/tree/node.rb
@@ -127,9 +127,9 @@ def to_siblings
parent && parent.children || Siblings.new(nodes: [self])
end
- def to_hash
- @hash ||= begin
- children_hash = (children || {}).map(&:to_hash).reduce(:deep_merge) || {}
+ def to_hash(sort = false)
+ (@hash ||= {})[sort] ||= begin
+ children_hash = children ? children.to_hash(sort) : {}
if key.nil?
children_hash
elsif leaf?
@@ -144,13 +144,13 @@ def to_hash
delegate :to_yaml, to: :to_hash
def inspect(level = 0)
- if key.nil?
- label = Term::ANSIColor.dark '∅'
- else
- label = [Term::ANSIColor.color(1 + level % 15, self.key),
- (": #{Term::ANSIColor.cyan(self.value.to_s)}" if leaf?),
- (" #{self.data}" if data?)].compact.join
- end
+ label = if key.nil?
+ Term::ANSIColor.dark '∅'
+ else
+ [Term::ANSIColor.color(1 + level % 15, key),
+ (": #{Term::ANSIColor.cyan(value.to_s)}" if leaf?),
+ (" #{data}" if data?)].compact.join
+ end
[' ' * level, label, ("\n" + children.map { |c| c.inspect(level + 1) }.join("\n") if children?)].compact.join
end
diff --git a/lib/i18n/tasks/data/tree/nodes.rb b/lib/i18n/tasks/data/tree/nodes.rb
index 0c664a39..be9d2610 100644
--- a/lib/i18n/tasks/data/tree/nodes.rb
+++ b/lib/i18n/tasks/data/tree/nodes.rb
@@ -29,8 +29,14 @@ def derive(new_attr = {})
self.class.new(attr)
end
- def to_hash
- @hash ||= map(&:to_hash).reduce(:deep_merge!) || {}
+ def to_hash(sort = false)
+ (@hash ||= {})[sort] ||= begin
+ if sort
+ self.sort { |a, b| a.key <=> b.key }
+ else
+ self
+ end.map { |node| node.to_hash(sort) }.reduce({}, :deep_merge!)
+ end
end
delegate :to_json, to: :to_hash
@@ -40,7 +46,7 @@ def inspect
if present?
map(&:inspect) * "\n"
else
- Term::ANSIColor.dark '∅'
+ Term::ANSIColor.dark '{∅}'
end
end
diff --git a/lib/i18n/tasks/data/tree/siblings.rb b/lib/i18n/tasks/data/tree/siblings.rb
index b44b3f45..c20ab235 100644
--- a/lib/i18n/tasks/data/tree/siblings.rb
+++ b/lib/i18n/tasks/data/tree/siblings.rb
@@ -45,7 +45,7 @@ def replace_node!(node, new_node)
key_to_node[new_node.key] = new_node
end
- include SplitKey
+ include ::I18n::Tasks::SplitKey
# @return [Node] by full key
def get(full_key)
@@ -110,22 +110,7 @@ def append(nodes)
def merge!(nodes)
nodes = Siblings.from_nested_hash(nodes) if nodes.is_a?(Hash)
nodes.each do |node|
- if key_to_node.key?(node.key)
- our = key_to_node[node.key]
- next if our == node
- our.value = node.value if node.leaf?
- our.data.merge!(node.data) if node.data?
- if node.children?
- if our.children
- our.children.merge!(node.children)
- else
- warn_add_children_to_leaf our
- our.children = node.children
- end
- end
- else
- key_to_node[node.key] = node.derive(parent: parent)
- end
+ merge_node! node
end
@list = key_to_node.values
dirty!
@@ -161,12 +146,31 @@ def set_root_key!(new_key, data = nil)
private
+ def merge_node!(node)
+ if key_to_node.key?(node.key)
+ our = key_to_node[node.key]
+ return if our == node
+ our.value = node.value if node.leaf?
+ our.data.merge!(node.data) if node.data?
+ if node.children?
+ if our.children
+ our.children.merge!(node.children)
+ else
+ warn_add_children_to_leaf our
+ our.children = node.children
+ end
+ end
+ else
+ key_to_node[node.key] = node.derive(parent: parent)
+ end
+ end
+
def warn_add_children_to_leaf(node)
::I18n::Tasks::Logging.log_warn "'#{node.full_key}' was a leaf, now has children (value <- scope conflict)"
end
class << self
- include SplitKey
+ include ::I18n::Tasks::SplitKey
def null
new
diff --git a/lib/i18n/tasks/data/tree/traversal.rb b/lib/i18n/tasks/data/tree/traversal.rb
index 3a752623..b0e5e17b 100644
--- a/lib/i18n/tasks/data/tree/traversal.rb
+++ b/lib/i18n/tasks/data/tree/traversal.rb
@@ -21,7 +21,11 @@ def levels(&block)
nodes = to_nodes
unless nodes.empty?
block.yield nodes
- Nodes.new(nodes.children).levels(&block)
+ if nodes.children.size == 1
+ first.children
+ else
+ Nodes.new(nodes: nodes.children)
+ end.levels(&block)
end
self
end
diff --git a/lib/i18n/tasks/google_translation.rb b/lib/i18n/tasks/google_translation.rb
index 46745f4c..a4bc2f03 100644
--- a/lib/i18n/tasks/google_translation.rb
+++ b/lib/i18n/tasks/google_translation.rb
@@ -5,6 +5,9 @@
module I18n::Tasks
module GoogleTranslation
+ # @param [I18n::Tasks::Tree::Siblings] forest to translate to the locales of its root nodes
+ # @param [String] from locale
+ # @return [I18n::Tasks::Tree::Siblings] translated forest
def google_translate_forest(forest, from)
forest.inject empty_forest do |result, root|
translated = google_translate_list(root.key_values(root: true), to: root.key, from: from)
@@ -12,7 +15,8 @@ def google_translate_forest(forest, from)
end
end
- # @param [Array] list of [key, value] pairs
+ # @param [Array<[String, Object]>] list of key-value pairs
+ # @return [Array<[String, Object]>] translated list
def google_translate_list(list, opts)
return [] if list.empty?
opts = opts.dup
@@ -26,6 +30,8 @@ def google_translate_list(list, opts)
result
end
+ # @param [Array<[String, Object]>] list of key-value pairs
+ # @return [Array<[String, Object]>] translated list
def fetch_google_translations(list, opts)
from_values(list, EasyTranslate.translate(to_values(list), opts)).tap do |result|
if result.blank?
@@ -38,21 +44,27 @@ def fetch_google_translations(list, opts)
def validate_google_translate_api_key!(key)
if key.blank?
- raise CommandError.new('Set Google API key via GOOGLE_TRANSLATE_API_KEY environment variable or translation.api_key in config/i18n-tasks.yml.
-Get the key at https://code.google.com/apis/console.')
+ raise CommandError.new(I18n.t('i18n_tasks.google_translate.errors.no_api_key'))
end
end
+ # @param [Array<[String, Object]>] list of key-value pairs
+ # @return [Array] values for translation extracted from list
def to_values(list)
list.map { |l| dump_value l[1] }.flatten.compact
end
+ # @param [Array<[String, Object]>] list of key-value pairs
+ # @param [Array] list of translated values
+ # @return [Array<[String, Object]>] translated key-value pairs
def from_values(list, translated_values)
keys = list.map(&:first)
untranslated_values = list.map(&:last)
keys.zip parse_value(untranslated_values, translated_values.to_enum)
end
+ # Prepare value for translation.
+ # @return [String, Array, nil] value for Google Translate or nil for non-string values
def dump_value(value)
case value
when Array
@@ -61,10 +73,14 @@ def dump_value(value)
when String
replace_interpolations value
else
- value
+ nil
end
end
+ # Parse translated value from the each_translated enumerator
+ # @param [Object] untranslated
+ # @param [Enumerator] each_translated
+ # @return [Object] final translated value
def parse_value(untranslated, each_translated)
case untranslated
when Array
@@ -72,10 +88,8 @@ def parse_value(untranslated, each_translated)
untranslated.map { |from| parse_value(from, each_translated) }
when String
restore_interpolations untranslated, each_translated.next
- when NilClass
- nil
else
- each_translated.next
+ untranslated
end
rescue Exception => e
puts "Exception: #{e.to_s}\n\n"
@@ -100,7 +114,8 @@ def parse_value(untranslated, each_translated)
INTERPOLATION_KEY_RE_TMP => UNTRANSLATABLE_STRING_TMP
}
- # 'hello, %{name}' => 'hello, '
+ # @param [String] value
+ # @return [String] 'hello, %{name}' => 'hello, '
def replace_interpolations(value)
if value =~ INTERPOLATION_KEY_RE
value.gsub INTERPOLATION_KEY_RE, UNTRANSLATABLE_STRING
@@ -113,6 +128,9 @@ def replace_interpolations(value)
end
end
+ # @param [String] untranslated
+ # @param [String] translated
+ # @return [String] 'hello, ' => 'hello, %{name}'
def restore_interpolations(untranslated, translated)
return translated if (untranslated !~ INTERPOLATION_KEY_RE && untranslated !~ INTERPOLATION_KEY_RE_JS && untranslated !~ INTERPOLATION_KEY_RE_TMP)
diff --git a/lib/i18n/tasks/logging.rb b/lib/i18n/tasks/logging.rb
index 1296106b..e7ae526b 100644
--- a/lib/i18n/tasks/logging.rb
+++ b/lib/i18n/tasks/logging.rb
@@ -21,6 +21,6 @@ def log_error(message)
end
def log_stderr(*args)
- STDERR.puts(*args)
+ $stderr.puts(*args)
end
end
diff --git a/lib/i18n/tasks/reports/terminal.rb b/lib/i18n/tasks/reports/terminal.rb
index 533ce964..d899928f 100644
--- a/lib/i18n/tasks/reports/terminal.rb
+++ b/lib/i18n/tasks/reports/terminal.rb
@@ -125,7 +125,7 @@ def key_occurrence(full_key, info)
def highlight_key(full_key, line, range = (0..-1))
result = line.dup
- result[range] = result[range].sub!(full_key) { |m| underline m }
+ result[range] = result[range].sub(full_key) { |m| underline m }
result
end
diff --git a/lib/i18n/tasks/scanners/base_scanner.rb b/lib/i18n/tasks/scanners/base_scanner.rb
index 67995c16..667b164c 100644
--- a/lib/i18n/tasks/scanners/base_scanner.rb
+++ b/lib/i18n/tasks/scanners/base_scanner.rb
@@ -8,7 +8,7 @@ class BaseScanner
include ::I18n::Tasks::KeyPatternMatching
include ::I18n::Tasks::Logging
- attr_reader :config, :key_filter, :ignore_lines_re
+ attr_reader :config, :key_filter, :ignore_lines_res
def initialize(config = {})
@config = config.dup.with_indifferent_access.tap do |conf|
@@ -21,14 +21,25 @@ def initialize(config = {})
# exclude common binary extensions by default (images and fonts)
conf[:exclude] = %w(*.jpg *.png *.gif *.svg *.ico *.eot *.ttf *.woff *.pdf)
end
- conf[:ignore_lines] ||= %q(^\s*[#/](?!\si18n-tasks-use)).freeze
- conf[:ignore_lines] = Array(conf[:ignore_lines])
- @ignore_lines_re = conf[:ignore_lines].map { |line| Regexp.new(line) }
+ # Regexps for lines to ignore per extension
+ if conf[:ignore_lines] && !conf[:ignore_lines].is_a?(Hash)
+ warn_deprecated "search.ignore_lines must be a Hash, found #{conf[:ignore_lines].class.name}"
+ conf[:ignore_lines] = nil
+ end
+ conf[:ignore_lines] ||= {
+ 'rb' => %q(^\s*#(?!\si18n-tasks-use)),
+ 'haml' => %q(^\s*-\s*#(?!\si18n-tasks-use)),
+ 'slim' => %q(^\s*(?:-#|/)(?!\si18n-tasks-use)),
+ 'erb' => %q(^\s*<%\s*#(?!\si18n-tasks-use)),
+ }
+ @ignore_lines_res = conf[:ignore_lines].inject({}) { |h, (ext, re)| h.update(ext => Regexp.new(re)) }
+ @key_filter = nil
end
end
- def exclude_line?(line)
- ignore_lines_re.any? { |re| re =~ line }
+ def exclude_line?(line, path)
+ re = ignore_lines_res[File.extname(path)[1..-1]]
+ re && re =~ line
end
def key_filter=(value)
diff --git a/lib/i18n/tasks/scanners/pattern_scanner.rb b/lib/i18n/tasks/scanners/pattern_scanner.rb
index 36e17e45..1ad7ca91 100644
--- a/lib/i18n/tasks/scanners/pattern_scanner.rb
+++ b/lib/i18n/tasks/scanners/pattern_scanner.rb
@@ -17,7 +17,7 @@ def scan_file(path, opts = {})
next unless valid_key?(key, strict)
key = key + ':' if key.end_with?('.')
location = src_location(path, text, src_pos)
- unless exclude_line?(location[:line])
+ unless exclude_line?(location[:line], path)
keys << [key, data: location]
end
end
diff --git a/lib/i18n/tasks/split_key.rb b/lib/i18n/tasks/split_key.rb
index 70772aef..96bd4a78 100644
--- a/lib/i18n/tasks/split_key.rb
+++ b/lib/i18n/tasks/split_key.rb
@@ -1,65 +1,69 @@
-module SplitKey
- extend self
+module I18n
+ module Tasks
+ module SplitKey
+ extend self
- # split a key by dots (.)
- # dots inside braces or parenthesis are not split on
- #
- # split_key 'a.b' # => ['a', 'b']
- # split_key 'a.#{b.c}' # => ['a', '#{b.c}']
- # split_key 'a.b.c', 2 # => ['a', 'b.c']
- def split_key(key, max = Float::INFINITY)
- parts = []
- pos = 0
- return [key] if max == 1
- key_parts(key) do |part|
- parts << part
- pos += part.length + 1
- if parts.length + 1 >= max
- parts << key.from(pos) unless pos == key.length
- break
+ # split a key by dots (.)
+ # dots inside braces or parenthesis are not split on
+ #
+ # split_key 'a.b' # => ['a', 'b']
+ # split_key 'a.#{b.c}' # => ['a', '#{b.c}']
+ # split_key 'a.b.c', 2 # => ['a', 'b.c']
+ def split_key(key, max = Float::INFINITY)
+ parts = []
+ pos = 0
+ return [key] if max == 1
+ key_parts(key) do |part|
+ parts << part
+ pos += part.length + 1
+ if parts.length + 1 >= max
+ parts << key.from(pos) unless pos == key.length
+ break
+ end
+ end
+ parts
end
- end
- parts
- end
- def last_key_part(key)
- last = nil
- key_parts(key) { |part| last = part }
- last
- end
+ def last_key_part(key)
+ last = nil
+ key_parts(key) { |part| last = part }
+ last
+ end
- # yield each key part
- # dots inside braces or parenthesis are not split on
- def key_parts(key, &block)
- return enum_for(:key_parts, key) unless block
- nesting = PARENS
- counts = PARENS_ZEROS # dup'd later if key contains parenthesis
- delim = '.'.freeze
- from = to = 0
- key.each_char do |char|
- if char == delim && PARENS_ZEROS == counts
- block.yield key[from...to]
- from = to = (to + 1)
- else
- nest_i, nest_inc = nesting[char]
- if nest_i
- counts = counts.dup if counts.frozen?
- counts[nest_i] += nest_inc
+ # yield each key part
+ # dots inside braces or parenthesis are not split on
+ def key_parts(key, &block)
+ return enum_for(:key_parts, key) unless block
+ nesting = PARENS
+ counts = PARENS_ZEROS # dup'd later if key contains parenthesis
+ delim = '.'.freeze
+ from = to = 0
+ key.each_char do |char|
+ if char == delim && PARENS_ZEROS == counts
+ block.yield key[from...to]
+ from = to = (to + 1)
+ else
+ nest_i, nest_inc = nesting[char]
+ if nest_i
+ counts = counts.dup if counts.frozen?
+ counts[nest_i] += nest_inc
+ end
+ to += 1
+ end
end
- to += 1
+ block.yield(key[from...to]) if from < to && to <= key.length
+ true
end
+
+ PARENS = %w({} [] ()).inject({}) { |h, s|
+ i = h.size / 2
+ h[s[0].freeze] = [i, 1].freeze
+ h[s[1].freeze] = [i, -1].freeze
+ h
+ }.freeze
+ PARENS_ZEROS = Array.new(PARENS.size, 0).freeze
+ private_constant :PARENS
+ private_constant :PARENS_ZEROS
end
- block.yield(key[from...to]) if from < to && to <= key.length
- true
end
-
- PARENS = %w({} [] ()).inject({}) { |h, s|
- i = h.size / 2
- h[s[0].freeze] = [i, 1].freeze
- h[s[1].freeze] = [i, -1].freeze
- h
- }.freeze
- PARENS_ZEROS = Array.new(PARENS.size, 0).freeze
- private_constant :PARENS
- private_constant :PARENS_ZEROS
end
diff --git a/lib/i18n/tasks/version.rb b/lib/i18n/tasks/version.rb
index bcf4eac6..a5ca223c 100644
--- a/lib/i18n/tasks/version.rb
+++ b/lib/i18n/tasks/version.rb
@@ -1,6 +1,6 @@
# coding: utf-8
module I18n
module Tasks
- VERSION = '0.7.5'
+ VERSION = '0.7.8'
end
end
diff --git a/spec/commands/data_commands_spec.rb b/spec/commands/data_commands_spec.rb
index 24a9d46a..5d142b71 100644
--- a/spec/commands/data_commands_spec.rb
+++ b/spec/commands/data_commands_spec.rb
@@ -20,7 +20,7 @@ def en_data_2
end
it '#data' do
- expect(JSON.parse(run_cmd :data, format: 'json')).to eq(en_data)
+ expect(JSON.parse(run_cmd :data, format: 'json', locales: 'en')).to eq(en_data)
end
it '#data-merge' do
diff --git a/spec/google_translate_spec.rb b/spec/google_translate_spec.rb
index c77707bb..1fba2d32 100644
--- a/spec/google_translate_spec.rb
+++ b/spec/google_translate_spec.rb
@@ -9,7 +9,8 @@
nil_value_test = ['nil-value-key', nil, nil],
text_test = ['key', "Hello - %{user} O'neill!", "Hola - %{user} O'neill!"],
html_test = ['html-key.html', "Hello - %{user} O'neill", "Hola - %{user} O'neill"],
- array_test = ['array-key', ['Hello.', nil, '', 'Goodbye.'], ['Hola.', nil, '', 'Adiós.']],
+ array_test = ['array-key', ['Hello.', nil, '', 'Goodbye.'], ['Hola.', nil, '', '¡Adiós.']],
+ fixnum_test = ['numeric-key', 1, 1],
handlebars_test = ['handlebars-key', "Hello {{username}}!", "Hola {{username}}!"],
template_test = ['template-key', "Hello [username]!", "Hola [username]!"],
newline_test = ['newline-key', "Hello %{user},\n\nWelcome to %{sitename}.", "Hola %{user},\n\nBienvenido a %{sitename}."]
@@ -49,6 +50,7 @@
'hello_html' => html_test[1],
'array_key' => array_test[1],
'nil-value-key' => nil_value_test[1],
+ 'fixnum-key' => fixnum_test[1],
'handlebars_key' => handlebars_test[1],
'template_key' => template_test[1],
'newline_key' => newline_test[1]
@@ -64,7 +66,8 @@
expect(task.t('common.hello', 'es')).to eq(text_test[2])
expect(task.t('common.hello_html', 'es')).to eq(html_test[2])
expect(task.t('common.array_key', 'es')).to eq(array_test[2])
- expect(task.t('nil-value-key', 'es')).to eq(nil_value_test[2])
+ expect(task.t('common.nil-value-key', 'es')).to eq(nil_value_test[2])
+ expect(task.t('common.fixnum-key', 'es')).to eq(fixnum_test[2])
expect(task.t('common.handlebars_key', 'es')).to eq(handlebars_test[2])
expect(task.t('common.template_key', 'es')).to eq(template_test[2])
expect(task.t('common.newline_key', 'es')).to eq(newline_test[2])
diff --git a/spec/i18n_spec.rb b/spec/i18n_spec.rb
index 0475c9fc..c1b7aeef 100644
--- a/spec/i18n_spec.rb
+++ b/spec/i18n_spec.rb
@@ -8,11 +8,11 @@
it 'does not have missing keys' do
expect(missing_keys).to be_empty,
- "Missing #{missing_keys.leaves.count} i18n keys, run `i18n-tasks missing' to show them"
+ "Missing #{missing_keys.leaves.count} i18n keys, run `i18n-tasks missing' to show them"
end
it 'does not have unused keys' do
- expect(i18n.unused_keys).to be_empty,
- "#{unused_keys.leaves.count} unused i18n keys, run `i18n-tasks unused' to show them"
+ expect(unused_keys).to be_empty,
+ "#{unused_keys.leaves.count} unused i18n keys, run `i18n-tasks unused' to show them"
end
end
diff --git a/spec/i18n_tasks_spec.rb b/spec/i18n_tasks_spec.rb
index 6612d0e6..b3f7af0e 100644
--- a/spec/i18n_tasks_spec.rb
+++ b/spec/i18n_tasks_spec.rb
@@ -5,6 +5,17 @@
describe 'i18n-tasks' do
delegate :run_cmd, :i18n_task, :in_test_app_dir, to: :TestCodebase
+ describe 'health' do
+ it 'outputs stats' do
+ t = i18n_task
+ stats = in_test_app_dir { t.forest_stats(t.data_forest t.locales) }
+ out = capture_stderr { run_cmd :health }
+ stats.values.each do |v|
+ expect(out).to include(v.to_s)
+ end
+ end
+ end
+
describe 'missing' do
let (:expected_missing_keys) {
%w( en.used_but_missing.key en.relative.index.missing
@@ -57,7 +68,7 @@
it 'removes unused' do
in_test_app_dir do
t = i18n_task
- unused = expected_unused_keys.map { |k| SplitKey.split_key(k, 2)[1] }
+ unused = expected_unused_keys.map { |k| ::I18n::Tasks::SplitKey.split_key(k, 2)[1] }
unused.each do |key|
expect(t.key_value?(key, :en)).to be true
expect(t.key_value?(key, :es)).to be true
@@ -76,6 +87,21 @@
end
describe 'normalize' do
+ it 'sorts the keys' do
+ in_test_app_dir do
+ run_cmd :normalize
+ en_yml_data = i18n_task.data.reload['en'].select_keys { |_k, node|
+ node.data[:path] == 'config/locales/en.yml'
+ }
+ expect(en_yml_data).to be_present
+ en_yml_data.nodes { |nodes|
+ next unless nodes.children
+ keys = nodes.children.map(&:key)
+ expect(keys).to eq keys.sort
+ }
+ end
+ end
+
it 'moves keys to the corresponding files as per data.write' do
in_test_app_dir {
expect(File).to_not exist 'config/locales/devise.en.yml'
diff --git a/spec/locale_tree/siblings_spec.rb b/spec/locale_tree/siblings_spec.rb
index 5094f24f..46492180 100644
--- a/spec/locale_tree/siblings_spec.rb
+++ b/spec/locale_tree/siblings_spec.rb
@@ -87,5 +87,10 @@
t['a.b.c.' + node.key] = node
expect(t['a.b.c.d'].value).to eq('e')
end
+
+ it '#inspect' do
+ expect(build_tree(a_hash).inspect).to eq "a: 1\nb\n ba: 1\n bb: 2"
+ expect(build_tree({}).inspect).to eq '{∅}'
+ end
end
end
diff --git a/spec/split_key_spec.rb b/spec/split_key_spec.rb
index 9ee12bf2..7bbc659c 100644
--- a/spec/split_key_spec.rb
+++ b/spec/split_key_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
describe 'SplitKey' do
- include SplitKey
+ include ::I18n::Tasks::SplitKey
[['', %w()],
['a', %w(a)],
diff --git a/spec/used_keys_spec.rb b/spec/used_keys_spec.rb
index 3ff7698d..6909107a 100644
--- a/spec/used_keys_spec.rb
+++ b/spec/used_keys_spec.rb
@@ -3,14 +3,18 @@
describe 'UsedKeys' do
let!(:task) { I18n::Tasks::BaseTask.new }
-
- around do |ex|
- task.config[:search] = {paths: ['a.html.slim']}
- TestCodebase.setup('a.html.slim' => <<-SLIM)
+ let(:file_name) { 'a.html.slim' }
+ let(:file_content) do
+ <<-SLIM
div = t 'a'
p = t 'a'
h1 = t 'b'
SLIM
+ end
+
+ around do |ex|
+ task.config[:search] = {paths: [file_name]}
+ TestCodebase.setup(file_name => file_content)
TestCodebase.in_test_app_dir { ex.run }
TestCodebase.teardown
end
@@ -45,4 +49,27 @@
[{pos: 29, line_num: 3, line_pos: 6, line: "h1 = t 'b'", src_path: 'a.html.slim'}]
)
end
+
+ describe 'when input is haml' do
+ let(:file_name) { 'a.html.haml' }
+ let(:file_content) do
+ <<-HAML
+#first{ title: t('a') }
+.second{ title: t('a') }
+- # t('a') in a comment is ignored
+ HAML
+ end
+
+ it '#used_keys(source_occurences: true)' do
+ used_keys = task.used_tree(source_occurrences: true)
+ expect(used_keys.size).to eq 1
+ expect_node_key_data(
+ used_keys.leaves.first,
+ 'a',
+ source_occurrences:
+ [{pos: 15, line_num: 1, line_pos: 16, line: "#first{ title: t('a') }", src_path: 'a.html.haml'},
+ {pos: 40, line_num: 2, line_pos: 17, line: ".second{ title: t('a') }", src_path: 'a.html.haml'}]
+ )
+ end
+ end
end
diff --git a/templates/config/i18n-tasks.yml b/templates/config/i18n-tasks.yml
index 6b561442..8d97b7da 100644
--- a/templates/config/i18n-tasks.yml
+++ b/templates/config/i18n-tasks.yml
@@ -22,7 +22,7 @@ data:
# key => file routes, matched top to bottom
write:
## E.g., write devise and simple form keys to their respective files
- # - ['{devise, simple_form}.*', 'config/locales/\1.%{locale.yml}']
+ # - ['{devise, simple_form}.*', 'config/locales/\1.%{locale}.yml']
# Catch-all
- config/locales/%{locale}.yml
# `i18n-tasks normalize -p` will force move the keys according to these rules
@@ -59,10 +59,6 @@ search:
## Or, File.fnmatch patterns to include
# include: ["*.rb", "*.html.slim"]
- ## Lines starting with # or / are ignored by default
- # ignore_lines:
- # - "^\\s*[#/](?!\\si18n-tasks-use)"
-
## Google Translate
# translation:
# # Get an API key and set billing info at https://code.google.com/apis/console to use Google Translate
@@ -70,13 +66,16 @@ search:
## Consider these keys not missing
# ignore_missing:
-# - pagination.views.*
+# - 'errors.messages.{accepted,blank,invalid,too_short,too_long}'
+# - '{devise,simple_form}.*'
## Consider these keys used
# ignore_unused:
-# - 'simple_form.{yes,no}'
-# - 'simple_form.{placeholders,hints,labels}.*'
-# - 'simple_form.{error_notification,required}.:'
+# - 'activerecord.attributes.*'
+# - '{devise,kaminari,will_paginate}.*'
+# - 'simple_form.{yes,no}'
+# - 'simple_form.{placeholders,hints,labels}.*'
+# - 'simple_form.{error_notification,required}.:'
## Exclude these keys from `i18n-tasks eq-base' report
# ignore_eq_base:
diff --git a/templates/rspec/i18n_spec.rb b/templates/rspec/i18n_spec.rb
index 0475c9fc..c1b7aeef 100644
--- a/templates/rspec/i18n_spec.rb
+++ b/templates/rspec/i18n_spec.rb
@@ -8,11 +8,11 @@
it 'does not have missing keys' do
expect(missing_keys).to be_empty,
- "Missing #{missing_keys.leaves.count} i18n keys, run `i18n-tasks missing' to show them"
+ "Missing #{missing_keys.leaves.count} i18n keys, run `i18n-tasks missing' to show them"
end
it 'does not have unused keys' do
- expect(i18n.unused_keys).to be_empty,
- "#{unused_keys.leaves.count} unused i18n keys, run `i18n-tasks unused' to show them"
+ expect(unused_keys).to be_empty,
+ "#{unused_keys.leaves.count} unused i18n keys, run `i18n-tasks unused' to show them"
end
end