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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: e4b9791c830f1768141d6d43dba65b1e3b963e90
4
- data.tar.gz: ddc91d95b7bdf1a0590af2c4175d71ac5a896fa7
3
+ metadata.gz: adc5e2843018cd679f4c0ee2b0b424e662d161e5
4
+ data.tar.gz: e0b636d1930cde221e2c72aac7b46aad29e32130
5
5
  SHA512:
6
- metadata.gz: fd0ea56aef3a916fd7f1a1ae6f51bdd83b01b69aa66f9c9ed8a38e0f82e3d59550443ac116a731227b8330f2866fc8eb69fca8841d2731c013a681f2021f9f13
7
- data.tar.gz: b4f2afc081cda21da193205db3d5f4555e41cb986c47cb9f85a29387fee4daf81d99c41436fd3a7c6be4c5510ac8f23f836fb864432d66aca96d98fb5f544452
6
+ metadata.gz: fd93fca95e142f5b01753b6841b77b1d64f22e4366e38e2777d418dafc6c3b553daacb8ecc3773a28b7816dca3d03f0dd33a10e60882e7147a8eb95c7b9ac6ea
7
+ data.tar.gz: e2ca0ffa8f077911d495ba53a704ffb1d255a801e6f076e0e1b9b194e047ae7f5d3a412f8b6cb81c27f037cf0a11f50971dadc9aed6dd0dc8a1a8016fa37f0fa
@@ -1,9 +1,9 @@
1
1
  language: ruby
2
2
  rvm:
3
- - 2.1.1
3
+ - 2.1.3
4
4
  - 2.0.0
5
5
  - 1.9.3
6
- - jruby-1.7.13
6
+ - jruby
7
7
  - rbx-2.2.10
8
8
  env:
9
9
  global:
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.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 (`config.write`)[#multiple-locale-files]:
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
- class MyCommands
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
  ```
@@ -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
@@ -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:
@@ -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
- добавлена в в https://code.google.com/apis/console.
88
+ добавлена в https://code.google.com/apis/console.
88
89
  health:
89
90
  no_keys_detected: "Ключи не обнаружены. Проверьте data.read в config/i18n-tasks.yml."
90
91
  missing:
@@ -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,7 +7,7 @@ module I18n::Tasks
7
7
  module Collection
8
8
  def self.included(base)
9
9
  base.module_eval do
10
- extend Command::DSL
10
+ include Command::DSL
11
11
  include Command::Options::Common
12
12
  include Command::Options::Locales
13
13
  include Command::Options::Trees
@@ -7,13 +7,13 @@ module I18n::Tasks
7
7
  cmd_opt :pattern_router, {
8
8
  short: :p,
9
9
  long: :pattern_router,
10
- desc: proc { I18n.t('i18n_tasks.cmd.args.desc.pattern_router') },
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: proc { I18n.t('i18n_tasks.cmd.desc.normalize') },
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: proc { I18n.t('i18n_tasks.cmd.desc.data') },
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: proc { I18n.t('i18n_tasks.cmd.desc.data_merge') },
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: proc { I18n.t('i18n_tasks.cmd.desc.data_write') },
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: proc { I18n.t('i18n_tasks.cmd.desc.data_remove') },
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,7 +6,7 @@ module I18n::Tasks
6
6
 
7
7
  cmd :eq_base,
8
8
  args: '[locale ...]',
9
- desc: proc { I18n.t('i18n_tasks.cmd.desc.eq_base') },
9
+ desc: t('i18n_tasks.cmd.desc.eq_base'),
10
10
  opt: cmd_opts(:locales, :out_format)
11
11
 
12
12
  def eq_base(opt = {})
@@ -6,14 +6,14 @@ module I18n::Tasks
6
6
 
7
7
  cmd :health,
8
8
  args: '[locale ...]',
9
- desc: proc { I18n.t('i18n_tasks.cmd.desc.health') },
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 I18n.t('i18n_tasks.health.no_keys_detected')
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: proc { I18n.t('i18n_tasks.cmd.desc.config') }
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: proc { I18n.t('i18n_tasks.cmd.desc.gem_path') }
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: I18n.t('i18n_tasks.cmd.desc.irb')
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| I18n.t('i18n_tasks.cmd.args.desc.missing_types', valid: valid, default: default) },
11
- proc { |invalid, valid| I18n.t('i18n_tasks.cmd.errors.invalid_missing_type', invalid: invalid * ', ', valid: valid * ', ', count: invalid.length) })
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: proc { I18n.t('i18n_tasks.cmd.desc.missing') },
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: proc { I18n.t('i18n_tasks.cmd.desc.translate_missing') },
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 I18n.t('i18n_tasks.translate_missing.translated', count: translated.leaves.count)
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: proc { I18n.t('i18n_tasks.cmd.desc.add_missing') },
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}. #{I18n.t('i18n_tasks.cmd.args.default_text', value: DEFAULT_ADD_MISSING_VALUE)}" })
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 I18n.t('i18n_tasks.add_missing.added', count: forest.leaves.count)
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: proc { I18n.t('i18n_tasks.cmd.desc.tree_translate') },
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: proc { I18n.t('i18n_tasks.cmd.desc.tree_merge') },
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: proc { I18n.t('i18n_tasks.cmd.desc.tree_filter') },
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: proc { I18n.t('i18n_tasks.cmd.desc.tree_rename_key') },
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
- I18n.t('i18n_tasks.cmd.args.desc.key_pattern_to_rename') }),
48
+ t('i18n_tasks.cmd.args.desc.key_pattern_to_rename') }),
49
49
  cmd_opt(:pattern).merge(short: :n, long: :name=, desc: proc {
50
- I18n.t('i18n_tasks.cmd.args.desc.new_key_name') })
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: proc { I18n.t('i18n_tasks.cmd.desc.tree_subtract') },
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: proc { I18n.t('i18n_tasks.cmd.desc.tree_set_value') },
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: proc { I18n.t('i18n_tasks.cmd.desc.tree_convert') },
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: proc { I18n.t('i18n_tasks.cmd.args.desc.strict') }
10
+ desc: t('i18n_tasks.cmd.args.desc.strict')
11
11
  }
12
12
 
13
13
  cmd :find,
14
14
  args: '[pattern]',
15
- desc: proc { I18n.t('i18n_tasks.cmd.desc.find') },
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: proc { I18n.t('i18n_tasks.cmd.desc.unused') },
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: proc { I18n.t('i18n_tasks.cmd.desc.remove_unused') },
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 I18n.t('i18n_tasks.remove_unused.removed', count: unused_keys.leaves.count)
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 I18n.t('i18n_tasks.remove_unused.noop')
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(I18n.t('i18n_tasks.remove_unused.confirm', count: unused_keys.leaves.count, locales: locales)),
57
- yellow(I18n.t('i18n_tasks.common.continue_q')),
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: proc { I18n.t('i18n_tasks.cmd.desc.xlsx_report') },
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
- include DSL::Cmd
9
- include DSL::CmdOpt
10
- include DSL::EnumOpt
11
-
12
- def self.extended(base)
13
- base.instance_variable_set :@dsl, HashWithIndifferentAccess.new { |h, k|
14
- h[k] = HashWithIndifferentAccess.new
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 included(base)
19
- base.instance_variable_get(:@dsl).deep_merge!(@dsl)
17
+ def t(*args)
18
+ I18n.t(*args)
20
19
  end
21
20
 
22
- def dsl(key)
23
- @dsl[key]
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
- extend Command::DSL
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: proc { I18n.t('i18n_tasks.cmd.args.desc.nostdin') },
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: proc { I18n.t('i18n_tasks.cmd.args.desc.confirm') },
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: proc { I18n.t('i18n_tasks.cmd.args.desc.key_pattern') },
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: proc { I18n.t('i18n_tasks.cmd.args.desc.value') },
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
- extend Command::DSL
5
+ include Command::DSL
6
6
 
7
7
  cmd_opt :locales, {
8
8
  short: :l,
9
9
  long: :locales=,
10
- desc: proc { I18n.t('i18n_tasks.cmd.args.desc.locales_filter') },
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: proc { I18n.t('i18n_tasks.cmd.args.desc.locale') },
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: proc { I18n.t('i18n_tasks.cmd.args.desc.locale_to_translate_from') })
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])
@@ -2,7 +2,7 @@ module I18n::Tasks
2
2
  module Command
3
3
  module Options
4
4
  module Trees
5
- extend Command::DSL
5
+ include Command::DSL
6
6
  format_opt = proc { |type|
7
7
  enum_opt_attr :f, :format=, enum_opt(type),
8
8
  proc { |valid, default|
@@ -13,7 +13,7 @@ require 'i18n/tasks/command/commander'
13
13
 
14
14
  module I18n::Tasks
15
15
  class Commands < Command::Commander
16
- extend Command::DSL
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 [key, value] pairs
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('Set Google API key via GOOGLE_TRANSLATE_API_KEY environment variable or translation.api_key in config/i18n-tasks.yml.
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
- value
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
- each_translated.next
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
- # 'hello, %{name}' => 'hello, <round-trippable string>'
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, :ignore_lines_re
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
- conf[:ignore_lines] ||= %q(^\s*[#/](?!\si18n-tasks-use)).freeze
25
- conf[:ignore_lines] = Array(conf[:ignore_lines])
26
- @ignore_lines_re = conf[:ignore_lines].map { |line| Regexp.new(line) }
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
- ignore_lines_re.any? { |re| re =~ line }
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
@@ -1,6 +1,6 @@
1
1
  # coding: utf-8
2
2
  module I18n
3
3
  module Tasks
4
- VERSION = '0.7.7'
4
+ VERSION = '0.7.8'
5
5
  end
6
6
  end
@@ -20,7 +20,7 @@ describe 'Data commands' do
20
20
  end
21
21
 
22
22
  it '#data' do
23
- expect(JSON.parse(run_cmd :data, format: 'json')).to eq(en_data)
23
+ expect(JSON.parse(run_cmd :data, format: 'json', locales: 'en')).to eq(en_data)
24
24
  end
25
25
 
26
26
  it '#data-merge' do
@@ -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
@@ -3,14 +3,18 @@ require 'spec_helper'
3
3
 
4
4
  describe 'UsedKeys' do
5
5
  let!(:task) { I18n::Tasks::BaseTask.new }
6
-
7
- around do |ex|
8
- task.config[:search] = {paths: ['a.html.slim']}
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
- # - pagination.views.*
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
- # - 'simple_form.{yes,no}'
78
- # - 'simple_form.{placeholders,hints,labels}.*'
79
- # - 'simple_form.{error_notification,required}.:'
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.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-09-22 00:00:00.000000000 Z
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: