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 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: