i18n-tasks 0.2.15 → 0.2.17

Sign up to get free protection for your applications and to get access to all the features.
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