i18n-tasks 0.7.7 → 0.7.8
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/.travis.yml +2 -2
- data/CHANGES.md +6 -0
- data/README.md +4 -4
- data/config/i18n-tasks.yml +3 -4
- data/config/locales/en.yml +2 -1
- data/config/locales/ru.yml +3 -2
- data/i18n-tasks.gemspec +0 -1
- data/lib/i18n/tasks/command/collection.rb +1 -1
- data/lib/i18n/tasks/command/commands/data.rb +6 -6
- data/lib/i18n/tasks/command/commands/eq_base.rb +1 -1
- data/lib/i18n/tasks/command/commands/health.rb +2 -2
- data/lib/i18n/tasks/command/commands/meta.rb +3 -3
- data/lib/i18n/tasks/command/commands/missing.rb +8 -8
- data/lib/i18n/tasks/command/commands/tree.rb +9 -9
- data/lib/i18n/tasks/command/commands/usages.rb +8 -8
- data/lib/i18n/tasks/command/commands/xlsx.rb +1 -1
- data/lib/i18n/tasks/command/dsl.rb +27 -12
- data/lib/i18n/tasks/command/options/common.rb +5 -5
- data/lib/i18n/tasks/command/options/locales.rb +4 -4
- data/lib/i18n/tasks/command/options/trees.rb +1 -1
- data/lib/i18n/tasks/commands.rb +1 -1
- data/lib/i18n/tasks/google_translation.rb +26 -8
- data/lib/i18n/tasks/scanners/base_scanner.rb +17 -6
- data/lib/i18n/tasks/scanners/pattern_scanner.rb +1 -1
- data/lib/i18n/tasks/version.rb +1 -1
- data/spec/commands/data_commands_spec.rb +1 -1
- data/spec/google_translate_spec.rb +6 -3
- data/spec/used_keys_spec.rb +31 -4
- data/templates/config/i18n-tasks.yml +7 -8
- metadata +2 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: adc5e2843018cd679f4c0ee2b0b424e662d161e5
|
4
|
+
data.tar.gz: e0b636d1930cde221e2c72aac7b46aad29e32130
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fd93fca95e142f5b01753b6841b77b1d64f22e4366e38e2777d418dafc6c3b553daacb8ecc3773a28b7816dca3d03f0dd33a10e60882e7147a8eb95c7b9ac6ea
|
7
|
+
data.tar.gz: e2ca0ffa8f077911d495ba53a704ffb1d255a801e6f076e0e1b9b194e047ae7f5d3a412f8b6cb81c27f037cf0a11f50971dadc9aed6dd0dc8a1a8016fa37f0fa
|
data/.travis.yml
CHANGED
data/CHANGES.md
CHANGED
@@ -1,3 +1,9 @@
|
|
1
|
+
## 0.7.8
|
2
|
+
|
3
|
+
* Fix Google Translate issues with non-string keys [#100](https://github.com/glebm/i18n-tasks/pull/100)
|
4
|
+
* 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)
|
5
|
+
* Fix other minor issues
|
6
|
+
|
1
7
|
## 0.7.7
|
2
8
|
|
3
9
|
* Fix regression: keys are sorted once again [#92](https://github.com/glebm/i18n-tasks/issues/92).
|
data/README.md
CHANGED
@@ -22,7 +22,7 @@ i18n-tasks can be used with any project using [i18n][i18n-gem] (default in Rails
|
|
22
22
|
Add it to the Gemfile:
|
23
23
|
|
24
24
|
```ruby
|
25
|
-
gem 'i18n-tasks', '~> 0.7.
|
25
|
+
gem 'i18n-tasks', '~> 0.7.8'
|
26
26
|
```
|
27
27
|
|
28
28
|
Copy default [configuration file](#configuration) (optional):
|
@@ -114,7 +114,7 @@ Sort the keys:
|
|
114
114
|
$ i18n-tasks normalize
|
115
115
|
```
|
116
116
|
|
117
|
-
Sort the keys, and move them to the respective files as defined by
|
117
|
+
Sort the keys, and move them to the respective files as defined by [`config.write`](#multiple-locale-files):
|
118
118
|
|
119
119
|
```console
|
120
120
|
$ i18n-tasks normalize -p
|
@@ -408,7 +408,7 @@ Add a custom task like the ones defined by the gem:
|
|
408
408
|
|
409
409
|
```ruby
|
410
410
|
# my_commands.rb
|
411
|
-
|
411
|
+
module MyCommands
|
412
412
|
include ::I18n::Tasks::Command::Collection
|
413
413
|
cmd :my_task, desc: 'my custom task'
|
414
414
|
def my_task(opts = {})
|
@@ -419,7 +419,7 @@ end
|
|
419
419
|
```yaml
|
420
420
|
# config/i18n-tasks.yml
|
421
421
|
<%
|
422
|
-
require 'my_commands'
|
422
|
+
require './my_commands'
|
423
423
|
I18n::Tasks::Commands.send :include, MyCommands
|
424
424
|
%>
|
425
425
|
```
|
data/config/i18n-tasks.yml
CHANGED
@@ -1,5 +1,8 @@
|
|
1
1
|
# i18n-tasks works on itself! this is the internal config
|
2
2
|
|
3
|
+
# This is not the default config for new apps, but is the internal config for i18n-tasks to analyze itself.
|
4
|
+
# You can find the default config here: https://github.com/glebm/i18n-tasks/blob/master/templates/config/i18n-tasks.yml
|
5
|
+
|
3
6
|
base_locale: en
|
4
7
|
## i18n-tasks detects locales automatically from the existing locale files
|
5
8
|
## uncomment to set locales explicitly
|
@@ -59,10 +62,6 @@ search:
|
|
59
62
|
## Or, File.fnmatch patterns to include
|
60
63
|
# include: ["*.rb", "*.html.slim"]
|
61
64
|
|
62
|
-
## Lines starting with # or / are ignored by default
|
63
|
-
# ignore_lines:
|
64
|
-
# - "^\\s*[#/](?!\\si18n-tasks-use)"
|
65
|
-
|
66
65
|
## Google Translate
|
67
66
|
# translation:
|
68
67
|
# # Get an API key and set billing info at https://code.google.com/apis/console to use Google Translate
|
data/config/locales/en.yml
CHANGED
@@ -12,7 +12,6 @@ en:
|
|
12
12
|
data_format: 'Data format: %{valid_text}. %{default_text}.'
|
13
13
|
key_pattern: Filter by key pattern (e.g. 'common.*')
|
14
14
|
key_pattern_to_rename: Full key (pattern) to rename. Required
|
15
|
-
keys: List of keys separated by commas (,), spaces, or newlines.
|
16
15
|
locale: 'Locale. Default: base'
|
17
16
|
locale_to_translate_from: 'Locale to translate from (default: base)'
|
18
17
|
locales_filter: 'Comma-separated list of locale(s) to process. Default: all. Special: base.'
|
@@ -82,6 +81,8 @@ en:
|
|
82
81
|
title: Forest (%{locales})
|
83
82
|
google_translate:
|
84
83
|
errors:
|
84
|
+
no_api_key: Set Google API key via GOOGLE_TRANSLATE_API_KEY environment variable or translation.api_key
|
85
|
+
in config/i18n-tasks.yml. Get the key at https://code.google.com/apis/console.
|
85
86
|
no_results: Google Translate returned no results. Make sure billing information is set at
|
86
87
|
https://code.google.com/apis/console.
|
87
88
|
health:
|
data/config/locales/ru.yml
CHANGED
@@ -12,7 +12,6 @@ ru:
|
|
12
12
|
data_format: "Формат данных: %{valid_text}. %{default_text}."
|
13
13
|
key_pattern: "Маска ключа (например, common.*)"
|
14
14
|
key_pattern_to_rename: "Полный ключ (шаблон) для переименования. Необходимый параметр."
|
15
|
-
keys: "Список ключей, разделенных запятыми (,), пробелами или символами новой строки."
|
16
15
|
locale: "Язык. По умолчанию: base"
|
17
16
|
locale_to_translate_from: "Язык, с которого переводить (по умолчанию: base)"
|
18
17
|
locales_filter: "Список языков для обработки, разделенный запятыми (,). По умолчанию: все.
|
@@ -83,8 +82,10 @@ ru:
|
|
83
82
|
title: "Данные (%{locales}):"
|
84
83
|
google_translate:
|
85
84
|
errors:
|
85
|
+
no_api_key: Задайте ключ API Google через переменную окружения GOOGLE_TRANSLATE_API_KEY
|
86
|
+
или translation.api_key в config/i18n-tasks.yml. Получите ключ через https://code.google.com/apis/console.
|
86
87
|
no_results: Google Translate не дал результатов. Убедитесь в том, что платежная информация
|
87
|
-
добавлена в
|
88
|
+
добавлена в https://code.google.com/apis/console.
|
88
89
|
health:
|
89
90
|
no_keys_detected: "Ключи не обнаружены. Проверьте data.read в config/i18n-tasks.yml."
|
90
91
|
missing:
|
data/i18n-tasks.gemspec
CHANGED
@@ -14,7 +14,6 @@ i18n-tasks helps you find and manage missing and unused translations.
|
|
14
14
|
|
15
15
|
It analyses code statically for key usages, such as `I18n.t('some.key')`, in order to report keys that are missing or unused,
|
16
16
|
pre-fill missing keys (optionally from Google Translate), and remove unused keys.
|
17
|
-
well.
|
18
17
|
TEXT
|
19
18
|
s.post_install_message = <<-TEXT
|
20
19
|
# Install default configuration:
|
@@ -7,13 +7,13 @@ module I18n::Tasks
|
|
7
7
|
cmd_opt :pattern_router, {
|
8
8
|
short: :p,
|
9
9
|
long: :pattern_router,
|
10
|
-
desc:
|
10
|
+
desc: t('i18n_tasks.cmd.args.desc.pattern_router'),
|
11
11
|
conf: {argument: false, optional: true}
|
12
12
|
}
|
13
13
|
|
14
14
|
cmd :normalize,
|
15
15
|
args: '[locale ...]',
|
16
|
-
desc:
|
16
|
+
desc: t('i18n_tasks.cmd.desc.normalize'),
|
17
17
|
opt: cmd_opts(:locales, :pattern_router)
|
18
18
|
|
19
19
|
def normalize(opt = {})
|
@@ -22,7 +22,7 @@ module I18n::Tasks
|
|
22
22
|
|
23
23
|
cmd :data,
|
24
24
|
args: '[locale ...]',
|
25
|
-
desc:
|
25
|
+
desc: t('i18n_tasks.cmd.desc.data'),
|
26
26
|
opt: cmd_opts(:locales, :out_format)
|
27
27
|
|
28
28
|
def data(opt = {})
|
@@ -31,7 +31,7 @@ module I18n::Tasks
|
|
31
31
|
|
32
32
|
cmd :data_merge,
|
33
33
|
args: '[tree ...]',
|
34
|
-
desc:
|
34
|
+
desc: t('i18n_tasks.cmd.desc.data_merge'),
|
35
35
|
opt: cmd_opts(:data_format, :nostdin)
|
36
36
|
|
37
37
|
def data_merge(opt = {})
|
@@ -42,7 +42,7 @@ module I18n::Tasks
|
|
42
42
|
|
43
43
|
cmd :data_write,
|
44
44
|
args: '[tree]',
|
45
|
-
desc:
|
45
|
+
desc: t('i18n_tasks.cmd.desc.data_write'),
|
46
46
|
opt: cmd_opts(:data_format, :nostdin)
|
47
47
|
|
48
48
|
def data_write(opt = {})
|
@@ -53,7 +53,7 @@ module I18n::Tasks
|
|
53
53
|
|
54
54
|
cmd :data_remove,
|
55
55
|
args: '[tree]',
|
56
|
-
desc:
|
56
|
+
desc: t('i18n_tasks.cmd.desc.data_remove'),
|
57
57
|
opt: cmd_opts(:data_format, :nostdin)
|
58
58
|
|
59
59
|
def data_remove(opt = {})
|
@@ -6,14 +6,14 @@ module I18n::Tasks
|
|
6
6
|
|
7
7
|
cmd :health,
|
8
8
|
args: '[locale ...]',
|
9
|
-
desc:
|
9
|
+
desc: t('i18n_tasks.cmd.desc.health'),
|
10
10
|
opt: cmd_opts(:locales, :out_format)
|
11
11
|
|
12
12
|
def health(opt = {})
|
13
13
|
forest = i18n.data_forest(opt[:locales])
|
14
14
|
stats = i18n.forest_stats(forest)
|
15
15
|
if stats[:key_count].zero?
|
16
|
-
raise CommandError.new
|
16
|
+
raise CommandError.new t('i18n_tasks.health.no_keys_detected')
|
17
17
|
end
|
18
18
|
terminal_report.forest_stats forest, stats
|
19
19
|
missing opt
|
@@ -6,7 +6,7 @@ module I18n::Tasks
|
|
6
6
|
|
7
7
|
cmd :config,
|
8
8
|
args: '[section ...]',
|
9
|
-
desc:
|
9
|
+
desc: t('i18n_tasks.cmd.desc.config')
|
10
10
|
|
11
11
|
def config(opts = {})
|
12
12
|
cfg = i18n.config_for_inspect
|
@@ -17,13 +17,13 @@ module I18n::Tasks
|
|
17
17
|
puts cfg
|
18
18
|
end
|
19
19
|
|
20
|
-
cmd :gem_path, desc:
|
20
|
+
cmd :gem_path, desc: t('i18n_tasks.cmd.desc.gem_path')
|
21
21
|
|
22
22
|
def gem_path
|
23
23
|
puts I18n::Tasks.gem_path
|
24
24
|
end
|
25
25
|
|
26
|
-
cmd :irb, desc:
|
26
|
+
cmd :irb, desc: t('i18n_tasks.cmd.desc.irb')
|
27
27
|
|
28
28
|
def irb
|
29
29
|
require 'i18n/tasks/console_context'
|
@@ -7,12 +7,12 @@ module I18n::Tasks
|
|
7
7
|
enum_opt :missing_types, I18n::Tasks::MissingKeys.missing_keys_types
|
8
8
|
cmd_opt :missing_types, enum_list_opt_attr(
|
9
9
|
:t, :types=, enum_opt(:missing_types),
|
10
|
-
proc { |valid, default|
|
11
|
-
proc { |invalid, valid|
|
10
|
+
proc { |valid, default| t('i18n_tasks.cmd.args.desc.missing_types', valid: valid, default: default) },
|
11
|
+
proc { |invalid, valid| t('i18n_tasks.cmd.errors.invalid_missing_type', invalid: invalid * ', ', valid: valid * ', ', count: invalid.length) })
|
12
12
|
|
13
13
|
cmd :missing,
|
14
14
|
args: '[locale ...]',
|
15
|
-
desc:
|
15
|
+
desc: t('i18n_tasks.cmd.desc.missing'),
|
16
16
|
opt: cmd_opts(:locales, :out_format, :missing_types)
|
17
17
|
|
18
18
|
def missing(opt = {})
|
@@ -21,14 +21,14 @@ module I18n::Tasks
|
|
21
21
|
|
22
22
|
cmd :translate_missing,
|
23
23
|
args: '[locale ...]',
|
24
|
-
desc:
|
24
|
+
desc: t('i18n_tasks.cmd.desc.translate_missing'),
|
25
25
|
opt: cmd_opts(:locales, :locale_to_translate_from) << cmd_opt(:out_format).except(:short)
|
26
26
|
|
27
27
|
def translate_missing(opt = {})
|
28
28
|
missing = i18n.missing_diff_forest opt[:locales], opt[:from]
|
29
29
|
translated = i18n.google_translate_forest missing, opt[:from]
|
30
30
|
i18n.data.merge! translated
|
31
|
-
log_stderr
|
31
|
+
log_stderr t('i18n_tasks.translate_missing.translated', count: translated.leaves.count)
|
32
32
|
print_forest translated, opt
|
33
33
|
end
|
34
34
|
|
@@ -36,14 +36,14 @@ module I18n::Tasks
|
|
36
36
|
|
37
37
|
cmd :add_missing,
|
38
38
|
args: '[locale ...]',
|
39
|
-
desc:
|
39
|
+
desc: t('i18n_tasks.cmd.desc.add_missing'),
|
40
40
|
opt: cmd_opts(:locales, :out_format) <<
|
41
|
-
cmd_opt(:value).merge(desc: proc { "#{cmd_opt(:value)[:desc].call}. #{
|
41
|
+
cmd_opt(:value).merge(desc: proc { "#{cmd_opt(:value)[:desc].call}. #{t('i18n_tasks.cmd.args.default_text', value: DEFAULT_ADD_MISSING_VALUE)}" })
|
42
42
|
|
43
43
|
def add_missing(opt = {})
|
44
44
|
forest = i18n.missing_keys(opt).set_each_value!(opt[:value] || DEFAULT_ADD_MISSING_VALUE)
|
45
45
|
i18n.data.merge! forest
|
46
|
-
log_stderr
|
46
|
+
log_stderr t('i18n_tasks.add_missing.added', count: forest.leaves.count)
|
47
47
|
print_forest forest, opt
|
48
48
|
end
|
49
49
|
end
|
@@ -6,7 +6,7 @@ module I18n::Tasks
|
|
6
6
|
|
7
7
|
cmd :tree_translate,
|
8
8
|
args: '[tree]',
|
9
|
-
desc:
|
9
|
+
desc: t('i18n_tasks.cmd.desc.tree_translate'),
|
10
10
|
opt: cmd_opts(:locale_to_translate_from) << cmd_opt(:data_format).except(:short)
|
11
11
|
|
12
12
|
def tree_translate(opts = {})
|
@@ -18,7 +18,7 @@ module I18n::Tasks
|
|
18
18
|
|
19
19
|
cmd :tree_merge,
|
20
20
|
args: '[tree ...]',
|
21
|
-
desc:
|
21
|
+
desc: t('i18n_tasks.cmd.desc.tree_merge'),
|
22
22
|
opt: cmd_opts(:data_format, :nostdin)
|
23
23
|
|
24
24
|
def tree_merge(opts = {})
|
@@ -27,7 +27,7 @@ module I18n::Tasks
|
|
27
27
|
|
28
28
|
cmd :tree_filter,
|
29
29
|
args: '[pattern] [tree]',
|
30
|
-
desc:
|
30
|
+
desc: t('i18n_tasks.cmd.desc.tree_filter'),
|
31
31
|
opt: cmd_opts(:data_format, :pattern)
|
32
32
|
|
33
33
|
def tree_filter(opt = {})
|
@@ -42,12 +42,12 @@ module I18n::Tasks
|
|
42
42
|
|
43
43
|
cmd :tree_rename_key,
|
44
44
|
args: '<key> <name> [tree]',
|
45
|
-
desc:
|
45
|
+
desc: t('i18n_tasks.cmd.desc.tree_rename_key'),
|
46
46
|
opt: [
|
47
47
|
cmd_opt(:pattern).merge(short: :k, long: :key=, desc: proc {
|
48
|
-
|
48
|
+
t('i18n_tasks.cmd.args.desc.key_pattern_to_rename') }),
|
49
49
|
cmd_opt(:pattern).merge(short: :n, long: :name=, desc: proc {
|
50
|
-
|
50
|
+
t('i18n_tasks.cmd.args.desc.new_key_name') })
|
51
51
|
] + cmd_opts(:data_format)
|
52
52
|
|
53
53
|
def tree_rename_key(opt = {})
|
@@ -62,7 +62,7 @@ module I18n::Tasks
|
|
62
62
|
|
63
63
|
cmd :tree_subtract,
|
64
64
|
args: '[tree A] [tree B ...]',
|
65
|
-
desc:
|
65
|
+
desc: t('i18n_tasks.cmd.desc.tree_subtract'),
|
66
66
|
opt: cmd_opts(:data_format, :nostdin)
|
67
67
|
|
68
68
|
def tree_subtract(opt = {})
|
@@ -73,7 +73,7 @@ module I18n::Tasks
|
|
73
73
|
|
74
74
|
cmd :tree_set_value,
|
75
75
|
args: '[value] [tree]',
|
76
|
-
desc:
|
76
|
+
desc: t('i18n_tasks.cmd.desc.tree_set_value'),
|
77
77
|
opt: cmd_opts(:value, :data_format, :nostdin, :pattern)
|
78
78
|
|
79
79
|
def tree_set_value(opt = {})
|
@@ -87,7 +87,7 @@ module I18n::Tasks
|
|
87
87
|
|
88
88
|
cmd :tree_convert,
|
89
89
|
args: '<tree>',
|
90
|
-
desc:
|
90
|
+
desc: t('i18n_tasks.cmd.desc.tree_convert'),
|
91
91
|
opt: [cmd_opt(:data_format).merge(short: :f, long: :from=),
|
92
92
|
cmd_opt(:out_format).merge(short: :t, long: :to=)]
|
93
93
|
|
@@ -7,12 +7,12 @@ module I18n::Tasks
|
|
7
7
|
cmd_opt :strict, {
|
8
8
|
short: :s,
|
9
9
|
long: :strict,
|
10
|
-
desc:
|
10
|
+
desc: t('i18n_tasks.cmd.args.desc.strict')
|
11
11
|
}
|
12
12
|
|
13
13
|
cmd :find,
|
14
14
|
args: '[pattern]',
|
15
|
-
desc:
|
15
|
+
desc: t('i18n_tasks.cmd.desc.find'),
|
16
16
|
opt: cmd_opts(:out_format, :pattern)
|
17
17
|
|
18
18
|
def find(opt = {})
|
@@ -22,7 +22,7 @@ module I18n::Tasks
|
|
22
22
|
|
23
23
|
cmd :unused,
|
24
24
|
args: '[locale ...]',
|
25
|
-
desc:
|
25
|
+
desc: t('i18n_tasks.cmd.desc.unused'),
|
26
26
|
opt: cmd_opts(:locales, :out_format, :strict)
|
27
27
|
|
28
28
|
def unused(opt = {})
|
@@ -31,7 +31,7 @@ module I18n::Tasks
|
|
31
31
|
|
32
32
|
cmd :remove_unused,
|
33
33
|
args: '[locale ...]',
|
34
|
-
desc:
|
34
|
+
desc: t('i18n_tasks.cmd.desc.remove_unused'),
|
35
35
|
opt: cmd_opts(:locales, :out_format, :strict, :confirm)
|
36
36
|
|
37
37
|
def remove_unused(opt = {})
|
@@ -40,10 +40,10 @@ module I18n::Tasks
|
|
40
40
|
terminal_report.unused_keys(unused_keys)
|
41
41
|
confirm_remove_unused!(unused_keys, opt)
|
42
42
|
removed = i18n.data.remove_by_key!(unused_keys)
|
43
|
-
log_stderr
|
43
|
+
log_stderr t('i18n_tasks.remove_unused.removed', count: unused_keys.leaves.count)
|
44
44
|
print_forest removed, opt
|
45
45
|
else
|
46
|
-
log_stderr bold green
|
46
|
+
log_stderr bold green t('i18n_tasks.remove_unused.noop')
|
47
47
|
end
|
48
48
|
end
|
49
49
|
|
@@ -53,8 +53,8 @@ module I18n::Tasks
|
|
53
53
|
return if ENV['CONFIRM'] || opt[:confirm]
|
54
54
|
locales = bold(opt[:locales] * ', ')
|
55
55
|
msg = [
|
56
|
-
red(
|
57
|
-
yellow(
|
56
|
+
red(t('i18n_tasks.remove_unused.confirm', count: unused_keys.leaves.count, locales: locales)),
|
57
|
+
yellow(t('i18n_tasks.common.continue_q')),
|
58
58
|
yellow('(yes/no)')
|
59
59
|
] * ' '
|
60
60
|
exit 1 unless agree msg
|
@@ -6,7 +6,7 @@ module I18n::Tasks
|
|
6
6
|
|
7
7
|
cmd :xlsx_report,
|
8
8
|
args: '[locale...]',
|
9
|
-
desc:
|
9
|
+
desc: t('i18n_tasks.cmd.desc.xlsx_report'),
|
10
10
|
opt: [cmd_opt(:locales),
|
11
11
|
{short: :p, long: :path=, desc: 'Destination path', conf: {default: 'tmp/i18n-report.xlsx'}}]
|
12
12
|
|
@@ -5,22 +5,37 @@ require 'i18n/tasks/command/dsl/enum_opt'
|
|
5
5
|
module I18n::Tasks
|
6
6
|
module Command
|
7
7
|
module DSL
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
}
|
8
|
+
def self.included(base)
|
9
|
+
base.module_eval do
|
10
|
+
@dsl = HashWithIndifferentAccess.new { |h, k|
|
11
|
+
h[k] = HashWithIndifferentAccess.new
|
12
|
+
}
|
13
|
+
extend ClassMethods
|
14
|
+
end
|
16
15
|
end
|
17
16
|
|
18
|
-
def
|
19
|
-
|
17
|
+
def t(*args)
|
18
|
+
I18n.t(*args)
|
20
19
|
end
|
21
20
|
|
22
|
-
|
23
|
-
|
21
|
+
module ClassMethods
|
22
|
+
include DSL::Cmd
|
23
|
+
include DSL::CmdOpt
|
24
|
+
include DSL::EnumOpt
|
25
|
+
|
26
|
+
def dsl(key)
|
27
|
+
@dsl[key]
|
28
|
+
end
|
29
|
+
|
30
|
+
# late-bound I18n.t for module bodies
|
31
|
+
def t(*args)
|
32
|
+
proc { I18n.t(*args) }
|
33
|
+
end
|
34
|
+
|
35
|
+
# if class is a module, merge DSL definitions when it is included
|
36
|
+
def included(base)
|
37
|
+
base.instance_variable_get(:@dsl).deep_merge!(@dsl)
|
38
|
+
end
|
24
39
|
end
|
25
40
|
end
|
26
41
|
end
|
@@ -5,7 +5,7 @@ module I18n::Tasks
|
|
5
5
|
module Command
|
6
6
|
module Options
|
7
7
|
module Common
|
8
|
-
|
8
|
+
include Command::DSL
|
9
9
|
include Options::EnumOpt
|
10
10
|
include Options::ListOpt
|
11
11
|
|
@@ -14,28 +14,28 @@ module I18n::Tasks
|
|
14
14
|
cmd_opt :nostdin, {
|
15
15
|
short: :S,
|
16
16
|
long: :nostdin,
|
17
|
-
desc:
|
17
|
+
desc: t('i18n_tasks.cmd.args.desc.nostdin'),
|
18
18
|
conf: {default: false}
|
19
19
|
}
|
20
20
|
|
21
21
|
cmd_opt :confirm, {
|
22
22
|
short: :y,
|
23
23
|
long: :confirm,
|
24
|
-
desc:
|
24
|
+
desc: t('i18n_tasks.cmd.args.desc.confirm'),
|
25
25
|
conf: {default: false}
|
26
26
|
}
|
27
27
|
|
28
28
|
cmd_opt :pattern, {
|
29
29
|
short: :p,
|
30
30
|
long: :pattern=,
|
31
|
-
desc:
|
31
|
+
desc: t('i18n_tasks.cmd.args.desc.key_pattern'),
|
32
32
|
conf: {argument: true, optional: false}
|
33
33
|
}
|
34
34
|
|
35
35
|
cmd_opt :value, {
|
36
36
|
short: :v,
|
37
37
|
long: :value=,
|
38
|
-
desc:
|
38
|
+
desc: t('i18n_tasks.cmd.args.desc.value'),
|
39
39
|
conf: {argument: true, optional: false}
|
40
40
|
}
|
41
41
|
|
@@ -2,12 +2,12 @@ module I18n::Tasks
|
|
2
2
|
module Command
|
3
3
|
module Options
|
4
4
|
module Locales
|
5
|
-
|
5
|
+
include Command::DSL
|
6
6
|
|
7
7
|
cmd_opt :locales, {
|
8
8
|
short: :l,
|
9
9
|
long: :locales=,
|
10
|
-
desc:
|
10
|
+
desc: t('i18n_tasks.cmd.args.desc.locales_filter'),
|
11
11
|
conf: {as: Array, delimiter: /\s*[+:,]\s*/, default: 'all', argument: true, optional: false},
|
12
12
|
parse: :parse_locales
|
13
13
|
}
|
@@ -15,7 +15,7 @@ module I18n::Tasks
|
|
15
15
|
cmd_opt :locale, {
|
16
16
|
short: :l,
|
17
17
|
long: :locale=,
|
18
|
-
desc:
|
18
|
+
desc: t('i18n_tasks.cmd.args.desc.locale'),
|
19
19
|
conf: {default: 'base', argument: true, optional: false},
|
20
20
|
parse: :parse_locale
|
21
21
|
}
|
@@ -23,7 +23,7 @@ module I18n::Tasks
|
|
23
23
|
cmd_opt :locale_to_translate_from, cmd_opt(:locale).merge(
|
24
24
|
short: :f,
|
25
25
|
long: :from=,
|
26
|
-
desc:
|
26
|
+
desc: t('i18n_tasks.cmd.args.desc.locale_to_translate_from'))
|
27
27
|
|
28
28
|
def parse_locales(opt, key = :locales)
|
29
29
|
argv = Array(opt[:arguments]) + Array(opt[key])
|
data/lib/i18n/tasks/commands.rb
CHANGED
@@ -13,7 +13,7 @@ require 'i18n/tasks/command/commander'
|
|
13
13
|
|
14
14
|
module I18n::Tasks
|
15
15
|
class Commands < Command::Commander
|
16
|
-
|
16
|
+
include Command::DSL
|
17
17
|
include Command::Commands::Health
|
18
18
|
include Command::Commands::Missing
|
19
19
|
include Command::Commands::Usages
|
@@ -5,6 +5,9 @@ require 'i18n/tasks/html_keys'
|
|
5
5
|
module I18n::Tasks
|
6
6
|
module GoogleTranslation
|
7
7
|
|
8
|
+
# @param [I18n::Tasks::Tree::Siblings] forest to translate to the locales of its root nodes
|
9
|
+
# @param [String] from locale
|
10
|
+
# @return [I18n::Tasks::Tree::Siblings] translated forest
|
8
11
|
def google_translate_forest(forest, from)
|
9
12
|
forest.inject empty_forest do |result, root|
|
10
13
|
translated = google_translate_list(root.key_values(root: true), to: root.key, from: from)
|
@@ -12,7 +15,8 @@ module I18n::Tasks
|
|
12
15
|
end
|
13
16
|
end
|
14
17
|
|
15
|
-
# @param [Array] list of
|
18
|
+
# @param [Array<[String, Object]>] list of key-value pairs
|
19
|
+
# @return [Array<[String, Object]>] translated list
|
16
20
|
def google_translate_list(list, opts)
|
17
21
|
return [] if list.empty?
|
18
22
|
opts = opts.dup
|
@@ -26,6 +30,8 @@ module I18n::Tasks
|
|
26
30
|
result
|
27
31
|
end
|
28
32
|
|
33
|
+
# @param [Array<[String, Object]>] list of key-value pairs
|
34
|
+
# @return [Array<[String, Object]>] translated list
|
29
35
|
def fetch_google_translations(list, opts)
|
30
36
|
from_values(list, EasyTranslate.translate(to_values(list), opts)).tap do |result|
|
31
37
|
if result.blank?
|
@@ -38,21 +44,27 @@ module I18n::Tasks
|
|
38
44
|
|
39
45
|
def validate_google_translate_api_key!(key)
|
40
46
|
if key.blank?
|
41
|
-
raise CommandError.new('
|
42
|
-
Get the key at https://code.google.com/apis/console.')
|
47
|
+
raise CommandError.new(I18n.t('i18n_tasks.google_translate.errors.no_api_key'))
|
43
48
|
end
|
44
49
|
end
|
45
50
|
|
51
|
+
# @param [Array<[String, Object]>] list of key-value pairs
|
52
|
+
# @return [Array<String>] values for translation extracted from list
|
46
53
|
def to_values(list)
|
47
54
|
list.map { |l| dump_value l[1] }.flatten.compact
|
48
55
|
end
|
49
56
|
|
57
|
+
# @param [Array<[String, Object]>] list of key-value pairs
|
58
|
+
# @param [Array<String>] list of translated values
|
59
|
+
# @return [Array<[String, Object]>] translated key-value pairs
|
50
60
|
def from_values(list, translated_values)
|
51
61
|
keys = list.map(&:first)
|
52
62
|
untranslated_values = list.map(&:last)
|
53
63
|
keys.zip parse_value(untranslated_values, translated_values.to_enum)
|
54
64
|
end
|
55
65
|
|
66
|
+
# Prepare value for translation.
|
67
|
+
# @return [String, Array<String, nil>, nil] value for Google Translate or nil for non-string values
|
56
68
|
def dump_value(value)
|
57
69
|
case value
|
58
70
|
when Array
|
@@ -61,10 +73,14 @@ Get the key at https://code.google.com/apis/console.')
|
|
61
73
|
when String
|
62
74
|
replace_interpolations value
|
63
75
|
else
|
64
|
-
|
76
|
+
nil
|
65
77
|
end
|
66
78
|
end
|
67
79
|
|
80
|
+
# Parse translated value from the each_translated enumerator
|
81
|
+
# @param [Object] untranslated
|
82
|
+
# @param [Enumerator] each_translated
|
83
|
+
# @return [Object] final translated value
|
68
84
|
def parse_value(untranslated, each_translated)
|
69
85
|
case untranslated
|
70
86
|
when Array
|
@@ -72,21 +88,23 @@ Get the key at https://code.google.com/apis/console.')
|
|
72
88
|
untranslated.map { |from| parse_value(from, each_translated) }
|
73
89
|
when String
|
74
90
|
restore_interpolations untranslated, each_translated.next
|
75
|
-
when NilClass
|
76
|
-
nil
|
77
91
|
else
|
78
|
-
|
92
|
+
untranslated
|
79
93
|
end
|
80
94
|
end
|
81
95
|
|
82
96
|
INTERPOLATION_KEY_RE = /%\{[^}]+\}/.freeze
|
83
97
|
UNTRANSLATABLE_STRING = 'zxzxzx'.freeze
|
84
98
|
|
85
|
-
#
|
99
|
+
# @param [String] value
|
100
|
+
# @return [String] 'hello, %{name}' => 'hello, <round-trippable string>'
|
86
101
|
def replace_interpolations(value)
|
87
102
|
value.gsub INTERPOLATION_KEY_RE, UNTRANSLATABLE_STRING
|
88
103
|
end
|
89
104
|
|
105
|
+
# @param [String] untranslated
|
106
|
+
# @param [String] translated
|
107
|
+
# @return [String] 'hello, <round-trippable string>' => 'hello, %{name}'
|
90
108
|
def restore_interpolations(untranslated, translated)
|
91
109
|
return translated if untranslated !~ INTERPOLATION_KEY_RE
|
92
110
|
each_value = untranslated.scan(INTERPOLATION_KEY_RE).to_enum
|
@@ -8,7 +8,7 @@ module I18n::Tasks::Scanners
|
|
8
8
|
include ::I18n::Tasks::KeyPatternMatching
|
9
9
|
include ::I18n::Tasks::Logging
|
10
10
|
|
11
|
-
attr_reader :config, :key_filter, :
|
11
|
+
attr_reader :config, :key_filter, :ignore_lines_res
|
12
12
|
|
13
13
|
def initialize(config = {})
|
14
14
|
@config = config.dup.with_indifferent_access.tap do |conf|
|
@@ -21,14 +21,25 @@ module I18n::Tasks::Scanners
|
|
21
21
|
# exclude common binary extensions by default (images and fonts)
|
22
22
|
conf[:exclude] = %w(*.jpg *.png *.gif *.svg *.ico *.eot *.ttf *.woff *.pdf)
|
23
23
|
end
|
24
|
-
|
25
|
-
conf[:ignore_lines]
|
26
|
-
|
24
|
+
# Regexps for lines to ignore per extension
|
25
|
+
if conf[:ignore_lines] && !conf[:ignore_lines].is_a?(Hash)
|
26
|
+
warn_deprecated "search.ignore_lines must be a Hash, found #{conf[:ignore_lines].class.name}"
|
27
|
+
conf[:ignore_lines] = nil
|
28
|
+
end
|
29
|
+
conf[:ignore_lines] ||= {
|
30
|
+
'rb' => %q(^\s*#(?!\si18n-tasks-use)),
|
31
|
+
'haml' => %q(^\s*-\s*#\s*(?!\si18n-tasks-use)),
|
32
|
+
'slim' => %q(^\s*(?:-#|/)(?!\si18n-tasks-use)),
|
33
|
+
'erb' => %q(^\s*<%\s*#(?!\si18n-tasks-use)),
|
34
|
+
}
|
35
|
+
@ignore_lines_res = conf[:ignore_lines].inject({}) { |h, (ext, re)| h.update(ext => Regexp.new(re)) }
|
36
|
+
@key_filter = nil
|
27
37
|
end
|
28
38
|
end
|
29
39
|
|
30
|
-
def exclude_line?(line)
|
31
|
-
|
40
|
+
def exclude_line?(line, path)
|
41
|
+
re = ignore_lines_res[File.extname(path)[1..-1]]
|
42
|
+
re && re =~ line
|
32
43
|
end
|
33
44
|
|
34
45
|
def key_filter=(value)
|
@@ -17,7 +17,7 @@ module I18n::Tasks::Scanners
|
|
17
17
|
next unless valid_key?(key, strict)
|
18
18
|
key = key + ':' if key.end_with?('.')
|
19
19
|
location = src_location(path, text, src_pos)
|
20
|
-
unless exclude_line?(location[:line])
|
20
|
+
unless exclude_line?(location[:line], path)
|
21
21
|
keys << [key, data: location]
|
22
22
|
end
|
23
23
|
end
|
data/lib/i18n/tasks/version.rb
CHANGED
@@ -9,7 +9,8 @@ describe 'Google Translation' do
|
|
9
9
|
nil_value_test = ['nil-value-key', nil, nil],
|
10
10
|
text_test = ['key', "Hello - %{user} O'neill!", "Hola - %{user} O'neill!"],
|
11
11
|
html_test = ['html-key.html', "Hello - <b>%{user} O'neill</b>", "Hola - <b>%{user} O'neill</b>"],
|
12
|
-
array_test = ['array-key', ['Hello.', nil, '', 'Goodbye.'], ['Hola.', nil, '', 'Adiós.']]
|
12
|
+
array_test = ['array-key', ['Hello.', nil, '', 'Goodbye.'], ['Hola.', nil, '', 'Adiós.']],
|
13
|
+
fixnum_test = ['numeric-key', 1, 1],
|
13
14
|
]
|
14
15
|
|
15
16
|
if ENV['GOOGLE_TRANSLATE_API_KEY']
|
@@ -45,7 +46,8 @@ describe 'Google Translation' do
|
|
45
46
|
'hello' => text_test[1],
|
46
47
|
'hello_html' => html_test[1],
|
47
48
|
'array_key' => array_test[1],
|
48
|
-
'nil-value-key' => nil_value_test[1]
|
49
|
+
'nil-value-key' => nil_value_test[1],
|
50
|
+
'fixnum-key' => fixnum_test[1]
|
49
51
|
}
|
50
52
|
})
|
51
53
|
task.data[:es] = build_tree('es' => {
|
@@ -58,7 +60,8 @@ describe 'Google Translation' do
|
|
58
60
|
expect(task.t('common.hello', 'es')).to eq(text_test[2])
|
59
61
|
expect(task.t('common.hello_html', 'es')).to eq(html_test[2])
|
60
62
|
expect(task.t('common.array_key', 'es')).to eq(array_test[2])
|
61
|
-
expect(task.t('nil-value-key', 'es')).to eq(nil_value_test[2])
|
63
|
+
expect(task.t('common.nil-value-key', 'es')).to eq(nil_value_test[2])
|
64
|
+
expect(task.t('common.fixnum-key', 'es')).to eq(fixnum_test[2])
|
62
65
|
expect(task.t('common.a', 'es')).to eq('λ')
|
63
66
|
end
|
64
67
|
end
|
data/spec/used_keys_spec.rb
CHANGED
@@ -3,14 +3,18 @@ require 'spec_helper'
|
|
3
3
|
|
4
4
|
describe 'UsedKeys' do
|
5
5
|
let!(:task) { I18n::Tasks::BaseTask.new }
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
TestCodebase.setup('a.html.slim' => <<-SLIM)
|
6
|
+
let(:file_name) { 'a.html.slim' }
|
7
|
+
let(:file_content) do
|
8
|
+
<<-SLIM
|
10
9
|
div = t 'a'
|
11
10
|
p = t 'a'
|
12
11
|
h1 = t 'b'
|
13
12
|
SLIM
|
13
|
+
end
|
14
|
+
|
15
|
+
around do |ex|
|
16
|
+
task.config[:search] = {paths: [file_name]}
|
17
|
+
TestCodebase.setup(file_name => file_content)
|
14
18
|
TestCodebase.in_test_app_dir { ex.run }
|
15
19
|
TestCodebase.teardown
|
16
20
|
end
|
@@ -45,4 +49,27 @@ h1 = t 'b'
|
|
45
49
|
[{pos: 29, line_num: 3, line_pos: 6, line: "h1 = t 'b'", src_path: 'a.html.slim'}]
|
46
50
|
)
|
47
51
|
end
|
52
|
+
|
53
|
+
describe 'when input is haml' do
|
54
|
+
let(:file_name) { 'a.html.haml' }
|
55
|
+
let(:file_content) do
|
56
|
+
<<-HAML
|
57
|
+
#first{ title: t('a') }
|
58
|
+
.second{ title: t('a') }
|
59
|
+
- # t('a') in a comment is ignored
|
60
|
+
HAML
|
61
|
+
end
|
62
|
+
|
63
|
+
it '#used_keys(source_occurences: true)' do
|
64
|
+
used_keys = task.used_tree(source_occurrences: true)
|
65
|
+
expect(used_keys.size).to eq 1
|
66
|
+
expect_node_key_data(
|
67
|
+
used_keys.leaves.first,
|
68
|
+
'a',
|
69
|
+
source_occurrences:
|
70
|
+
[{pos: 15, line_num: 1, line_pos: 16, line: "#first{ title: t('a') }", src_path: 'a.html.haml'},
|
71
|
+
{pos: 40, line_num: 2, line_pos: 17, line: ".second{ title: t('a') }", src_path: 'a.html.haml'}]
|
72
|
+
)
|
73
|
+
end
|
74
|
+
end
|
48
75
|
end
|
@@ -59,10 +59,6 @@ search:
|
|
59
59
|
## Or, File.fnmatch patterns to include
|
60
60
|
# include: ["*.rb", "*.html.slim"]
|
61
61
|
|
62
|
-
## Lines starting with # or / are ignored by default
|
63
|
-
# ignore_lines:
|
64
|
-
# - "^\\s*[#/](?!\\si18n-tasks-use)"
|
65
|
-
|
66
62
|
## Google Translate
|
67
63
|
# translation:
|
68
64
|
# # Get an API key and set billing info at https://code.google.com/apis/console to use Google Translate
|
@@ -70,13 +66,16 @@ search:
|
|
70
66
|
|
71
67
|
## Consider these keys not missing
|
72
68
|
# ignore_missing:
|
73
|
-
#
|
69
|
+
# - 'errors.messages.{accepted,blank,invalid,too_short,too_long}'
|
70
|
+
# - '{devise,simple_form}.*'
|
74
71
|
|
75
72
|
## Consider these keys used
|
76
73
|
# ignore_unused:
|
77
|
-
#
|
78
|
-
#
|
79
|
-
#
|
74
|
+
# - 'activerecord.attributes.*'
|
75
|
+
# - '{devise,kaminari,will_paginate}.*'
|
76
|
+
# - 'simple_form.{yes,no}'
|
77
|
+
# - 'simple_form.{placeholders,hints,labels}.*'
|
78
|
+
# - 'simple_form.{error_notification,required}.:'
|
80
79
|
|
81
80
|
## Exclude these keys from `i18n-tasks eq-base' report
|
82
81
|
# ignore_eq_base:
|
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.7.
|
4
|
+
version: 0.7.8
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- glebm
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-10-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: erubis
|
@@ -197,7 +197,6 @@ description: |
|
|
197
197
|
|
198
198
|
It analyses code statically for key usages, such as `I18n.t('some.key')`, in order to report keys that are missing or unused,
|
199
199
|
pre-fill missing keys (optionally from Google Translate), and remove unused keys.
|
200
|
-
well.
|
201
200
|
email:
|
202
201
|
- glex.spb@gmail.com
|
203
202
|
executables:
|