i18n-tasks 0.7.7 → 0.7.8
Sign up to get free protection for your applications and to get access to all the features.
- 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:
|