i18n-tasks 0.2.19 → 0.2.20

Sign up to get free protection for your applications and to get access to all the features.
Files changed (38) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGES.md +5 -1
  3. data/LICENSE.txt +1 -1
  4. data/README.md +51 -39
  5. data/doc/img/i18n-usages.png +0 -0
  6. data/i18n-tasks.gemspec +1 -1
  7. data/lib/i18n/tasks.rb +7 -2
  8. data/lib/i18n/tasks/base_task.rb +2 -4
  9. data/lib/i18n/tasks/configuration.rb +2 -4
  10. data/lib/i18n/tasks/data/adapter/json_adapter.rb +22 -0
  11. data/lib/i18n/tasks/data/adapter/yaml_adapter.rb +21 -0
  12. data/lib/i18n/tasks/data/file_system.rb +13 -0
  13. data/lib/i18n/tasks/data/storage/file_storage.rb +105 -0
  14. data/lib/i18n/tasks/data/yaml.rb +6 -65
  15. data/lib/i18n/tasks/data_traversal.rb +2 -2
  16. data/lib/i18n/tasks/fill_tasks.rb +2 -11
  17. data/lib/i18n/tasks/ignore_keys.rb +3 -1
  18. data/lib/i18n/tasks/key.rb +60 -0
  19. data/lib/i18n/tasks/key_group.rb +65 -0
  20. data/lib/i18n/tasks/missing_keys.rb +51 -18
  21. data/lib/i18n/tasks/reports/base.rb +8 -4
  22. data/lib/i18n/tasks/reports/spreadsheet.rb +8 -8
  23. data/lib/i18n/tasks/reports/terminal.rb +39 -16
  24. data/lib/i18n/tasks/scanners/base_scanner.rb +36 -2
  25. data/lib/i18n/tasks/scanners/pattern_scanner.rb +9 -7
  26. data/lib/i18n/tasks/translation_data.rb +4 -1
  27. data/lib/i18n/tasks/unused_keys.rb +9 -7
  28. data/lib/i18n/tasks/{source_keys.rb → used_keys.rb} +5 -6
  29. data/lib/i18n/tasks/version.rb +1 -1
  30. data/lib/tasks/i18n-tasks.rake +24 -20
  31. data/spec/file_system_data_spec.rb +68 -0
  32. data/spec/fixtures/config/i18n-tasks.yml +2 -2
  33. data/spec/i18n_tasks_spec.rb +5 -5
  34. data/spec/key_group_spec.rb +48 -0
  35. data/spec/used_keys_spec.rb +22 -0
  36. metadata +17 -7
  37. data/lib/i18n/tasks/untranslated_keys.rb +0 -50
  38. data/spec/yaml_adapter_spec.rb +0 -33
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: c8a1d39250f5a17141d7e2ef77087cfbb2350723
4
- data.tar.gz: 4c24ee7926d87036337ef73c85fd19963f512c9c
3
+ metadata.gz: ab1b5fe079fcb795dc047f1e0e4f3d777b83c2ef
4
+ data.tar.gz: 23b4a9f9e87b2f0ed8ac2c8c8a2b1992edc7b90d
5
5
  SHA512:
6
- metadata.gz: fda620af8e5ed8bb3481d2aa64f7961086eed48ad8958f28f54df723bec60e35f2ad006f01d33e9a51abdd0ce1bf338741c9959cc1c5d286e6f93a8026f6d1c1
7
- data.tar.gz: 8f971a9e3024f79310958b5701e9ec255fb14278e3e90464338c42a097cc5fbcbfeaa3e8455975ad5651fc0ceb494f7a5f6c88bce37eecb3d387f8d1871547ce
6
+ metadata.gz: 4100f55d87da5b5131c3adf1794ae10d2fb4b1de691966ff6b24129bf660fca3035a857d841707ceb8946214926646b28aad8f0b2154b77b294a98422b533cd3
7
+ data.tar.gz: 335f197c93d93fc41c27600815a74a964851778050d1d699de15be38998f17a3f5e3354dddcb52708ec50151a5a058cab41fd232de814c6b47e18ddfb6768595
data/CHANGES.md CHANGED
@@ -1,4 +1,8 @@
1
- ## v0.2.17..v0.2.18
1
+ ## v0.2.20
2
+
3
+ * `rake i18n:usages` report
4
+
5
+ ## v0.2.17..v0.2.19
2
6
 
3
7
  * Bugfixes
4
8
 
@@ -1,4 +1,4 @@
1
- Copyright (c) 2013 Gleb Mazovetskiy
1
+ Copyright (c) 2013-2014 Gleb Mazovetskiy
2
2
 
3
3
  MIT License
4
4
 
data/README.md CHANGED
@@ -5,6 +5,21 @@ Tasks to manage translations in ruby applications using I18n.
5
5
 
6
6
  ![i18n-screenshot](https://raw.github.com/glebm/i18n-tasks/master/doc/img/i18n-tasks.gif "i18n-tasks output screenshot")
7
7
 
8
+ ## Installation
9
+
10
+ Simply add to Gemfile:
11
+
12
+ ```ruby
13
+ gem 'i18n-tasks', '~> 0.2.20'
14
+ ```
15
+
16
+ If not using Rails, require the tasks in Rakefile:
17
+
18
+ ```ruby
19
+ # Rakefile
20
+ load 'tasks/i18n-tasks.rake'
21
+ ```
22
+
8
23
  ## Usage
9
24
 
10
25
  Use `rake -T i18n` to get the list of tasks with descriptions. These are [the tasks](/lib/tasks/i18n-tasks.rake) available:
@@ -56,29 +71,13 @@ rake i18n:normalize
56
71
  `i18n:unused` will detect pattern translations and not report them, e.g.:
57
72
 
58
73
  ```ruby
59
- t 'category.' + category.key # 'category.arts_and_crafts' considered used
74
+ t 'category.' + category.key # category.* keys are all considered used
60
75
  t "category.#{category.key}" # also works
61
76
  ```
62
77
 
63
78
  Relative keys (`t '.title'`) and plural keys (key.one/many/other/etc) are fully supported.
64
79
 
65
- For more examples see [the tests](/spec/i18n_tasks_spec.rb).
66
-
67
-
68
- ## Installation
69
-
70
- Simply add to Gemfile:
71
-
72
- ```ruby
73
- gem 'i18n-tasks', '~> 0.2.10'
74
- ```
75
-
76
- If not using Rails, require the tasks in Rakefile:
77
-
78
- ```ruby
79
- # Rakefile
80
- load 'tasks/i18n-tasks.rake'
81
- ```
80
+ Translation data storage, key usage search, and other [settings](#configuration) are compatible with Rails by default.
82
81
 
83
82
  ## Configuration
84
83
 
@@ -92,24 +91,31 @@ base_locale: en
92
91
  locales: [es, fr]
93
92
  ```
94
93
 
94
+ On Rails, if locales are set in the config file, you can make i18n tasks a lot faster by adding this to `Rakefile`:
95
+
96
+ ```ruby
97
+ # disable loading :environment for i18n-tasks
98
+ Rake::Task['i18n:setup'].clear_prerequisites
99
+ ```
100
+
95
101
  ### Storage
96
102
 
97
103
  ```yaml
98
104
  # i18n data storage
99
105
  data:
100
- # The default YAML adapter supports reading from and writing to YAML files
101
- adapter: yaml
106
+ # The default file adapter supports YAML and JSON files. You can provide a custom class name here.
107
+ adapter: file_system
102
108
  # a list of file globs to read from per-locale
103
109
  read:
104
- # this one is default:
110
+ # default:
105
111
  - 'config/locales/%{locale}.yml'
106
- # add this one to also read from namespaced files, e.g. simple_form.en.yml:
112
+ # to also read from namespaced files, e.g. simple_form.en.yml:
107
113
  - 'config/locales/*.%{locale}.yml'
108
114
  # a list of {key pattern => file} routes, matched top to bottom
109
115
  write:
110
- # this would save all devise keys in it's own file (per locale):
116
+ # save all devise keys in it's own file (per locale):
111
117
  - ['devise.*', 'config/locales/devise.%{locale}.yml']
112
- # this is the default catch-all:
118
+ # default catch-all:
113
119
  - 'config/locales/%{locale}.yml' # path is short for ['*', path]
114
120
  ```
115
121
 
@@ -127,13 +133,24 @@ Example:
127
133
  data:
128
134
  write:
129
135
  # store sorcery and simple_form keys in the respective files:
130
- - ['{sorcery,simple_form}.*', 'config/locales/\\1.%{locale}.yml']
131
- # write every namespace to its own file:
136
+ - ['{sorcery,simple_form}.*', 'config/locales/\1.%{locale}.yml']
137
+ # write every key namespace to its own file:
132
138
  - ['{:}.*', 'config/locales/\1.%{locale}.yml']
133
139
  ```
134
140
 
135
141
  ### Usage search
136
142
 
143
+ Inspect all the usages with:
144
+
145
+ ```bash
146
+ rake i18n:usages
147
+ ```
148
+
149
+ ![i18n-screenshot](https://raw.github.com/glebm/i18n-tasks/master/doc/img/i18n-usages.png "rake i18n:usages output screenshot")
150
+
151
+
152
+ Configure usage search in `config/i18n-tasks.yml`:
153
+
137
154
  ```yaml
138
155
  # i18n usage search in source
139
156
  search:
@@ -164,8 +181,8 @@ relative_roots:
164
181
  - app/views-mobile
165
182
  ```
166
183
 
167
- It is also possible to use a key scanner by setting `search.scanner`.
168
- See [the default scanner](/lib/i18n/tasks/scanners/pattern_scanner.rb) for reference.
184
+ It is also possible to use a custom key usage scanner by setting `search.scanner` to a class name.
185
+ See [the default pattern scanner](/lib/i18n/tasks/scanners/pattern_scanner.rb) for reference.
169
186
 
170
187
 
171
188
  ### Fine-tuning
@@ -215,24 +232,23 @@ You might want to test for missing and unused translations as part of your test
215
232
  This is how you can do it with rspec:
216
233
 
217
234
  ```ruby
218
- # spec_helper.rb
235
+ # spec/i18n_keys_spec.rb:
236
+ require 'spec_helper'
237
+
219
238
  require 'i18n/tasks'
220
- require 'i18n/tasks/base_task'
221
239
 
222
- # spec/i18n_keys_spec.rb
223
- require 'spec_helper'
224
- describe 'translation keys' do
240
+ describe 'Translation keys' do
225
241
  let(:i18n) { I18n::Tasks::BaseTask.new }
226
242
 
227
243
  it 'are all present' do
228
- expect(i18n.untranslated_keys).to have(0).keys
244
+ expect(i18n.missing_keys).to have(0).keys
229
245
  end
230
246
 
231
247
  it 'are all used' do
232
248
  expect(i18n.unused_keys).to have(0).keys
233
249
  end
234
-
235
250
  end
251
+
236
252
  ```
237
253
 
238
254
  ## XLSX
@@ -253,7 +269,3 @@ While i18n-tasks does not provide an HTML version of the report, you can add [on
253
269
  This was originally developed for [Zuigo](http://zuigo.com/), a platform to organize and discover events.
254
270
 
255
271
  [MIT license](/LICENSE.txt)
256
-
257
-
258
- [![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/glebm/i18n-tasks/trend.png)](https://bitdeli.com/free "Bitdeli Badge")
259
-
Binary file
@@ -34,6 +34,6 @@ Gem::Specification.new do |s|
34
34
  s.add_development_dependency 'axlsx', '~> 2.0'
35
35
  s.add_development_dependency 'bundler', '~> 1.3'
36
36
  s.add_development_dependency 'rake'
37
- s.add_development_dependency 'rspec-rails'
37
+ s.add_development_dependency 'rspec'
38
38
  s.add_development_dependency 'yard'
39
39
  end
@@ -1,4 +1,3 @@
1
- require 'i18n/tasks/version'
2
1
  require 'active_support/core_ext/hash'
3
2
  require 'active_support/core_ext/string'
4
3
  require 'active_support/core_ext/module/delegation'
@@ -6,7 +5,11 @@ require 'active_support/core_ext/object/try'
6
5
  require 'active_support/core_ext/object/blank'
7
6
  require 'term/ansicolor'
8
7
  require 'erubis'
9
- require 'i18n/tasks/railtie' if defined?(Rails)
8
+
9
+ require 'i18n/tasks/version'
10
+ require 'i18n/tasks/key'
11
+ require 'i18n/tasks/key_group'
12
+ require 'i18n/tasks/base_task'
10
13
 
11
14
  module I18n
12
15
  module Tasks
@@ -29,3 +32,5 @@ module I18n
29
32
  end
30
33
  end
31
34
  end
35
+
36
+ require 'i18n/tasks/railtie' if defined?(Rails)
@@ -3,11 +3,10 @@ require 'i18n/tasks/configuration'
3
3
  require 'i18n/tasks/key_pattern_matching'
4
4
  require 'i18n/tasks/relative_keys'
5
5
  require 'i18n/tasks/plural_keys'
6
- require 'i18n/tasks/source_keys'
6
+ require 'i18n/tasks/used_keys'
7
7
  require 'i18n/tasks/translation_data'
8
8
  require 'i18n/tasks/ignore_keys'
9
9
  require 'i18n/tasks/missing_keys'
10
- require 'i18n/tasks/untranslated_keys'
11
10
  require 'i18n/tasks/unused_keys'
12
11
  require 'i18n/tasks/google_translation'
13
12
  require 'i18n/tasks/fill_tasks'
@@ -21,9 +20,8 @@ module I18n
21
20
  include DataTraversal
22
21
  include RelativeKeys
23
22
  include PluralKeys
24
- include SourceKeys
23
+ include UsedKeys
25
24
  include MissingKeys
26
- include UntranslatedKeys
27
25
  include UnusedKeys
28
26
  include TranslationData
29
27
  include FillTasks
@@ -1,6 +1,4 @@
1
1
  module I18n::Tasks::Configuration
2
- extend ::ActiveSupport::Concern
3
-
4
2
  # i18n-tasks config (defaults + config/i18n-tasks.yml)
5
3
  # @return [Hash{String => String,Hash,Array}]
6
4
  def config
@@ -18,7 +16,7 @@ module I18n::Tasks::Configuration
18
16
  def data_config
19
17
  @config_sections[:data] ||= begin
20
18
  conf = (config[:data] || {}).with_indifferent_access
21
- adapter = (conf[:adapter].presence || conf[:class].presence || :yaml).to_s
19
+ adapter = (conf[:adapter].presence || conf[:class].presence || :file_system).to_s
22
20
  if adapter !~ /[A-Z]/
23
21
  adapter = "I18n::Tasks::Data::#{adapter.camelize}"
24
22
  end
@@ -34,7 +32,7 @@ module I18n::Tasks::Configuration
34
32
  # @return [Hash{String => String,Hash,Array}]
35
33
  def translation_config
36
34
  @config_sections[:translation] ||= begin
37
- conf = (config[:translation] ||= {}).with_indifferent_access
35
+ conf = (config[:translation] || {}).with_indifferent_access
38
36
  conf[:api_key] ||= ENV['GOOGLE_TRANSLATE_API_KEY']
39
37
  conf
40
38
  end
@@ -0,0 +1,22 @@
1
+ require 'json'
2
+
3
+ module I18n::Tasks
4
+ module Data
5
+ module Adapter
6
+ module JsonAdapter
7
+ extend self
8
+
9
+ # @return [Hash] locale tree
10
+ def parse(str)
11
+ JSON.parse(str)
12
+ end
13
+
14
+ # @return [String]
15
+ def dump(tree)
16
+ JSON.generate(tree)
17
+ end
18
+
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,21 @@
1
+ require 'yaml'
2
+ module I18n::Tasks
3
+ module Data
4
+ module Adapter
5
+ module YamlAdapter
6
+ extend self
7
+
8
+ # @return [Hash] locale tree
9
+ def parse(str)
10
+ YAML.load(str)
11
+ end
12
+
13
+ # @return [String]
14
+ def dump(tree)
15
+ tree.to_yaml
16
+ end
17
+
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,13 @@
1
+ require 'i18n/tasks/data/storage/file_storage'
2
+ require 'i18n/tasks/data/adapter/json_adapter'
3
+ require 'i18n/tasks/data/adapter/yaml_adapter'
4
+
5
+ module I18n::Tasks
6
+ module Data
7
+ class FileSystem
8
+ include Storage::FileStorage
9
+ register_adapter '*.yml', Adapter::YamlAdapter
10
+ register_adapter '*.json', Adapter::JsonAdapter
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,105 @@
1
+ require 'i18n/tasks/data_traversal'
2
+ require 'i18n/tasks/key_pattern_matching'
3
+
4
+ module I18n::Tasks
5
+ module Data
6
+ module Storage
7
+ module FileStorage
8
+
9
+ def self.included(base)
10
+ base.extend KlassMethods
11
+ end
12
+
13
+ include ::I18n::Tasks::DataTraversal
14
+ include ::I18n::Tasks::KeyPatternMatching
15
+ attr_reader :config
16
+
17
+ DEFAULTS = {
18
+ read: ['config/locales/%{locale}.yml'],
19
+ write: ['config/locales/%{locale}.yml']
20
+ }.with_indifferent_access
21
+
22
+ def initialize(config = {})
23
+ self.config = config
24
+ end
25
+
26
+ def config=(config)
27
+ opt = DEFAULTS.deep_merge((config || {}).with_indifferent_access)
28
+ @read = opt[:read]
29
+ @write = opt[:write].map { |x| x.is_a?(String) ? ['*', x] : x }.map { |x|
30
+ [compile_key_pattern(x[0]), x[1]]
31
+ }
32
+ @locale_data = {}
33
+ end
34
+
35
+ # get locale tree
36
+ def get(locale)
37
+ locale = locale.to_s
38
+ @locale_data[locale] ||= begin
39
+ @read.map do |path|
40
+ Dir.glob path % {locale: locale}
41
+ end.flatten.map do |locale_file|
42
+ load_file locale_file
43
+ end.inject({}) do |hash, locale_data|
44
+ hash.deep_merge! locale_data || {}
45
+ hash
46
+ end[locale.to_s] || {}
47
+ end
48
+ end
49
+
50
+ alias [] get
51
+
52
+ # set locale tree
53
+ def set(locale, value_tree)
54
+ locale = locale.to_s
55
+ out = {}
56
+ traverse value_tree do |key, value|
57
+ route = @write.detect { |route| route[0] =~ key }
58
+ key_match = $~
59
+ path = route[1] % {locale: locale}
60
+ path.gsub!(/[\\]\d+/) { |m| key_match[m[1..-1].to_i] }
61
+ (out[path] ||= []) << [key, value]
62
+ end
63
+ out.each do |path, data|
64
+ tree = {locale => list_to_tree(data)}
65
+ write_tree(path, tree)
66
+ end
67
+ @locale_data[locale] = nil
68
+ end
69
+
70
+ alias []= set
71
+
72
+ def reload
73
+ @locale_data = {}
74
+ end
75
+
76
+ protected
77
+
78
+ def load_file(file)
79
+ adapter_for(file).parse ::File.read(file)
80
+ end
81
+
82
+ def write_tree(path, tree)
83
+ ::File.open(path, 'w') { |f| f.write(adapter_for(path).dump(tree)) }
84
+ end
85
+
86
+ def adapter_for(file)
87
+ self.class.adapter_for(file)
88
+ end
89
+
90
+ module KlassMethods
91
+ # @param pattern [String] File.fnmatch pattern
92
+ # @param adapter [responds to parse(string)->hash and dump(hash)->string]
93
+ def register_adapter(pattern, adapter)
94
+ (@fn_patterns ||= {})[pattern] = adapter
95
+ end
96
+
97
+ def adapter_for(path)
98
+ @fn_patterns.detect { |pattern, adapter| ::File.fnmatch(pattern, path) }[1] or
99
+ raise "Adapter not found for #{path}. Registered adapters: #{@fn_patterns.inspect}"
100
+ end
101
+ end
102
+ end
103
+ end
104
+ end
105
+ end
@@ -1,72 +1,13 @@
1
- require 'i18n/tasks/data_traversal'
2
- require 'i18n/tasks/key_pattern_matching'
3
- require 'yaml'
1
+ require 'i18n/tasks/data/file_system'
4
2
 
5
3
  module I18n::Tasks
6
4
  module Data
7
- class Yaml
8
- include ::I18n::Tasks::DataTraversal
9
- include ::I18n::Tasks::KeyPatternMatching
10
- attr_reader :config
11
-
12
- DEFAULTS = {
13
- read: ['config/locales/%{locale}.yml'],
14
- write: ['config/locales/%{locale}.yml']
15
- }.with_indifferent_access
16
-
17
- def initialize(config = {})
18
- self.config = config
19
- end
20
-
21
- def config=(config)
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|
25
- [compile_key_pattern(x[0]), x[1]]
26
- }
27
- @locale_data = {}
28
- end
29
-
30
- # get locale tree
31
- def get(locale)
32
- locale = locale.to_s
33
- @locale_data[locale] ||= begin
34
- @read.map do |path|
35
- Dir.glob path % {locale: locale}
36
- end.flatten.map do |locale_file|
37
- YAML.load_file locale_file
38
- end.inject({}) do |hash, locale_data|
39
- hash.deep_merge! locale_data || {}
40
- hash
41
- end[locale.to_s] || {}
42
- end
43
- end
44
-
45
- alias [] get
46
-
47
- # set locale tree
48
- def set(locale, value_tree)
49
- locale = locale.to_s
50
- out = {}
51
- traverse value_tree do |key, value|
52
- route = @write.detect { |route| route[0] =~ key }
53
- key_match = $~
54
- path = route[1] % {locale: locale}
55
- path.gsub!(/[\\]\d+/) { |m| key_match[m[1..-1].to_i] }
56
- (out[path] ||= []) << [key, value]
57
- end
58
- out.each do |path, data|
59
- tree = { locale => list_to_tree(data) }
60
- File.open(path, 'w') { |f| f.write(tree.to_yaml) }
61
- end
62
- @locale_data[locale] = nil
63
- end
64
-
65
- alias []= set
66
-
67
- def reload
68
- @locale_data = {}
5
+ class Yaml < FileSystem
6
+ def initialize(*args)
7
+ super
8
+ I18n::Tasks.warn_deprecated "data.adapter set to 'yaml'. please use 'file_system' instead"
69
9
  end
10
+ register_adapter '*.yml', Adapter::YamlAdapter
70
11
  end
71
12
  end
72
13
  end