i18n-tasks 0.2.15 → 0.2.17

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: 217d5375c8adaf43404a25edbb7b8d1e0ace0846
4
- data.tar.gz: 7cb0ada61b7e6d10f4da54c879eb8955eed92400
3
+ metadata.gz: f5078ec1751923ec5ebfcd79893a7bdca8ae618f
4
+ data.tar.gz: e29ebefde17fdbefc0408452466e5f1a19a2be71
5
5
  SHA512:
6
- metadata.gz: c8a931302b28482f56cef52028280832c0a9e963c9e6c4ee28131c139db5b4e2667719f7776f192a8106b91200704ca80e8e1b5c2152a04dfa8b5410dc7c1579
7
- data.tar.gz: 4e9597da0828551fcd2fb82ae0a2a21d84bf4f699137d6b16e58b4de57433554ea2f6b44a21f64841271ddc71b21b87cd1aa6458db9b5b59da24dd504c3b8ca6
6
+ metadata.gz: 55359af166cef34bd9c4708a0a482d5107d54d347615172b39803559355d8738e6da03901562a509ae8b6474cdda7ee6b19d4044a1978520d7cee9e9d81bfacb
7
+ data.tar.gz: a05eb27caad0776691685f6e70ce271084adf7ae4d71c97f1898736501ddd9b7a5a47627dd1f4623349764dd281aa6ef344aa763190ce38799d882bd565933f5
data/CHANGES.md CHANGED
@@ -1,4 +1,13 @@
1
- ## v0.2.14.
1
+ ## v0.2.16
2
+
3
+ * Key search extracted into its own class, and a custom scanner can now be provided.
4
+ * Removed support for deprecated settings
5
+
6
+ ## v0.2.15
7
+
8
+ * More robust I18n.t call detection (detect I18n.translate and multiline calls)
9
+
10
+ ## v0.2.14
2
11
 
3
12
  * Google Translate fixes: preserve interpolations, set correct format based on the key (text or html).
4
13
 
data/README.md CHANGED
@@ -172,6 +172,9 @@ relative_roots:
172
172
  - app/views-mobile
173
173
  ```
174
174
 
175
+ It is also possible to use a key scanner by setting `search.scanner`.
176
+ See [the default scanner](/lib/i18n/tasks/scanners/pattern_scanner.rb) for reference.
177
+
175
178
 
176
179
  ### Fine-tuning
177
180
 
@@ -224,18 +227,19 @@ This is how you can do it with rspec:
224
227
  require 'i18n/tasks'
225
228
  require 'i18n/tasks/base_task'
226
229
 
227
- # spec/locales_spec.rb
230
+ # spec/i18n_keys_spec.rb
228
231
  require 'spec_helper'
229
- describe 'translations' do
232
+ describe 'translation keys' do
230
233
  let(:i18n) { I18n::Tasks::BaseTask.new }
231
234
 
232
- it 'are all used' do
233
- i18n.unused_keys.should have(0).keys
235
+ it 'are all present' do
236
+ expect(i18n.untranslated_keys).to have(0).keys
234
237
  end
235
238
 
236
- it 'are all present' do
237
- i18n.untranslated_keys.should have(0).keys
239
+ it 'are all used' do
240
+ expect(i18n.unused_keys).to have(0).keys
238
241
  end
242
+
239
243
  end
240
244
  ```
241
245
 
@@ -26,33 +26,10 @@ module I18n::Tasks::Configuration
26
26
  end
27
27
  end
28
28
 
29
- DEFAULT_PATTERN = /\bt(?:ranslate)?[( ]\s*(:?".+?"|:?'.+?'|:\w+)/
30
- # search config
31
- # @return [Hash{String => String,Hash,Array}]
32
- def search_config
33
- @config_sections[:search] ||= begin
34
- if config.key?(:grep)
35
- config[:search] ||= config.delete(:grep)
36
- I18n::Tasks.warn_deprecated 'please rename "grep" key to "search" in config/i18n-tasks.yml'
37
- end
38
- search_config = (config[:search] || {}).with_indifferent_access
39
- search_config.tap do |conf|
40
- conf[:paths] = %w(app/) if conf[:paths].blank?
41
- conf[:include] = Array(conf[:include]) if conf[:include].present?
42
- conf[:exclude] = Array(conf[:exclude])
43
- conf[:pattern] = conf[:pattern].present? ? Regexp.new(conf[:pattern]) : DEFAULT_PATTERN
44
- end
45
- end
46
- end
47
-
48
29
  def relative_roots
49
30
  @config_sections[:relative_roots] ||= config[:relative_roots].presence || %w(app/views)
50
31
  end
51
32
 
52
- def relative_roots=(paths)
53
- @config_sections[:relative_roots] = paths
54
- end
55
-
56
33
  # translation config
57
34
  # @return [Hash{String => String,Hash,Array}]
58
35
  def translation_config
@@ -19,14 +19,9 @@ module I18n::Tasks
19
19
  end
20
20
 
21
21
  def config=(config)
22
- opt = (config || {}).with_indifferent_access
23
- if opt.key?(:paths)
24
- opt[:read] ||= opt.delete(:paths)
25
- ::I18n::Tasks.warn_deprecated 'please rename "data.paths" key to "data.read" in config/i18n-tasks.yml'
26
- end
27
- opt = DEFAULTS.deep_merge(opt)
28
- @read = opt[:read]
29
- @write = opt[:write].map { |x| x.is_a?(String) ? ['*', x] : x }.map { |x|
22
+ opt = DEFAULTS.deep_merge((config || {}).with_indifferent_access)
23
+ @read = opt[:read]
24
+ @write = opt[:write].map { |x| x.is_a?(String) ? ['*', x] : x }.map { |x|
30
25
  [compile_key_pattern(x[0]), x[1]]
31
26
  }
32
27
  @locale_data = {}
@@ -34,7 +29,7 @@ module I18n::Tasks
34
29
 
35
30
  # get locale tree
36
31
  def get(locale)
37
- locale = locale.to_s
32
+ locale = locale.to_s
38
33
  @locale_data[locale] ||= begin
39
34
  @read.map do |path|
40
35
  Dir.glob path % {locale: locale}
@@ -17,9 +17,6 @@ module I18n::Tasks::KeyPatternMatching
17
17
  # : matches a single key
18
18
  # {a, b.c} match any in set, can use : and *, match is captured
19
19
  def compile_key_pattern(key_pattern)
20
- if key_pattern.end_with? '.'
21
- I18n::Tasks.warn_deprecated %Q(please change pattern "#{key_pattern}" to "#{key_pattern += '*'}" in config/i18n-tasks.yml)
22
- end
23
20
  /^#{key_pattern.
24
21
  gsub(/\./, '\.').
25
22
  gsub(/\*/, '.*').
@@ -43,4 +40,4 @@ module I18n::Tasks::KeyPatternMatching
43
40
  /^(?:#{prefixes.map { |p| Regexp.escape(p) }.join('|')})/
44
41
  end
45
42
  end
46
- end
43
+ end
@@ -1,15 +1,18 @@
1
- module I18n::Tasks::RelativeKeys
2
-
3
- # @param key [String] relative i18n key (starts with a .)
4
- # @param path [String] path to the file containing the key
5
- # @return [String] absolute version of the key
6
- def absolutize_key(key, path, roots = relative_roots)
7
- # normalized path
8
- path = File.expand_path path
9
- (path_root = roots.map { |path| File.expand_path path }.sort.reverse.detect { |root| path.start_with?(root + '/') }) or
10
- raise "No relative key root detected for \"#{key}\" at #{path}. Please set relative_roots in config/i18n-tasks.yml (currently set to #{relative_roots})"
11
- # key prefix based on path
12
- prefix = path.gsub(%r(#{path_root}/|(\.[^/]+)*$), '').tr('/', '.').gsub(%r(\._), '.')
13
- "#{prefix}#{key}"
1
+ module I18n
2
+ module Tasks
3
+ module RelativeKeys
4
+ # @param key [String] relative i18n key (starts with a .)
5
+ # @param path [String] path to the file containing the key
6
+ # @return [String] absolute version of the key
7
+ def absolutize_key(key, path, roots = relative_roots)
8
+ # normalized path
9
+ path = File.expand_path path
10
+ (path_root = roots.map { |path| File.expand_path path }.sort.reverse.detect { |root| path.start_with?(root + '/') }) or
11
+ raise "No relative key root detected for \"#{key}\" at #{path}. Please set relative_roots in config/i18n-tasks.yml (currently set to #{relative_roots})"
12
+ # key prefix based on path
13
+ prefix = path.gsub(%r(#{path_root}/|(\.[^/]+)*$), '').tr('/', '.').gsub(%r(\._), '.')
14
+ "#{prefix}#{key}"
15
+ end
16
+ end
14
17
  end
15
18
  end
@@ -0,0 +1,65 @@
1
+ require 'i18n/tasks/relative_keys'
2
+ module I18n::Tasks::Scanners
3
+ class BaseScanner
4
+ include ::I18n::Tasks::RelativeKeys
5
+ attr_reader :config
6
+
7
+ def initialize(config)
8
+ @config = config.dup.with_indifferent_access.tap do |conf|
9
+ conf[:paths] = %w(app/) if conf[:paths].blank?
10
+ conf[:include] = Array(conf[:include]) if conf[:include].present?
11
+ conf[:exclude] = Array(conf[:exclude])
12
+ end
13
+ end
14
+
15
+ # @return [Array] found key usages, absolutized and unique
16
+ def keys
17
+ @keys ||= traverse_files { |path| scan_file(path) }.flatten.uniq
18
+ end
19
+
20
+ # @return [String] keys used in file (unimplemented)
21
+ def scan_file(path)
22
+ raise 'Unimplemented'
23
+ end
24
+
25
+ # Run given block for every relevant file, according to config
26
+ # @return [Array] Results of block calls
27
+ def traverse_files
28
+ result = []
29
+ Find.find(*config[:paths]) do |path|
30
+ next if File.directory?(path)
31
+ next if config[:include] and !config[:include].any? { |glob| File.fnmatch(glob, path) }
32
+ next if config[:exclude].any? { |glob| File.fnmatch(glob, path) }
33
+ result << yield(path)
34
+ end
35
+ result
36
+ end
37
+
38
+ protected
39
+
40
+ def extract_key_from_match(match, path)
41
+ key = strip_literal(match[0])
42
+ key = absolutize_key(key, path) if path && key.start_with?('.')
43
+ key
44
+ end
45
+
46
+ # remove the leading colon and unwrap quotes from the key match
47
+ def strip_literal(literal)
48
+ key = literal
49
+ key.slice!(0) if ':' == key[0]
50
+ key = key[1..-2] if %w(' ").include?(key[0])
51
+ key
52
+ end
53
+
54
+ VALID_KEY_RE = /^[\w.\#{}]+$/
55
+
56
+ def valid_key?(key)
57
+ key =~ VALID_KEY_RE
58
+ end
59
+
60
+ def relative_roots
61
+ config[:relative_roots]
62
+ end
63
+
64
+ end
65
+ end
@@ -0,0 +1,26 @@
1
+ # Scans for I18n.t usages
2
+ require 'i18n/tasks/scanners/base_scanner'
3
+ module I18n::Tasks::Scanners
4
+ class PatternScanner < BaseScanner
5
+ LITERAL_RE = /:?".+?"|:?'.+?'|:\w+/
6
+ DEFAULT_PATTERN = /\bt(?:ranslate)?[( ]\s*(#{LITERAL_RE})/
7
+
8
+ # Extract i18n keys from file based on the pattern. The pattern must capture key literal.
9
+ # @return [String] keys found in file
10
+ def scan_file(path)
11
+ keys = []
12
+ File.open(path, 'rb') do |f|
13
+ f.read.scan(pattern) do |match|
14
+ key = extract_key_from_match(match, path)
15
+ keys << key if valid_key?(key)
16
+ end
17
+ end
18
+ keys
19
+ end
20
+
21
+ protected
22
+ def pattern
23
+ @pattern ||= config[:pattern].present? ? Regexp.new(config[:pattern]) : DEFAULT_PATTERN
24
+ end
25
+ end
26
+ end
@@ -1,12 +1,19 @@
1
1
  require 'find'
2
+ require 'i18n/tasks/scanners/pattern_scanner'
2
3
 
3
4
  module I18n::Tasks::SourceKeys
4
- # find all keys in the source (relative keys are returned in absolutized)
5
+ # find all keys in the source (relative keys are absolutized)
5
6
  # @return [Array<String>]
6
7
  def find_source_keys
7
- @source_keys ||= traverse_files do |path|
8
- extract_keys(path)
9
- end.flatten.uniq
8
+ @source_keys ||= scanner.keys
9
+ end
10
+
11
+ def scanner
12
+ @scanner ||= begin
13
+ search_config = config[:search].with_indifferent_access
14
+ class_name = search_config[:scanner] || '::I18n::Tasks::Scanners::PatternScanner'
15
+ class_name.constantize.new search_config.merge(relative_roots: relative_roots)
16
+ end
10
17
  end
11
18
 
12
19
  # whether the key is used in the source
@@ -26,42 +33,4 @@ module I18n::Tasks::SourceKeys
26
33
  @pattern_keys_prefixes ||=
27
34
  find_source_keys.select { |k| k =~ /\#{.*?}/ || k.ends_with?('.') }.map { |k| k.split(/\.?#/)[0].presence }.compact
28
35
  end
29
-
30
- # Run given block for every relevant file, according to search_config
31
- # @return [Array] Results of block calls
32
- def traverse_files
33
- result = []
34
- Find.find(*search_config[:paths]) do |path|
35
- next if File.directory?(path)
36
- next if search_config[:include] and !search_config[:include].any? { |glob| File.fnmatch(glob, path) }
37
- next if search_config[:exclude].any? { |glob| File.fnmatch(glob, path) }
38
- result << yield(path)
39
- end
40
- result
41
- end
42
-
43
- # Extract i18n keys from file
44
- # @return [String] keys used in file (absolutized and unique)
45
- def extract_keys(path)
46
- keys = []
47
- File.open(path, 'rb') do |f|
48
- f.read.scan(search_config[:pattern]) do |match|
49
- key = parse_key(match)
50
- key = absolutize_key(key, path) if key.start_with? '.'
51
- if key =~ /^[\w.\#{}]+$/
52
- keys << key
53
- end
54
- end
55
- end
56
- keys
57
- end
58
-
59
- private
60
- # remove the leading colon and unwrap quotes from the key match
61
- def parse_key(match)
62
- key = match[0]
63
- key.slice!(0) if ':' == key[0]
64
- key = key[1..-2] if %w(' ").include?(key[0])
65
- key
66
- end
67
36
  end
@@ -1,5 +1,5 @@
1
1
  module I18n
2
2
  module Tasks
3
- VERSION = '0.2.15'
3
+ VERSION = '0.2.17'
4
4
  end
5
5
  end
@@ -1,9 +1,8 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe 'Source keys' do
4
- let!(:task) { I18n::Tasks::BaseTask.new }
5
- describe 'pattern' do
6
- let!(:pattern) { task.search_config[:pattern] }
3
+ describe 'Pattern Scanner' do
4
+ describe 'default pattern' do
5
+ let!(:pattern) { I18n::Tasks::Scanners::PatternScanner::DEFAULT_PATTERN }
7
6
 
8
7
  ['t "a.b"', "t 'a.b'", 't("a.b")', "t('a.b')",
9
8
  "t('a.b', :arg => val)", "t('a.b', arg: val)",
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.2.15
4
+ version: 0.2.17
5
5
  platform: ruby
6
6
  authors:
7
7
  - glebm
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-01-07 00:00:00.000000000 Z
11
+ date: 2014-01-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -213,6 +213,8 @@ files:
213
213
  - lib/i18n/tasks/reports/base.rb
214
214
  - lib/i18n/tasks/reports/spreadsheet.rb
215
215
  - lib/i18n/tasks/reports/terminal.rb
216
+ - lib/i18n/tasks/scanners/base_scanner.rb
217
+ - lib/i18n/tasks/scanners/pattern_scanner.rb
216
218
  - lib/i18n/tasks/source_keys.rb
217
219
  - lib/i18n/tasks/translation_data.rb
218
220
  - lib/i18n/tasks/untranslated_keys.rb
@@ -227,9 +229,9 @@ files:
227
229
  - spec/google_translate_spec.rb
228
230
  - spec/i18n_tasks_spec.rb
229
231
  - spec/key_pattern_matching_spec.rb
232
+ - spec/pattern_scanner_spec.rb
230
233
  - spec/readme_spec.rb
231
234
  - spec/relative_keys_spec.rb
232
- - spec/source_keys_spec.rb
233
235
  - spec/spec_helper.rb
234
236
  - spec/support/fixtures.rb
235
237
  - spec/support/i18n_tasks_output_matcher.rb
@@ -272,9 +274,9 @@ test_files:
272
274
  - spec/google_translate_spec.rb
273
275
  - spec/i18n_tasks_spec.rb
274
276
  - spec/key_pattern_matching_spec.rb
277
+ - spec/pattern_scanner_spec.rb
275
278
  - spec/readme_spec.rb
276
279
  - spec/relative_keys_spec.rb
277
- - spec/source_keys_spec.rb
278
280
  - spec/spec_helper.rb
279
281
  - spec/support/fixtures.rb
280
282
  - spec/support/i18n_tasks_output_matcher.rb