i18n-tasks 0.5.1 → 0.5.2
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 +6 -1
- data/README.md +10 -6
- data/lib/i18n/tasks/configuration.rb +1 -1
- data/lib/i18n/tasks/data/file_system_base.rb +4 -7
- data/lib/i18n/tasks/data/tree/node.rb +0 -2
- data/lib/i18n/tasks/ignore_keys.rb +1 -1
- data/lib/i18n/tasks/scanners/base_scanner.rb +26 -41
- data/lib/i18n/tasks/scanners/pattern_scanner.rb +5 -2
- data/lib/i18n/tasks/used_keys.rb +1 -2
- data/lib/i18n/tasks/version.rb +1 -1
- data/spec/fixtures/app/views/index.html.slim +4 -0
- data/spec/i18n_tasks_spec.rb +1 -0
- data/spec/locale_tree/siblings_spec.rb +0 -1
- metadata +2 -4
- data/config/locales/en.yml +0 -4
- data/config/locales/es.yml +0 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0268bd9f81bcf59f191082abc4d7659858b01307
|
4
|
+
data.tar.gz: 0feb0bd995b09220bb7ae0843a3cc67c01cfd938
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3514ce68ee51f2b90028fbb87cd5b1e249cc66ebe41f9b746e65d39e87b00b2a372099f8e3d2abf9f28e829d0e8cb8d6fc68f64c6ac6c25f029aa307d8b37c5e
|
7
|
+
data.tar.gz: 339eec064e4f2fa5b52182113aafe7f819ef2c5d1917901556a0f3d228e85ef661afb640876677b653fdfb1327adc0539ab447e3d2b8c41f8c0fe3327e148d8a
|
data/CHANGES.md
CHANGED
@@ -1,7 +1,12 @@
|
|
1
|
+
## 0.5.2
|
2
|
+
|
3
|
+
* Ignore lines during search with `config.search.ignore_lines`. Ignores comments by default.
|
4
|
+
* Fixed minor issues with `i18-tasks config` output.
|
5
|
+
|
1
6
|
## 0.5.1
|
2
7
|
|
3
8
|
* Fix [conservative router](https://github.com/glebm/i18n-tasks#conservative-router).
|
4
|
-
*
|
9
|
+
* Conservative router is now the default.
|
5
10
|
|
6
11
|
## 0.5.0
|
7
12
|
|
data/README.md
CHANGED
@@ -6,7 +6,7 @@ The default approach to locale data management with gems such as [i18n][i18n-gem
|
|
6
6
|
If you use a key that does not exist, this will only blow up at runtime. Keys left over from removed code accumulate
|
7
7
|
in the resource files and introduce unnecessary overhead on the translators. Translation files can quickly turn to disarray.
|
8
8
|
|
9
|
-
i18n-tasks improves this by
|
9
|
+
i18n-tasks improves this by analysing code statically, without running it. It scans calls such as `I18n.t('some.key')` and provides reports on key usage, missing, and unused keys.
|
10
10
|
It can also pre-fill missing keys, including from Google Translate, and it can remove unused keys as well.
|
11
11
|
|
12
12
|
i18n-tasks can be used with any project using [i18n][i18n-gem] (default in Rails), or similar, even if it isn't ruby.
|
@@ -18,7 +18,7 @@ i18n-tasks can be used with any project using [i18n][i18n-gem] (default in Rails
|
|
18
18
|
Add to Gemfile:
|
19
19
|
|
20
20
|
```ruby
|
21
|
-
gem 'i18n-tasks', '~> 0.5.
|
21
|
+
gem 'i18n-tasks', '~> 0.5.2'
|
22
22
|
```
|
23
23
|
|
24
24
|
|
@@ -203,13 +203,14 @@ data:
|
|
203
203
|
##### Conservative router
|
204
204
|
|
205
205
|
Conservative router keeps the keys where they are found, or infers the path from base locale.
|
206
|
-
If the key is completely new, conservative router will fall back to
|
206
|
+
If the key is completely new, conservative router will fall back to pattern router behaviour.
|
207
207
|
Conservative router is the default router.
|
208
208
|
|
209
209
|
```
|
210
210
|
data:
|
211
211
|
router: conservative_router
|
212
212
|
write:
|
213
|
+
- ['devise.*', 'config/locales/devise.%{locale}.yml']
|
213
214
|
- 'config/locales/%{locale}.yml'
|
214
215
|
```
|
215
216
|
|
@@ -243,11 +244,14 @@ search:
|
|
243
244
|
- '*.rb'
|
244
245
|
- '*.html.*'
|
245
246
|
- '*.text.*'
|
246
|
-
# explicitly exclude files (default:
|
247
|
+
# explicitly exclude files (default: exclude common binary files)
|
247
248
|
exclude:
|
248
249
|
- '*.js'
|
249
250
|
# you can override the default key regex pattern:
|
250
251
|
pattern: "\\bt[( ]\\s*(:?\".+?\"|:?'.+?'|:\\w+)"
|
252
|
+
# comments are ignored by default
|
253
|
+
ignore_lines:
|
254
|
+
- "^\\s*[#/](?!\\si18n-tasks-use)"
|
251
255
|
```
|
252
256
|
|
253
257
|
To configure paths for relative key resolution:
|
@@ -327,12 +331,12 @@ describe 'I18n' do
|
|
327
331
|
let(:i18n) { I18n::Tasks::BaseTask.new }
|
328
332
|
|
329
333
|
it 'does not have missing keys' do
|
330
|
-
count = i18n.missing_keys.count
|
334
|
+
count = i18n.missing_keys.leaves.count
|
331
335
|
fail "There are #{count} missing i18n keys! Run 'i18n-tasks missing' for more details." unless count.zero?
|
332
336
|
end
|
333
337
|
|
334
338
|
it 'does not have unused keys' do
|
335
|
-
count = i18n.unused_keys.count
|
339
|
+
count = i18n.unused_keys.leaves.count
|
336
340
|
fail "There are #{count} unused i18n keys! Run 'i18n-tasks unused' for more details." unless count.zero?
|
337
341
|
end
|
338
342
|
end
|
@@ -108,7 +108,7 @@ module I18n::Tasks::Configuration
|
|
108
108
|
def config_for_inspect
|
109
109
|
# hide empty sections, stringify keys
|
110
110
|
Hash[config_sections.reject { |k, v| v.nil? || v.empty? }.map { |k, v|
|
111
|
-
[k.to_s, v.respond_to?(:deep_stringify_keys) ? v.deep_stringify_keys : v] }].tap do |h|
|
111
|
+
[k.to_s, v.respond_to?(:deep_stringify_keys) ? v.deep_stringify_keys.to_hash : v] }].tap do |h|
|
112
112
|
h.each do |_k, v|
|
113
113
|
if v.is_a?(Hash) && v.key?('config')
|
114
114
|
v.merge! v.delete('config')
|
@@ -10,7 +10,7 @@ module I18n::Tasks
|
|
10
10
|
class FileSystemBase
|
11
11
|
include ::I18n::Tasks::Data::FileFormats
|
12
12
|
|
13
|
-
attr_reader :config
|
13
|
+
attr_reader :config, :base_locale
|
14
14
|
|
15
15
|
DEFAULTS = {
|
16
16
|
read: ['config/locales/%{locale}.yml'],
|
@@ -18,7 +18,8 @@ module I18n::Tasks
|
|
18
18
|
}.with_indifferent_access
|
19
19
|
|
20
20
|
def initialize(config = {})
|
21
|
-
|
21
|
+
@base_locale = config[:base_locale]
|
22
|
+
self.config = config.except(:base_locale)
|
22
23
|
end
|
23
24
|
|
24
25
|
# get locale tree
|
@@ -96,7 +97,7 @@ module I18n::Tasks
|
|
96
97
|
if name[0] != name[0].upcase
|
97
98
|
name = "I18n::Tasks::Data::Router::#{name.classify}"
|
98
99
|
end
|
99
|
-
name.constantize.new(self, @config)
|
100
|
+
name.constantize.new(self, @config.merge(base_locale: base_locale))
|
100
101
|
end
|
101
102
|
end
|
102
103
|
attr_writer :router
|
@@ -114,10 +115,6 @@ module I18n::Tasks
|
|
114
115
|
end
|
115
116
|
end.reduce(:merge!) || Tree::Siblings.null
|
116
117
|
end
|
117
|
-
|
118
|
-
def base_locale
|
119
|
-
config[:base_locale]
|
120
|
-
end
|
121
118
|
end
|
122
119
|
end
|
123
120
|
end
|
@@ -19,7 +19,7 @@ module I18n::Tasks::IgnoreKeys
|
|
19
19
|
patterns = global + type_ignore
|
20
20
|
elsif type_ignore.is_a?(Hash)
|
21
21
|
# ignore per locale
|
22
|
-
patterns = global + (type_ignore[
|
22
|
+
patterns = global + (type_ignore['all'] || []) +
|
23
23
|
type_ignore.select { |k, v| k.to_s =~ /\b#{locale}\b/ }.values.flatten(1).compact
|
24
24
|
end
|
25
25
|
compile_patterns_re patterns
|
@@ -7,10 +7,10 @@ module I18n::Tasks::Scanners
|
|
7
7
|
include ::I18n::Tasks::KeyPatternMatching
|
8
8
|
include ::I18n::Tasks::Logging
|
9
9
|
|
10
|
-
attr_reader :config, :key_filter, :
|
10
|
+
attr_reader :config, :key_filter, :ignore_lines_re
|
11
11
|
|
12
12
|
def initialize(config = {})
|
13
|
-
@config
|
13
|
+
@config = config.dup.with_indifferent_access.tap do |conf|
|
14
14
|
conf[:paths] = %w(app/) if conf[:paths].blank?
|
15
15
|
conf[:include] = Array(conf[:include]) if conf[:include].present?
|
16
16
|
if conf.key?(:exclude)
|
@@ -19,8 +19,14 @@ module I18n::Tasks::Scanners
|
|
19
19
|
# exclude common binary extensions by default (images and fonts)
|
20
20
|
conf[:exclude] = %w(*.jpg *.png *.gif *.svg *.ico *.eot *.ttf *.woff *.pdf)
|
21
21
|
end
|
22
|
+
conf[:ignore_lines] ||= %q(^\s*[#/](?!\si18n-tasks-use)).freeze
|
23
|
+
conf[:ignore_lines] = Array(conf[:ignore_lines])
|
24
|
+
@ignore_lines_re = conf[:ignore_lines].map { |line| Regexp.new(line) }
|
22
25
|
end
|
23
|
-
|
26
|
+
end
|
27
|
+
|
28
|
+
def exclude_line?(line)
|
29
|
+
ignore_lines_re.any? { |re| re =~ line }
|
24
30
|
end
|
25
31
|
|
26
32
|
def key_filter=(value)
|
@@ -28,21 +34,14 @@ module I18n::Tasks::Scanners
|
|
28
34
|
@key_filter_pattern = compile_key_pattern(value) if @key_filter
|
29
35
|
end
|
30
36
|
|
31
|
-
# @return [Array]
|
37
|
+
# @return [Array<{key,data:{source_locations:[]}}]
|
32
38
|
def keys
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
keys = traverse_files { |path|
|
40
|
-
scan_file(path)
|
41
|
-
}.reduce(:+) || []
|
42
|
-
keys.group_by(&:first).map { |key, key_loc|
|
43
|
-
[key, data: {source_locations: key_loc.map { |(k, attr)| attr[:data] }}]
|
44
|
-
}
|
45
|
-
end
|
39
|
+
keys = traverse_files { |path|
|
40
|
+
scan_file(path)
|
41
|
+
}.reduce(:+) || []
|
42
|
+
keys.group_by(&:first).map { |key, key_loc|
|
43
|
+
[key, data: {source_locations: key_loc.map { |(k, attr)| attr[:data] }}]
|
44
|
+
}
|
46
45
|
end
|
47
46
|
|
48
47
|
def read_file(path)
|
@@ -87,37 +86,23 @@ module I18n::Tasks::Scanners
|
|
87
86
|
self.key_filter = filter_was
|
88
87
|
end
|
89
88
|
|
90
|
-
def recording_source_locations
|
91
|
-
was = @record_src_loc
|
92
|
-
@record_src_loc = true
|
93
|
-
yield
|
94
|
-
ensure
|
95
|
-
@record_src_loc = was
|
96
|
-
end
|
97
|
-
|
98
89
|
protected
|
99
90
|
|
100
91
|
def path_fnmatch_any?(path, globs)
|
101
92
|
globs.any? { |glob| File.fnmatch(glob, path) }
|
102
93
|
end
|
103
94
|
|
104
|
-
def src_location(path, text, src_pos)
|
105
|
-
|
106
|
-
if
|
107
|
-
|
95
|
+
def src_location(path, text, src_pos, position = true)
|
96
|
+
data = {src_path: path}
|
97
|
+
if position
|
98
|
+
line_begin = text.rindex(/^/, src_pos - 1)
|
99
|
+
line_end = text.index(/.(?=\n|$)/, src_pos)
|
100
|
+
data.merge! pos: src_pos,
|
101
|
+
line_num: text[0..src_pos].count("\n") + 1,
|
102
|
+
line_pos: src_pos - line_begin + 1,
|
103
|
+
line: text[line_begin..line_end]
|
108
104
|
end
|
109
|
-
|
110
|
-
end
|
111
|
-
|
112
|
-
def src_text_location(text, src_pos)
|
113
|
-
line_begin = text.rindex(/^/, src_pos - 1)
|
114
|
-
line_end = text.index(/.(?=\n|$)/, src_pos)
|
115
|
-
{
|
116
|
-
pos: src_pos,
|
117
|
-
line_num: text[0..src_pos].count("\n") + 1,
|
118
|
-
line_pos: src_pos - line_begin + 1,
|
119
|
-
line: text[line_begin..line_end]
|
120
|
-
}
|
105
|
+
data
|
121
106
|
end
|
122
107
|
|
123
108
|
# remove the leading colon and unwrap quotes from the key match
|
@@ -13,7 +13,10 @@ module I18n::Tasks::Scanners
|
|
13
13
|
src_pos = Regexp.last_match.offset(0).first
|
14
14
|
key = match_to_key(match, path)
|
15
15
|
next unless valid_key?(key)
|
16
|
-
|
16
|
+
location = src_location(path, text, src_pos)
|
17
|
+
unless exclude_line?(location[:line])
|
18
|
+
keys << [key, data: location]
|
19
|
+
end
|
17
20
|
end
|
18
21
|
keys
|
19
22
|
end
|
@@ -44,7 +47,7 @@ module I18n::Tasks::Scanners
|
|
44
47
|
end
|
45
48
|
|
46
49
|
def translate_call_re
|
47
|
-
|
50
|
+
/(?<=^|[^\w'\-])t(?:ranslate)?/
|
48
51
|
end
|
49
52
|
|
50
53
|
# Match literals:
|
data/lib/i18n/tasks/used_keys.rb
CHANGED
@@ -6,12 +6,11 @@ module I18n::Tasks
|
|
6
6
|
module UsedKeys
|
7
7
|
|
8
8
|
# find all keys in the source (relative keys are absolutized)
|
9
|
-
# @option opts [false|true] :source_locations
|
10
9
|
# @option opts [String] :key_filter
|
11
10
|
# @return [Array<String>]
|
12
11
|
def used_tree(opts = {})
|
13
12
|
return scanner.with_key_filter(opts[:key_filter]) { used_tree(opts.except(:key_filter)) } if opts[:key_filter]
|
14
|
-
key_attrs =
|
13
|
+
key_attrs = scanner.keys
|
15
14
|
Data::Tree::Node.new(
|
16
15
|
key: 'used',
|
17
16
|
data: {key_filter: scanner.key_filter},
|
data/lib/i18n/tasks/version.rb
CHANGED
@@ -1,3 +1,7 @@
|
|
1
|
+
| x't :fp_quote_before
|
2
|
+
| x-t :fp_dash_before
|
3
|
+
/ t(:fp_comment)
|
4
|
+
/ i18n-tasks-use t(:fn_comment)
|
1
5
|
p #{t('ca.a')} #{t 'ca.b'} #{t "ca.c"}
|
2
6
|
p #{t 'ca.d'} #{t 'ca.f', i: 'world'} #{t 'ca.e', i: 'world'}
|
3
7
|
p #{t 'missing_in_es.a'} #{t 'same_in_es.a'} #{t 'blank_in_es.a'}
|
data/spec/i18n_tasks_spec.rb
CHANGED
@@ -14,6 +14,7 @@ describe 'i18n-tasks' do
|
|
14
14
|
en.missing_symbol_key en.missing_symbol.key_two en.missing_symbol.key_three
|
15
15
|
es.missing_in_es_plural_1.a es.missing_in_es_plural_2.a
|
16
16
|
en.missing-key-with-a-dash.key
|
17
|
+
en.fn_comment
|
17
18
|
)
|
18
19
|
}
|
19
20
|
it 'detects missing or identical' do
|
@@ -6,7 +6,6 @@ describe 'Tree siblings / forest' do
|
|
6
6
|
context 'Node' do
|
7
7
|
it '::new with children' do
|
8
8
|
children = I18n::Tasks::Data::Tree::Siblings.from_key_attr([['a', value: 1]])
|
9
|
-
#require 'byebug'; byebug
|
10
9
|
node = I18n::Tasks::Data::Tree::Node.new(
|
11
10
|
key: 'fr',
|
12
11
|
children: children
|
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.5.
|
4
|
+
version: 0.5.2
|
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-07-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: erubis
|
@@ -201,8 +201,6 @@ files:
|
|
201
201
|
- README.md
|
202
202
|
- Rakefile
|
203
203
|
- bin/i18n-tasks
|
204
|
-
- config/locales/en.yml
|
205
|
-
- config/locales/es.yml
|
206
204
|
- i18n-tasks.gemspec
|
207
205
|
- lib/i18n/tasks.rb
|
208
206
|
- lib/i18n/tasks/base_task.rb
|
data/config/locales/en.yml
DELETED
data/config/locales/es.yml
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
--- {}
|