i18n-tasks 0.9.4 → 0.9.5

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: 4807ae41e4ea2c7274b08bc55c2a2286a6e601d5
4
- data.tar.gz: bdc921c3485e004c0e395a79afde8a5cfcfa888c
3
+ metadata.gz: d0229b3a4c2b8749a457c6b71e412a80802a6aa3
4
+ data.tar.gz: e43c66b6e67ef86dd28fcb7d7c9875c4578c9b84
5
5
  SHA512:
6
- metadata.gz: 3b58817464f4c4878f822606dda7ae226b33f53b6542b938a272864d1d4a92806a72d81f4d16571e8176e04687784861a7c541f1ac0e92b6ce055ed46a93b8da
7
- data.tar.gz: 276c9a94d0575d383ea163a8e20d56b26248cf0c16da4caa2efd53f7530ed4632f3f264e9dcf747013db063cd19c984cd218cb60829ace938f79b6c97db7130f
6
+ metadata.gz: d370ab448ca1126486d67e810b9dab6f20ea07b5145c297a3fdbc15bf03fc6c3118434d93803b9b7ba9147b57b36f30b9582ab7af27d6d31172fe79d84157737
7
+ data.tar.gz: 0f1a783ca1d8ca7024d26f9506fc814ac6eff22ddb1141f4730567e73730c287e192a216ad5f4971d399d0df664ade82a8cf72301a1486e1cffff15b4a254bf9
data/README.md CHANGED
@@ -24,7 +24,7 @@ i18n-tasks can be used with any project using the ruby [i18n gem][i18n-gem] (def
24
24
  Add i18n-tasks to the Gemfile:
25
25
 
26
26
  ```ruby
27
- gem 'i18n-tasks', '~> 0.9.4'
27
+ gem 'i18n-tasks', '~> 0.9.5'
28
28
  ```
29
29
 
30
30
  Copy the default [configuration file](#configuration):
@@ -278,6 +278,12 @@ User.model_name.human
278
278
  ```
279
279
 
280
280
  You can also explicitly ignore keys appearing in locale files via `ignore*` settings.
281
+
282
+ If you have helper methods that generate translation keys, such as a `page_title` method that returns `t '.page_title'`,
283
+ or a `Spree.t(key)` method that returns `t "spree.#{key}"`, use the built-in `PatternMapper` to map these.
284
+
285
+ For more complex cases, you can implement a [custom scanner][custom-scanner-docs].
286
+
281
287
  See the [config file][config] to find out more.
282
288
 
283
289
  <a name="translation-config"></a>
@@ -332,3 +338,4 @@ Custom tasks can be added easily, see the examples [on the wiki](https://github.
332
338
  [screenshot-i18n-tasks]: https://i.imgur.com/XZBd8l7.png "i18n-tasks screenshot"
333
339
  [screenshot-find]: https://i.imgur.com/VxBrSfY.png "i18n-tasks find output screenshot"
334
340
  [adapter-example]: https://github.com/glebm/i18n-tasks/blob/master/lib/i18n/tasks/data/file_system_base.rb
341
+ [custom-scanner-docs]: https://github.com/glebm/i18n-tasks/wiki/A-custom-scanner-example
@@ -14,23 +14,25 @@ class I18n::Tasks::CLI
14
14
  end
15
15
 
16
16
  def start(argv)
17
- auto_output_coloring do
18
- begin
19
- if run(argv) == :exit_1
20
- exit 1
21
- end
22
- rescue OptionParser::ParseError => e
23
- error e.message, 64
24
- rescue I18n::Tasks::CommandError => e
17
+ I18n.with_locale(base_task.internal_locale) do
18
+ auto_output_coloring do
25
19
  begin
26
- error e.message, 78
27
- ensure
28
- log_verbose e.backtrace * "\n"
20
+ if run(argv) == :exit_1
21
+ exit 1
22
+ end
23
+ rescue OptionParser::ParseError => e
24
+ error e.message, 64
25
+ rescue I18n::Tasks::CommandError => e
26
+ begin
27
+ error e.message, 78
28
+ ensure
29
+ log_verbose e.backtrace * "\n"
30
+ end
31
+ rescue Errno::EPIPE
32
+ # ignore Errno::EPIPE which is throw when pipe breaks, e.g.:
33
+ # i18n-tasks missing | head
34
+ exit 1
29
35
  end
30
- rescue Errno::EPIPE
31
- # ignore Errno::EPIPE which is throw when pipe breaks, e.g.:
32
- # i18n-tasks missing | head
33
- exit 1
34
36
  end
35
37
  end
36
38
  rescue ExecutionError => e
@@ -43,7 +45,7 @@ class I18n::Tasks::CLI
43
45
  end
44
46
 
45
47
  def context
46
- @context ||= ::I18n::Tasks::Commands.new(base_task).tap(&:set_internal_locale!)
48
+ @context ||= ::I18n::Tasks::Commands.new(base_task)
47
49
  end
48
50
 
49
51
  def commands
@@ -27,10 +27,6 @@ module I18n::Tasks
27
27
  end
28
28
  end
29
29
 
30
- def set_internal_locale!
31
- I18n.locale = i18n.internal_locale
32
- end
33
-
34
30
  protected
35
31
 
36
32
  def terminal_report
@@ -45,21 +45,23 @@ module I18n::Tasks
45
45
  cmd :add_missing,
46
46
  pos: '[locale ...]',
47
47
  desc: t('i18n_tasks.cmd.desc.add_missing'),
48
- args: [:locales, :out_format, arg(:value) + [{default: '%{value_or_default_or_human_key}'}]]
48
+ args: [:locales, :out_format, arg(:value) + [{default: '%{value_or_default_or_human_key}'}],
49
+ ['--nil-value', 'Set value to nil. Takes precedence over the value argument.']]
49
50
 
50
51
  def add_missing(opt = {})
51
52
  added = i18n.empty_forest
52
53
  locales = (opt[:locales] || i18n.locales)
54
+ value = opt[:'nil-value'] ? nil : opt[:value]
53
55
  if locales[0] == i18n.base_locale
54
56
  # Merge base locale first, as this may affect the value for the other locales
55
57
  forest = i18n.missing_keys({locales: [locales[0]]}.update(opt.slice(:types, :base_locale))).
56
- set_each_value!(opt[:value])
58
+ set_each_value!(value)
57
59
  i18n.data.merge! forest
58
60
  added.merge! forest
59
61
  locales = locales[1..-1]
60
62
  end
61
63
  forest = i18n.missing_keys({locales: locales}.update(opt.slice(:types, :base_locale))).
62
- set_each_value!(opt[:value])
64
+ set_each_value!(value)
63
65
  i18n.data.merge! forest
64
66
  added.merge! forest
65
67
  log_stderr t('i18n_tasks.add_missing.added', count: added.leaves.count)
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+ require 'i18n/tasks/scanners/file_scanner'
3
+ require 'i18n/tasks/scanners/relative_keys'
4
+ require 'i18n/tasks/scanners/occurrence_from_position'
5
+ require 'i18n/tasks/scanners/ruby_key_literals'
6
+
7
+ module I18n::Tasks::Scanners
8
+ # Maps the provided patterns to keys.
9
+ class PatternMapper < FileScanner
10
+ include I18n::Tasks::Scanners::RelativeKeys
11
+ include I18n::Tasks::Scanners::OccurrenceFromPosition
12
+ include I18n::Tasks::Scanners::RubyKeyLiterals
13
+
14
+ # @param patterns [Array<[String, String]> the list of pattern-key pairs
15
+ # the patterns follow the regular expression syntax, with a syntax addition for matching
16
+ # string/symbol literals: you can include %{key} in the pattern, and it will be converted to
17
+ # a named capture group, capturing ruby strings and symbols, that can then be used in the key:
18
+ #
19
+ # patterns: [['Spree\.t[( ]\s*%{key}', 'spree.%{key}']]
20
+ #
21
+ # All of the named capture groups are interpolated into the key with %{group_name} interpolations.
22
+ #
23
+ def initialize(config:, **args)
24
+ super
25
+ @patterns = configure_patterns(config[:patterns] || [])
26
+ end
27
+
28
+ protected
29
+
30
+ # @return [Array<[absolute key, Results::Occurrence]>]
31
+ def scan_file(path)
32
+ text = read_file(path)
33
+ @patterns.flat_map do |pattern, key|
34
+ result = []
35
+ text.scan(pattern) do |_|
36
+ match = Regexp.last_match
37
+ matches = Hash[match.names.map(&:to_sym).zip(match.captures)]
38
+ if matches.key?(:key)
39
+ matches[:key] = strip_literal(matches[:key])
40
+ next unless valid_key?(matches[:key])
41
+ end
42
+ result << [absolute_key(key % matches, path),
43
+ occurrence_from_position(path, text, match.offset(0).first)]
44
+ end
45
+ result
46
+ end
47
+ end
48
+
49
+ private
50
+
51
+ KEY_GROUP = "(?<key>#{LITERAL_RE})"
52
+
53
+ def configure_patterns(patterns)
54
+ patterns.map do |(pattern, key)|
55
+ [pattern.is_a?(Regexp) ? pattern : Regexp.new(pattern % {key: KEY_GROUP}), key]
56
+ end
57
+ end
58
+ end
59
+ end
@@ -2,12 +2,14 @@
2
2
  require 'i18n/tasks/scanners/file_scanner'
3
3
  require 'i18n/tasks/scanners/relative_keys'
4
4
  require 'i18n/tasks/scanners/occurrence_from_position'
5
+ require 'i18n/tasks/scanners/ruby_key_literals'
5
6
 
6
7
  module I18n::Tasks::Scanners
7
8
  # Scan for I18n.t usages using a simple regular expression.
8
9
  class PatternScanner < FileScanner
9
10
  include RelativeKeys
10
11
  include OccurrenceFromPosition
12
+ include RubyKeyLiterals
11
13
 
12
14
  def initialize(**args)
13
15
  super
@@ -50,26 +52,13 @@ module I18n::Tasks::Scanners
50
52
  re && re =~ line
51
53
  end
52
54
 
53
- # remove the leading colon and unwrap quotes from the key match
54
- # @param literal [String] e.g: "key", 'key', or :key.
55
- # @return [String] key
56
- def strip_literal(literal)
57
- key = literal
58
- key = key[1..-1] if ':'.freeze == key[0]
59
- key = key[1..-2] if QUOTES.include?(key[0])
60
- key
61
- end
62
-
63
- QUOTES = ["'".freeze, '"'.freeze].freeze
64
- VALID_KEY_CHARS = /(?:[[:word:]]|[-.?!;À-ž])/
65
- VALID_KEY_RE_STRICT = /^#{VALID_KEY_CHARS}+$/
66
- VALID_KEY_RE = /^(#{VALID_KEY_CHARS}|[:\#{@}\[\]])+$/
55
+ VALID_KEY_RE_DYNAMIC = /^(#{VALID_KEY_CHARS}|[:\#{@}\[\]])+$/
67
56
 
68
57
  def valid_key?(key)
69
58
  if @config[:strict]
70
- key =~ VALID_KEY_RE_STRICT && !key.end_with?('.')
59
+ super(key)
71
60
  else
72
- key =~ VALID_KEY_RE
61
+ key =~ VALID_KEY_RE_DYNAMIC
73
62
  end
74
63
  end
75
64
 
@@ -87,13 +76,6 @@ module I18n::Tasks::Scanners
87
76
  /(?<=^|[^\w'\-.]|[^\w'\-]I18n\.|I18n\.)t(?:ranslate)?/
88
77
  end
89
78
 
90
- # Match literals:
91
- # * String: '', "#{}"
92
- # * Symbol: :sym, :'', :"#{}"
93
- def literal_re
94
- /:?".+?"|:?'.+?'|:\w+/
95
- end
96
-
97
79
  def default_pattern
98
80
  # capture only the first argument
99
81
  /
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+ module I18n::Tasks::Scanners
3
+ module RubyKeyLiterals
4
+ LITERAL_RE = /:?".+?"|:?'.+?'|:\w+/
5
+
6
+ # Match literals:
7
+ # * String: '', "#{}"
8
+ # * Symbol: :sym, :'', :"#{}"
9
+ def literal_re
10
+ LITERAL_RE
11
+ end
12
+
13
+ # remove the leading colon and unwrap quotes from the key match
14
+ # @param literal [String] e.g: "key", 'key', or :key.
15
+ # @return [String] key
16
+ def strip_literal(literal)
17
+ literal = literal[1..-1] if ':' == literal[0]
18
+ literal = literal[1..-2] if "'" == literal[0] || '"' == literal[0]
19
+ literal
20
+ end
21
+
22
+ VALID_KEY_CHARS = /(?:[[:word:]]|[-.?!;À-ž])/
23
+ VALID_KEY_RE = /^#{VALID_KEY_CHARS}+$/
24
+
25
+ def valid_key?(key)
26
+ key =~ VALID_KEY_RE && !key.end_with?('.')
27
+ end
28
+ end
29
+ end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
  module I18n
3
3
  module Tasks
4
- VERSION = '0.9.4'
4
+ VERSION = '0.9.5'
5
5
  end
6
6
  end
@@ -105,3 +105,16 @@ search:
105
105
  ## Ignore these keys completely:
106
106
  # ignore:
107
107
  # - kaminari.*
108
+
109
+ ## Sometimes, it isn't possible for i18n-tasks to match the key correctly,
110
+ ## e.g. in case of a relative key defined in a helper method.
111
+ ## In these cases you can use the built-in PatternMapper to map patterns to keys, e.g.:
112
+ #
113
+ # <%#= I18n::Tasks.add_scanner 'I18n::Tasks::Scanners::PatternMapper',
114
+ # only: %w(*.html.haml *.html.slim),
115
+ # patterns: [['= title\b', '.page_title']] %>
116
+ #
117
+ # The PatternMapper can also match key literals via a special %{key} interpolation, e.g.:
118
+ #
119
+ # <%#= I18n::Tasks.add_scanner 'I18n::Tasks::Scanners::PatternMapper',
120
+ # patterns: [['\bSpree\.t[( ]\s*%{key}', 'spree.%{key}']] %>
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.9.4
4
+ version: 0.9.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - glebm
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-02-06 00:00:00.000000000 Z
11
+ date: 2016-03-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -281,6 +281,7 @@ files:
281
281
  - lib/i18n/tasks/scanners/files/file_finder.rb
282
282
  - lib/i18n/tasks/scanners/files/file_reader.rb
283
283
  - lib/i18n/tasks/scanners/occurrence_from_position.rb
284
+ - lib/i18n/tasks/scanners/pattern_mapper.rb
284
285
  - lib/i18n/tasks/scanners/pattern_scanner.rb
285
286
  - lib/i18n/tasks/scanners/pattern_with_scope_scanner.rb
286
287
  - lib/i18n/tasks/scanners/relative_keys.rb
@@ -288,6 +289,7 @@ files:
288
289
  - lib/i18n/tasks/scanners/results/occurrence.rb
289
290
  - lib/i18n/tasks/scanners/ruby_ast_call_finder.rb
290
291
  - lib/i18n/tasks/scanners/ruby_ast_scanner.rb
292
+ - lib/i18n/tasks/scanners/ruby_key_literals.rb
291
293
  - lib/i18n/tasks/scanners/scanner.rb
292
294
  - lib/i18n/tasks/scanners/scanner_multiplexer.rb
293
295
  - lib/i18n/tasks/split_key.rb