i18n-tasks 0.7.4 → 0.7.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/CHANGES.md +21 -13
- data/README.md +1 -1
- data/bin/i18n-tasks +2 -2
- data/lib/i18n/tasks/command/options/common.rb +1 -1
- data/lib/i18n/tasks/command/options/locales.rb +1 -1
- data/lib/i18n/tasks/configuration.rb +1 -1
- data/lib/i18n/tasks/data/file_system_base.rb +1 -1
- data/lib/i18n/tasks/data/tree/node.rb +5 -4
- data/lib/i18n/tasks/data/tree/siblings.rb +1 -1
- data/lib/i18n/tasks/ignore_keys.rb +7 -7
- data/lib/i18n/tasks/key_pattern_matching.rb +1 -1
- data/lib/i18n/tasks/locale_pathname.rb +7 -1
- data/lib/i18n/tasks/logging.rb +1 -1
- data/lib/i18n/tasks/missing_keys.rb +1 -1
- data/lib/i18n/tasks/plural_keys.rb +2 -1
- data/lib/i18n/tasks/reports/base.rb +1 -1
- data/lib/i18n/tasks/scanners/base_scanner.rb +3 -3
- data/lib/i18n/tasks/scanners/pattern_scanner.rb +1 -1
- data/lib/i18n/tasks/split_key.rb +46 -20
- data/lib/i18n/tasks/version.rb +1 -1
- data/spec/split_key_spec.rb +6 -0
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 850032b9cd081295834563c079f301118c4adc93
|
4
|
+
data.tar.gz: bb430460401ab69f396b53e29337b7d12894c49a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2f28025277307b4c42facd0f94691100f73680a27eaf135945484e5711e66db865a094269f895c3f6e7cdb767c021a50df51fb50d77377eccbfa7e8955359e18
|
7
|
+
data.tar.gz: 6abfa104439e6592d7a40934fa8e7c70707094be19faad49ce5ca4fbb9a04774613662f0076ff2fa436cd62001a242ad0dea35dcddbcdab7b3e0c49b11f17304
|
data/CHANGES.md
CHANGED
@@ -1,7 +1,15 @@
|
|
1
|
+
## 0.7.5
|
2
|
+
|
3
|
+
Dynamic key usage inference fixes by [Mikko Koski](https://github.com/rap1ds):
|
4
|
+
|
5
|
+
* Append `:` to keys ending with dot '.' (to scan `t('category.' + cat)` as `t('category.:')`)
|
6
|
+
* Consider keys ending with `:` as match expressions
|
7
|
+
* Make `@` a valid character for keys (to allow `t("category.#{@cat}"`)
|
8
|
+
|
1
9
|
## 0.7.4
|
2
10
|
|
3
11
|
* Fix `add-missing --help`
|
4
|
-
* Fix a minor issue with `health` #88(https://github.com/glebm/i18n-tasks/issues/88)
|
12
|
+
* Fix a minor issue with `health` [#88](https://github.com/glebm/i18n-tasks/issues/88)
|
5
13
|
|
6
14
|
## 0.7.3
|
7
15
|
|
@@ -196,29 +204,29 @@ With these trees, information can be associated with each node, which allows for
|
|
196
204
|
|
197
205
|
* config/i18n-tasks.yml now processed with ERB
|
198
206
|
* can now be used with any ruby apps, not just Rails
|
199
|
-
* more locale formats are considered valid
|
207
|
+
* more locale formats are considered valid
|
200
208
|
* `i18n:missing` accepts locales
|
201
209
|
* `i18n:missing` supports plural keys
|
202
210
|
|
203
211
|
## v0.2.4
|
204
212
|
|
205
|
-
* more powerful key pattern matching with sets and backtracking
|
213
|
+
* more powerful key pattern matching with sets and backtracking
|
206
214
|
|
207
215
|
## v0.2.3
|
208
216
|
|
209
|
-
* spreadsheet report, tests run on rbx
|
217
|
+
* spreadsheet report, tests run on rbx
|
210
218
|
|
211
219
|
## v0.2.2
|
212
220
|
|
213
|
-
* improved output with terminal-table
|
221
|
+
* improved output with terminal-table
|
214
222
|
|
215
223
|
## v0.2.1
|
216
224
|
|
217
|
-
* fill tasks renamed, fix symbol key search
|
225
|
+
* fill tasks renamed, fix symbol key search
|
218
226
|
|
219
227
|
## v0.2.0
|
220
228
|
|
221
|
-
* 3 more prefill tasks, including Google Translate
|
229
|
+
* 3 more prefill tasks, including Google Translate
|
222
230
|
* tasks renamed
|
223
231
|
|
224
232
|
## v0.1.8
|
@@ -227,16 +235,16 @@ With these trees, information can be associated with each node, which allows for
|
|
227
235
|
|
228
236
|
## v0.1.7
|
229
237
|
|
230
|
-
* ability to route prefill output via data.write config
|
231
|
-
* multiple configuration variables renamed (still understands old syntax with deprecation warnings)
|
238
|
+
* ability to route prefill output via data.write config
|
239
|
+
* multiple configuration variables renamed (still understands old syntax with deprecation warnings)
|
232
240
|
|
233
241
|
## v0.1.6
|
234
242
|
|
235
|
-
* New key pattern syntax for i18n-tasks.yml a la globbing
|
243
|
+
* New key pattern syntax for i18n-tasks.yml a la globbing
|
236
244
|
|
237
245
|
## v0.1.5
|
238
246
|
|
239
|
-
* Removed get_locale_data, added data configuration options
|
247
|
+
* Removed get_locale_data, added data configuration options
|
240
248
|
|
241
249
|
## v0.1.4
|
242
250
|
|
@@ -245,10 +253,10 @@ With these trees, information can be associated with each node, which allows for
|
|
245
253
|
|
246
254
|
## v0.1.3
|
247
255
|
|
248
|
-
* detect countable keys as used for unused task
|
256
|
+
* detect countable keys as used for unused task
|
249
257
|
* account for non-string keys coming from yaml (thanks @lichtamberg)
|
250
258
|
|
251
259
|
## v0.1.2
|
252
260
|
|
253
261
|
* added grep config options (thanks @dmke)
|
254
|
-
* improved terminal output
|
262
|
+
* improved terminal output
|
data/README.md
CHANGED
data/bin/i18n-tasks
CHANGED
@@ -35,7 +35,7 @@ begin
|
|
35
35
|
exit
|
36
36
|
}
|
37
37
|
commander.cmds.each do |name, attr|
|
38
|
-
slop_dsl = slop_adapter.slop_command(name, attr) { |
|
38
|
+
slop_dsl = slop_adapter.slop_command(name, attr) { |_name, opts|
|
39
39
|
begin
|
40
40
|
ran = true
|
41
41
|
instance.safe_run name, opts
|
@@ -45,7 +45,7 @@ begin
|
|
45
45
|
exit 1
|
46
46
|
end
|
47
47
|
}
|
48
|
-
instance_exec
|
48
|
+
instance_exec(&slop_dsl)
|
49
49
|
end
|
50
50
|
end
|
51
51
|
rescue Slop::Error => e
|
@@ -43,7 +43,7 @@ module I18n::Tasks
|
|
43
43
|
opt[key]
|
44
44
|
end
|
45
45
|
|
46
|
-
VALID_LOCALE_RE = /\A\w[\w
|
46
|
+
VALID_LOCALE_RE = /\A\w[\w\-\.]*\z/i
|
47
47
|
|
48
48
|
def validate_locale!(locale)
|
49
49
|
raise CommandError.new(I18n.t('i18n_tasks.cmd.errors.invalid_locale', invalid: locale)) if VALID_LOCALE_RE !~ locale
|
@@ -12,7 +12,7 @@ module I18n::Tasks::Configuration
|
|
12
12
|
)
|
13
13
|
|
14
14
|
def file_config
|
15
|
-
file = CONFIG_FILES.detect { |f| File.
|
15
|
+
file = CONFIG_FILES.detect { |f| File.exist?(f) }
|
16
16
|
config = file && YAML.load(Erubis::Eruby.new(File.read(file)).result)
|
17
17
|
if config.present?
|
18
18
|
config.with_indifferent_access.tap do |c|
|
@@ -8,11 +8,12 @@ module I18n::Tasks::Data::Tree
|
|
8
8
|
attr_reader :key, :children, :parent
|
9
9
|
|
10
10
|
def initialize(opts = {})
|
11
|
-
@key = opts[:key]
|
11
|
+
@key = opts[:key]
|
12
|
+
@key = @key.to_s.freeze if @key
|
12
13
|
@value = opts[:value]
|
13
14
|
@data = opts[:data]
|
14
15
|
@parent = opts[:parent]
|
15
|
-
self.children = opts[:children] if opts[:children]
|
16
|
+
self.children = (opts[:children] if opts[:children])
|
16
17
|
end
|
17
18
|
|
18
19
|
def attributes
|
@@ -102,7 +103,7 @@ module I18n::Tasks::Data::Tree
|
|
102
103
|
def walk_to_root(&visitor)
|
103
104
|
return to_enum(:walk_to_root) unless visitor
|
104
105
|
visitor.yield self
|
105
|
-
parent.walk_to_root
|
106
|
+
parent.walk_to_root(&visitor) if parent?
|
106
107
|
end
|
107
108
|
|
108
109
|
def root
|
@@ -123,7 +124,7 @@ module I18n::Tasks::Data::Tree
|
|
123
124
|
end
|
124
125
|
|
125
126
|
def to_siblings
|
126
|
-
parent.
|
127
|
+
parent && parent.children || Siblings.new(nodes: [self])
|
127
128
|
end
|
128
129
|
|
129
130
|
def to_hash
|
@@ -49,7 +49,7 @@ module I18n::Tasks::Data::Tree
|
|
49
49
|
|
50
50
|
# @return [Node] by full key
|
51
51
|
def get(full_key)
|
52
|
-
first_key, rest = split_key(full_key, 2)
|
52
|
+
first_key, rest = split_key(full_key.to_s, 2)
|
53
53
|
node = key_to_node[first_key]
|
54
54
|
if rest && node
|
55
55
|
node = node.children.try(:get, rest)
|
@@ -15,13 +15,13 @@ module I18n::Tasks::IgnoreKeys
|
|
15
15
|
@ignore_patterns[type] ||= {}
|
16
16
|
@ignore_patterns[type][locale] ||= begin
|
17
17
|
global, type_ignore = ignore_config.presence || [], ignore_config(type).presence || []
|
18
|
-
if type_ignore.is_a?(Array)
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
18
|
+
patterns = if type_ignore.is_a?(Array)
|
19
|
+
global + type_ignore
|
20
|
+
elsif type_ignore.is_a?(Hash)
|
21
|
+
# ignore per locale
|
22
|
+
global + (type_ignore['all'] || []) +
|
23
|
+
type_ignore.select { |k, v| k.to_s =~ /\b#{locale}\b/ }.values.flatten(1).compact
|
24
|
+
end
|
25
25
|
compile_patterns_re patterns
|
26
26
|
end
|
27
27
|
end
|
@@ -39,7 +39,7 @@ module I18n::Tasks::KeyPatternMatching
|
|
39
39
|
end
|
40
40
|
|
41
41
|
# @return true if the key looks like an expression
|
42
|
-
KEY_INTERPOLATION_RE = /(?:\#{.*?}
|
42
|
+
KEY_INTERPOLATION_RE = /(?:\#{.*?}|\*+|\:+)/.freeze
|
43
43
|
def key_expression?(k)
|
44
44
|
@key_is_expr ||= {}
|
45
45
|
if @key_is_expr[k].nil?
|
@@ -3,7 +3,13 @@ module I18n::Tasks
|
|
3
3
|
extend self
|
4
4
|
|
5
5
|
def replace_locale(path, from, to)
|
6
|
-
path.
|
6
|
+
path && path.sub(path_locale_re(from), to)
|
7
|
+
end
|
8
|
+
|
9
|
+
private
|
10
|
+
|
11
|
+
def path_locale_re(locale)
|
12
|
+
(@path_locale_res ||= {})[locale] ||= /(?<=^|[\/.])#{locale}(?=\.)/.freeze
|
7
13
|
end
|
8
14
|
end
|
9
15
|
end
|
data/lib/i18n/tasks/logging.rb
CHANGED
@@ -67,7 +67,7 @@ module I18n::Tasks
|
|
67
67
|
# keys present in compared_to, but not in locale
|
68
68
|
def missing_diff_tree(locale, compared_to = base_locale)
|
69
69
|
data[compared_to].select_keys { |key, _node|
|
70
|
-
locale_key_missing? locale, depluralize_key(key,
|
70
|
+
locale_key_missing? locale, depluralize_key(key, compared_to)
|
71
71
|
}.set_root_key!(locale, type: :missing_diff).keys { |_key, node|
|
72
72
|
if node.data.key?(:path)
|
73
73
|
# change path and locale to base
|
@@ -21,7 +21,8 @@ module I18n::Tasks::PluralKeys
|
|
21
21
|
# @return the base form if the key is a specific plural form (e.g. apple for apple.many), and the key as passed otherwise
|
22
22
|
def depluralize_key(key, locale = base_locale)
|
23
23
|
return key if key !~ PLURAL_KEY_RE
|
24
|
-
|
24
|
+
key_name = last_key_part(key)
|
25
|
+
parent_key = key[0 .. - (key_name.length + 2)]
|
25
26
|
nodes = tree("#{locale}.#{parent_key}").presence || (locale != base_locale && tree("#{base_locale}.#{parent_key}"))
|
26
27
|
if nodes && plural_forms?(nodes)
|
27
28
|
parent_key
|
@@ -40,7 +40,7 @@ module I18n::Tasks::Reports
|
|
40
40
|
def sort_by_attr!(objects, order = {locale: :asc, key: :asc})
|
41
41
|
order_keys = order.keys
|
42
42
|
objects.sort! { |a, b|
|
43
|
-
by = order_keys.detect { |
|
43
|
+
by = order_keys.detect { |k| a[k] != b[k] }
|
44
44
|
order[by] == :desc ? b[by] <=> a[by] : a[by] <=> b[by]
|
45
45
|
}
|
46
46
|
objects
|
@@ -42,7 +42,7 @@ module I18n::Tasks::Scanners
|
|
42
42
|
scan_file(path, opts)
|
43
43
|
}.reduce(:+) || []
|
44
44
|
keys.group_by(&:first).map { |key, key_loc|
|
45
|
-
[key, data: {source_occurrences: key_loc.map { |(
|
45
|
+
[key, data: {source_occurrences: key_loc.map { |(_k, attr)| attr[:data] }}]
|
46
46
|
}
|
47
47
|
end
|
48
48
|
|
@@ -61,7 +61,7 @@ module I18n::Tasks::Scanners
|
|
61
61
|
# @return [Array] Results of block calls
|
62
62
|
def traverse_files
|
63
63
|
result = []
|
64
|
-
paths = config[:paths].select { |p| File.
|
64
|
+
paths = config[:paths].select { |p| File.exist?(p) }
|
65
65
|
if paths.empty?
|
66
66
|
log_warn "search.paths #{config[:paths].inspect} do not exist"
|
67
67
|
return result
|
@@ -117,7 +117,7 @@ module I18n::Tasks::Scanners
|
|
117
117
|
|
118
118
|
VALID_KEY_CHARS = /[-\w.?!;:]/
|
119
119
|
VALID_KEY_RE_STRICT = /^#{VALID_KEY_CHARS}+$/
|
120
|
-
VALID_KEY_RE = /^(#{VALID_KEY_CHARS}|[\#{}])+$/
|
120
|
+
VALID_KEY_RE = /^(#{VALID_KEY_CHARS}|[\#{@}])+$/
|
121
121
|
|
122
122
|
def valid_key?(key, strict = false)
|
123
123
|
return false if @key_filter && @key_filter_pattern !~ key
|
@@ -15,6 +15,7 @@ module I18n::Tasks::Scanners
|
|
15
15
|
src_pos = Regexp.last_match.offset(0).first
|
16
16
|
key = match_to_key(match, path)
|
17
17
|
next unless valid_key?(key, strict)
|
18
|
+
key = key + ':' if key.end_with?('.')
|
18
19
|
location = src_location(path, text, src_pos)
|
19
20
|
unless exclude_line?(location[:line])
|
20
21
|
keys << [key, data: location]
|
@@ -39,7 +40,6 @@ module I18n::Tasks::Scanners
|
|
39
40
|
# @return [String] full absolute key name
|
40
41
|
def match_to_key(match, path)
|
41
42
|
key = strip_literal(match[0])
|
42
|
-
key = key + '*' if key.end_with?('.')
|
43
43
|
key = absolutize_key(key, path) if path && key.start_with?('.')
|
44
44
|
key
|
45
45
|
end
|
data/lib/i18n/tasks/split_key.rb
CHANGED
@@ -1,39 +1,65 @@
|
|
1
1
|
module SplitKey
|
2
2
|
extend self
|
3
3
|
|
4
|
-
# split a key
|
4
|
+
# split a key by dots (.)
|
5
|
+
# dots inside braces or parenthesis are not split on
|
6
|
+
#
|
5
7
|
# split_key 'a.b' # => ['a', 'b']
|
6
8
|
# split_key 'a.#{b.c}' # => ['a', '#{b.c}']
|
7
9
|
# split_key 'a.b.c', 2 # => ['a', 'b.c']
|
8
10
|
def split_key(key, max = Float::INFINITY)
|
9
11
|
parts = []
|
10
|
-
|
11
|
-
|
12
|
+
pos = 0
|
13
|
+
return [key] if max == 1
|
14
|
+
key_parts(key) do |part|
|
15
|
+
parts << part
|
16
|
+
pos += part.length + 1
|
17
|
+
if parts.length + 1 >= max
|
18
|
+
parts << key.from(pos) unless pos == key.length
|
19
|
+
break
|
20
|
+
end
|
21
|
+
end
|
22
|
+
parts
|
23
|
+
end
|
24
|
+
|
25
|
+
def last_key_part(key)
|
26
|
+
last = nil
|
27
|
+
key_parts(key) { |part| last = part }
|
28
|
+
last
|
29
|
+
end
|
30
|
+
|
31
|
+
# yield each key part
|
32
|
+
# dots inside braces or parenthesis are not split on
|
33
|
+
def key_parts(key, &block)
|
34
|
+
return enum_for(:key_parts, key) unless block
|
35
|
+
nesting = PARENS
|
36
|
+
counts = PARENS_ZEROS # dup'd later if key contains parenthesis
|
12
37
|
delim = '.'.freeze
|
13
|
-
|
14
|
-
key.
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
buf << char
|
19
|
-
elsif char == delim && parts.length + 1 < max && counts.all?(&:zero?)
|
20
|
-
part = buf.join
|
21
|
-
buf.clear
|
22
|
-
parts << part
|
23
|
-
yield part if block_given?
|
38
|
+
from = to = 0
|
39
|
+
key.each_char do |char|
|
40
|
+
if char == delim && PARENS_ZEROS == counts
|
41
|
+
block.yield key[from...to]
|
42
|
+
from = to = (to + 1)
|
24
43
|
else
|
25
|
-
|
44
|
+
nest_i, nest_inc = nesting[char]
|
45
|
+
if nest_i
|
46
|
+
counts = counts.dup if counts.frozen?
|
47
|
+
counts[nest_i] += nest_inc
|
48
|
+
end
|
49
|
+
to += 1
|
26
50
|
end
|
27
51
|
end
|
28
|
-
|
29
|
-
|
52
|
+
block.yield(key[from...to]) if from < to && to <= key.length
|
53
|
+
true
|
30
54
|
end
|
31
55
|
|
32
|
-
|
33
|
-
i
|
56
|
+
PARENS = %w({} [] ()).inject({}) { |h, s|
|
57
|
+
i = h.size / 2
|
34
58
|
h[s[0].freeze] = [i, 1].freeze
|
35
59
|
h[s[1].freeze] = [i, -1].freeze
|
36
60
|
h
|
37
61
|
}.freeze
|
38
|
-
|
62
|
+
PARENS_ZEROS = Array.new(PARENS.size, 0).freeze
|
63
|
+
private_constant :PARENS
|
64
|
+
private_constant :PARENS_ZEROS
|
39
65
|
end
|
data/lib/i18n/tasks/version.rb
CHANGED
data/spec/split_key_spec.rb
CHANGED
@@ -22,6 +22,12 @@ describe 'SplitKey' do
|
|
22
22
|
expect(split_key 'a.b.c', 1).to eq(['a.b.c'])
|
23
23
|
expect(split_key 'a.b.c', 2).to eq(['a', 'b.c'])
|
24
24
|
expect(split_key 'a.b.c.', 2).to eq(['a', 'b.c.'])
|
25
|
+
expect(split_key 'a.b.c.d.e.f', 4).to eq(['a', 'b', 'c', 'd.e.f'])
|
25
26
|
end
|
26
27
|
|
28
|
+
it 'last part' do
|
29
|
+
expect(last_key_part 'a.b.c').to eq('c')
|
30
|
+
expect(last_key_part 'a').to eq('a')
|
31
|
+
expect(last_key_part 'a.b.c.d').to eq('d')
|
32
|
+
end
|
27
33
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: i18n-tasks
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.7.
|
4
|
+
version: 0.7.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- glebm
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-09-03 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: erubis
|