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 +4 -4
- data/README.md +8 -1
- data/lib/i18n/tasks/cli.rb +18 -16
- data/lib/i18n/tasks/command/commander.rb +0 -4
- data/lib/i18n/tasks/command/commands/missing.rb +5 -3
- data/lib/i18n/tasks/scanners/pattern_mapper.rb +59 -0
- data/lib/i18n/tasks/scanners/pattern_scanner.rb +5 -23
- data/lib/i18n/tasks/scanners/ruby_key_literals.rb +29 -0
- data/lib/i18n/tasks/version.rb +1 -1
- data/templates/config/i18n-tasks.yml +13 -0
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d0229b3a4c2b8749a457c6b71e412a80802a6aa3
|
4
|
+
data.tar.gz: e43c66b6e67ef86dd28fcb7d7c9875c4578c9b84
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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.
|
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
|
data/lib/i18n/tasks/cli.rb
CHANGED
@@ -14,23 +14,25 @@ class I18n::Tasks::CLI
|
|
14
14
|
end
|
15
15
|
|
16
16
|
def start(argv)
|
17
|
-
|
18
|
-
|
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
|
-
|
27
|
-
|
28
|
-
|
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)
|
48
|
+
@context ||= ::I18n::Tasks::Commands.new(base_task)
|
47
49
|
end
|
48
50
|
|
49
51
|
def commands
|
@@ -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!(
|
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!(
|
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
|
-
|
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
|
59
|
+
super(key)
|
71
60
|
else
|
72
|
-
key =~
|
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
|
data/lib/i18n/tasks/version.rb
CHANGED
@@ -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
|
+
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-
|
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
|