i18n-tasks 0.3.4 → 0.3.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGES.md +4 -0
- data/README.md +9 -12
- data/bin/i18n-tasks +2 -6
- data/i18n-tasks.gemspec +4 -5
- data/lib/i18n/tasks.rb +1 -4
- data/lib/i18n/tasks/base_task.rb +2 -0
- data/lib/i18n/tasks/commands_base.rb +2 -3
- data/lib/i18n/tasks/configuration.rb +13 -5
- data/lib/i18n/tasks/data/storage/file_storage.rb +22 -0
- data/lib/i18n/tasks/logging.rb +15 -0
- data/lib/i18n/tasks/missing_keys.rb +1 -1
- data/lib/i18n/tasks/version.rb +1 -1
- data/spec/file_system_data_spec.rb +60 -28
- data/spec/plural_keys_spec.rb +43 -0
- metadata +8 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 188bad44ecd17931f47d9a52c8c757090f01b44c
|
4
|
+
data.tar.gz: b2be17a08191fed3f80262d829c0a2d6251d3318
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2ceecebcd0b87015d6d5487f7a4e6e658f76a066d3960cf7b55e741ecbd7f99445c8110cb5b7a33f18f1319d27c6fbab014a7209e57033c071dc220fd815d419
|
7
|
+
data.tar.gz: 1de63c98ea3c1e7ad37cd00359e8e7e1cda7cdadfa454b44a7e7ae9a84a0b7789c96828d3093e3ac2bd45095f303fe21f9e4d65d7c37cbd356047505139cc077
|
data/CHANGES.md
CHANGED
data/README.md
CHANGED
@@ -11,20 +11,12 @@ This information is inferred based on the keys the gem detects used with calls s
|
|
11
11
|
|
12
12
|
## Installation
|
13
13
|
|
14
|
-
|
14
|
+
Add to Gemfile:
|
15
15
|
|
16
16
|
```ruby
|
17
17
|
gem 'i18n-tasks', '~> 0.3.2'
|
18
18
|
```
|
19
19
|
|
20
|
-
2. Create a config file at `config/i18n-tasks.yml`:
|
21
|
-
|
22
|
-
```yaml
|
23
|
-
# config/i18n-tasks.yml
|
24
|
-
base_locale: en
|
25
|
-
locales: [es, fr] # This includes base_locale by default
|
26
|
-
```
|
27
|
-
|
28
20
|
## Usage
|
29
21
|
|
30
22
|
Run `i18n-tasks` to get the list of tasks with short descriptions.
|
@@ -112,9 +104,8 @@ Inspect configuration with `i18n-tasks config`.
|
|
112
104
|
|
113
105
|
### Locales
|
114
106
|
|
115
|
-
By default,
|
116
|
-
|
117
|
-
so it is recommended to set locale settings explicitly:
|
107
|
+
By default, `base_locale` is set to `en` and `locales` are inferred from the paths to data files.
|
108
|
+
You can override these in the config:
|
118
109
|
|
119
110
|
```yaml
|
120
111
|
# config/i18n-tasks.yml
|
@@ -127,6 +118,7 @@ locales: [es, fr] # This includes base_locale by default
|
|
127
118
|
The default data adapter supports YAML and JSON files.
|
128
119
|
|
129
120
|
```yaml
|
121
|
+
# config/i18n-tasks.yml
|
130
122
|
# i18n data storage
|
131
123
|
data:
|
132
124
|
# file_system is the default adapter, you can provide a custom class name here:
|
@@ -156,6 +148,7 @@ data:
|
|
156
148
|
Example:
|
157
149
|
|
158
150
|
```yaml
|
151
|
+
# config/i18n-tasks.yml
|
159
152
|
data:
|
160
153
|
write:
|
161
154
|
# store sorcery and simple_form keys in the respective files:
|
@@ -170,6 +163,7 @@ data:
|
|
170
163
|
Configure usage search in `config/i18n-tasks.yml`:
|
171
164
|
|
172
165
|
```yaml
|
166
|
+
# config/i18n-tasks.yml
|
173
167
|
# i18n usage search in source
|
174
168
|
search:
|
175
169
|
# search these directories (relative to your Rails.root directory, default: 'app/')
|
@@ -191,6 +185,7 @@ search:
|
|
191
185
|
To configure paths for relative key resolution:
|
192
186
|
|
193
187
|
```yaml
|
188
|
+
# config/i18n-tasks.yml
|
194
189
|
# directories containing relative keys
|
195
190
|
relative_roots:
|
196
191
|
# default:
|
@@ -209,6 +204,7 @@ Tasks may incorrectly report framework i18n keys as missing, also some patterns
|
|
209
204
|
When all else fails, use the options below.
|
210
205
|
|
211
206
|
```yaml
|
207
|
+
# config/i18n-tasks.yml
|
212
208
|
# do not report these keys as unused
|
213
209
|
ignore_unused:
|
214
210
|
- category.*.db_name
|
@@ -240,6 +236,7 @@ ignore:
|
|
240
236
|
Put the key in `GOOGLE_TRANSLATE_API_KEY` environment variable or in the config file.
|
241
237
|
|
242
238
|
```yaml
|
239
|
+
# config/i18n-tasks.yml
|
243
240
|
translation:
|
244
241
|
api_key: <Google Translate API key>
|
245
242
|
```
|
data/bin/i18n-tasks
CHANGED
@@ -28,15 +28,11 @@ if command
|
|
28
28
|
args = command[2]
|
29
29
|
|
30
30
|
if opts.empty? && args.empty?
|
31
|
-
|
32
|
-
STDERR.puts Term::ANSIColor.green "i18n-tasks: run #{meth.tr('_', '-')} without arguments"
|
33
|
-
end
|
31
|
+
::I18n::Tasks.log_verbose "run #{meth.tr('_', '-')} without arguments"
|
34
32
|
cmd.send meth
|
35
33
|
else
|
36
34
|
opts = opts.merge(arguments: args) unless args.empty?
|
37
|
-
|
38
|
-
STDERR.puts Term::ANSIColor.green "i18n-tasks: run #{meth.tr('_', '-')} with #{opts.map { |k, v| "#{k}=#{v}" } * ' '}"
|
39
|
-
end
|
35
|
+
::I18n::Tasks.log_verbose "run #{meth.tr('_', '-')} with #{opts.map { |k, v| "#{k}=#{v}" } * ' '}"
|
40
36
|
cmd.send meth, opts
|
41
37
|
end
|
42
38
|
else
|
data/i18n-tasks.gemspec
CHANGED
@@ -10,13 +10,12 @@ Gem::Specification.new do |s|
|
|
10
10
|
s.email = ['glex.spb@gmail.com']
|
11
11
|
s.summary = %q{Manage translations in ruby applications with the awesome power of static analysis — Edit}
|
12
12
|
s.description = %q{
|
13
|
-
The basic approach to i18n key management in frameworks such as Rails
|
14
|
-
|
13
|
+
The basic approach to i18n key management in frameworks such as Rails is far from perfect.
|
15
14
|
If you use a key that does not exist, this will only blow up at runtime. Keys left over from removed code accumulate
|
16
|
-
in the resource files, introducing unnecessary overhead on the translators.
|
17
|
-
Translation files can quickly turn to disarray.
|
15
|
+
in the resource files, introducing unnecessary overhead on the translators. Translation files can quickly turn to disarray.
|
18
16
|
|
19
|
-
i18n-tasks
|
17
|
+
i18n-tasks improves this by using static analysis. It provides tasks to find and manage missing and unused translations.
|
18
|
+
This information is inferred based on the keys the gem detects used with calls such as `I18n.t` when scanning the code.
|
20
19
|
}
|
21
20
|
s.homepage = 'https://github.com/glebm/i18n-tasks'
|
22
21
|
if s.respond_to?(:metadata=)
|
data/lib/i18n/tasks.rb
CHANGED
@@ -25,10 +25,7 @@ module I18n
|
|
25
25
|
HashWithIndifferentAccess.new.merge(file.presence || {})
|
26
26
|
end
|
27
27
|
end
|
28
|
-
|
29
|
-
def warn_deprecated(message)
|
30
|
-
STDERR.puts Term::ANSIColor.yellow Term::ANSIColor.bold "i18n-tasks: [DEPRECATED] #{message}"
|
31
|
-
end
|
28
|
+
include ::I18n::Tasks::Logging
|
32
29
|
end
|
33
30
|
end
|
34
31
|
end
|
data/lib/i18n/tasks/base_task.rb
CHANGED
@@ -10,6 +10,7 @@ require 'i18n/tasks/missing_keys'
|
|
10
10
|
require 'i18n/tasks/unused_keys'
|
11
11
|
require 'i18n/tasks/google_translation'
|
12
12
|
require 'i18n/tasks/fill_tasks'
|
13
|
+
require 'i18n/tasks/logging'
|
13
14
|
|
14
15
|
module I18n
|
15
16
|
module Tasks
|
@@ -26,6 +27,7 @@ module I18n
|
|
26
27
|
include TranslationData
|
27
28
|
include FillTasks
|
28
29
|
include GoogleTranslation
|
30
|
+
include Logging
|
29
31
|
|
30
32
|
def initialize(config = {})
|
31
33
|
self.config = config || {}
|
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'ostruct'
|
2
2
|
module I18n::Tasks
|
3
3
|
class CommandsBase
|
4
|
+
include ::I18n::Tasks::Logging
|
4
5
|
def locales_opt(locales)
|
5
6
|
return i18n_task.locales if locales == ['all'] || locales == 'all'
|
6
7
|
if locales.present?
|
@@ -14,9 +15,7 @@ module I18n::Tasks
|
|
14
15
|
|
15
16
|
def locales_opt_or_args(opt)
|
16
17
|
locales_opt(opt[:arguments].presence || opt[:locales]).tap do |locales|
|
17
|
-
|
18
|
-
STDERR.puts Term::ANSIColor.green "i18n-tasks: locales are #{locales.inspect}"
|
19
|
-
end
|
18
|
+
log_verbose "locales for the command are #{locales.inspect}"
|
20
19
|
end
|
21
20
|
end
|
22
21
|
|
@@ -48,18 +48,26 @@ module I18n::Tasks::Configuration
|
|
48
48
|
# @return [Array<String>] all available locales, base_locale is always first
|
49
49
|
def locales
|
50
50
|
@config_sections[:locales] ||= begin
|
51
|
-
locales =
|
52
|
-
|
53
|
-
|
51
|
+
locales = config[:locales]
|
52
|
+
locales ||= data.available_locales
|
53
|
+
locales = locales.map(&:to_s)
|
54
|
+
locales = if locales.include?(base_locale)
|
55
|
+
[base_locale] + (locales - [base_locale])
|
56
|
+
else
|
57
|
+
[base_locale] + locales
|
58
|
+
end
|
59
|
+
if config[:locales]
|
60
|
+
log_verbose "config.locales set to #{locales}"
|
54
61
|
else
|
55
|
-
|
62
|
+
log_verbose "config.locales inferred from data #{locales}"
|
56
63
|
end
|
64
|
+
locales
|
57
65
|
end
|
58
66
|
end
|
59
67
|
|
60
68
|
# @return [String] default i18n locale
|
61
69
|
def base_locale
|
62
|
-
@config_sections[:base_locale] ||= config[:base_locale] ||
|
70
|
+
@config_sections[:base_locale] ||= (config[:base_locale] || 'en').to_s
|
63
71
|
end
|
64
72
|
|
65
73
|
# evaluated configuration (as the app sees it)
|
@@ -71,6 +71,28 @@ module I18n::Tasks
|
|
71
71
|
|
72
72
|
def reload
|
73
73
|
@locale_data = {}
|
74
|
+
@available_locales = nil
|
75
|
+
self
|
76
|
+
end
|
77
|
+
|
78
|
+
# Get available locales from the list of file names to read
|
79
|
+
def available_locales
|
80
|
+
@available_locales ||= begin
|
81
|
+
locales = Set.new
|
82
|
+
@read.map do |pattern|
|
83
|
+
[pattern, Dir.glob(pattern % {locale: '*'})] if pattern.include?('%{locale}')
|
84
|
+
end.compact.each do |pattern, paths|
|
85
|
+
p = pattern.gsub('\\', '\\\\').gsub('/', '\/').gsub('.', '\.')
|
86
|
+
p = p.gsub(/(\*+)/) { $1 == '**' ? '.*' : '[^/]*?' }.gsub('%{locale}', '([^/.]+)')
|
87
|
+
re = /\A#{p}\z/
|
88
|
+
paths.each do |path|
|
89
|
+
if re =~ path
|
90
|
+
locales << $1
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
locales
|
95
|
+
end
|
74
96
|
end
|
75
97
|
|
76
98
|
protected
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module I18n::Tasks::Logging
|
2
|
+
def warn_deprecated(message)
|
3
|
+
log_stderr Term::ANSIColor.yellow Term::ANSIColor.bold "i18n-tasks: [DEPRECATED] #{message}"
|
4
|
+
end
|
5
|
+
|
6
|
+
def log_verbose(message)
|
7
|
+
if ENV['VERBOSE']
|
8
|
+
log_stderr Term::ANSIColor.green "i18n-tasks: #{message}"
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def log_stderr(*args)
|
13
|
+
STDERR.puts *args
|
14
|
+
end
|
15
|
+
end
|
@@ -26,7 +26,7 @@ module I18n::Tasks
|
|
26
26
|
end
|
27
27
|
|
28
28
|
def untranslated_keys(locales = nil)
|
29
|
-
|
29
|
+
warn_deprecated '#untranslated_keys. Please use #missing_keys instead'
|
30
30
|
missing_keys(locales: locales)
|
31
31
|
end
|
32
32
|
|
data/lib/i18n/tasks/version.rb
CHANGED
@@ -1,41 +1,73 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe 'File system i18n' do
|
4
|
+
describe '#available_locales' do
|
5
|
+
before do
|
6
|
+
TestCodebase.setup(
|
7
|
+
'config/locales/en.yml' => {en: {}},
|
8
|
+
'config/locales/es.yml' => {es: {}},
|
9
|
+
'config/locales/other.fr.yml' => {fr: {}}
|
10
|
+
)
|
11
|
+
end
|
12
|
+
after do
|
13
|
+
TestCodebase.teardown
|
14
|
+
end
|
15
|
+
let(:data) { I18n::Tasks::Data::FileSystem.new }
|
16
|
+
it 'default pattern' do
|
17
|
+
data.config = {read: ['config/locales/%{locale}.yml']}
|
18
|
+
TestCodebase.in_test_app_dir {
|
19
|
+
expect(data.available_locales.sort).to eq(%w(en es).sort)
|
20
|
+
}
|
21
|
+
end
|
22
|
+
it 'more inclusive pattern' do
|
23
|
+
data.config = {read: ['config/locales/*%{locale}.yml']}
|
24
|
+
TestCodebase.in_test_app_dir {
|
25
|
+
expect(data.available_locales.sort).to eq(%w(en es fr).sort)
|
26
|
+
}
|
27
|
+
end
|
28
|
+
it 'another pattern' do
|
29
|
+
data.config = {read: ['config/locales/*.%{locale}.yml']}
|
30
|
+
TestCodebase.in_test_app_dir {
|
31
|
+
expect(data.available_locales.sort).to eq(%w(fr).sort)
|
32
|
+
}
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
4
36
|
describe 'yml' do
|
5
|
-
|
6
|
-
|
37
|
+
let(:data) { I18n::Tasks::Data::FileSystem.new }
|
38
|
+
after { TestCodebase.teardown }
|
7
39
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
40
|
+
it '#get' do
|
41
|
+
data.config = {read: ['a.yml', '{b,c}.yml']}
|
42
|
+
TestCodebase.setup(
|
43
|
+
'a.yml' => {en: {a: 1}}.stringify_keys.to_yaml,
|
44
|
+
'b.yml' => {en: {b: 1}}.stringify_keys.to_yaml,
|
45
|
+
'c.yml' => {en: {c: 1}}.stringify_keys.to_yaml
|
46
|
+
)
|
47
|
+
TestCodebase.in_test_app_dir {
|
48
|
+
expect(data[:en].symbolize_keys).to eq(a: 1, b: 1, c: 1)
|
49
|
+
}
|
50
|
+
end
|
19
51
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
52
|
+
it '#set' do
|
53
|
+
data.config = {read: 'a.yml', write: [['{:}.*', '\1.%{locale}.yml']]}
|
54
|
+
keys = {'a' => {'b' => 'c'}, 'x' => 'y'}
|
55
|
+
locale_data = {'pizza' => keys, 'sushi' => keys}
|
56
|
+
TestCodebase.setup
|
57
|
+
TestCodebase.in_test_app_dir {
|
58
|
+
data[:en] = locale_data
|
59
|
+
files = %w(pizza.en.yml sushi.en.yml)
|
60
|
+
Dir['*.yml'].sort.should == files.sort
|
61
|
+
files.each { |f| YAML.load_file(f)['en'].should == {File.basename(f, '.en.yml') => keys} }
|
62
|
+
}
|
63
|
+
end
|
32
64
|
end
|
33
65
|
|
34
66
|
describe 'json' do
|
35
67
|
let!(:data) {
|
36
68
|
I18n::Tasks::Data::FileSystem.new(
|
37
|
-
|
38
|
-
|
69
|
+
read: ['config/locales/%{locale}.json'],
|
70
|
+
write: ['config/locales/%{locale}.json']
|
39
71
|
)
|
40
72
|
}
|
41
73
|
after { TestCodebase.teardown }
|
@@ -48,7 +80,7 @@ describe 'File system i18n' do
|
|
48
80
|
'c.json' => {en: {c: 1}}.stringify_keys.to_json
|
49
81
|
)
|
50
82
|
TestCodebase.in_test_app_dir {
|
51
|
-
data[:en].symbolize_keys.
|
83
|
+
expect(data[:en].symbolize_keys).to eq(a: 1, b: 1, c: 1)
|
52
84
|
}
|
53
85
|
end
|
54
86
|
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'Plural keys' do
|
4
|
+
let(:task) { ::I18n::Tasks::BaseTask.new }
|
5
|
+
before do
|
6
|
+
TestCodebase.setup('config/locales/en.yml' => '')
|
7
|
+
TestCodebase.in_test_app_dir do
|
8
|
+
task.data['en'] = {
|
9
|
+
'regular_key' => 'a',
|
10
|
+
'plural_key' => {
|
11
|
+
'one' => 'one', 'other' => '%{count}'
|
12
|
+
},
|
13
|
+
'not_really_plural' => {
|
14
|
+
'one' => 'a',
|
15
|
+
'green' => 'b'
|
16
|
+
}
|
17
|
+
}
|
18
|
+
task.data['en']
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
describe '#depluralize_key' do
|
23
|
+
it 'depluralizes plural keys' do
|
24
|
+
expect(depluralize('plural_key.one')).to eq('plural_key')
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'ignores regular keys' do
|
28
|
+
expect(depluralize('regular_key')).to eq('regular_key')
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'ignores keys that look like plural but are not' do
|
32
|
+
expect(depluralize('not_really_plural.one')).to eq('not_really_plural.one')
|
33
|
+
end
|
34
|
+
|
35
|
+
def depluralize(key)
|
36
|
+
task.depluralize_key('en', key)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
after do
|
41
|
+
TestCodebase.teardown
|
42
|
+
end
|
43
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: i18n-tasks
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.
|
4
|
+
version: 0.3.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- glebm
|
@@ -180,13 +180,12 @@ dependencies:
|
|
180
180
|
version: '0'
|
181
181
|
description: |2
|
182
182
|
|
183
|
-
The basic approach to i18n key management in frameworks such as Rails
|
184
|
-
|
183
|
+
The basic approach to i18n key management in frameworks such as Rails is far from perfect.
|
185
184
|
If you use a key that does not exist, this will only blow up at runtime. Keys left over from removed code accumulate
|
186
|
-
in the resource files, introducing unnecessary overhead on the translators.
|
187
|
-
Translation files can quickly turn to disarray.
|
185
|
+
in the resource files, introducing unnecessary overhead on the translators. Translation files can quickly turn to disarray.
|
188
186
|
|
189
|
-
i18n-tasks
|
187
|
+
i18n-tasks improves this by using static analysis. It provides tasks to find and manage missing and unused translations.
|
188
|
+
This information is inferred based on the keys the gem detects used with calls such as `I18n.t` when scanning the code.
|
190
189
|
email:
|
191
190
|
- glex.spb@gmail.com
|
192
191
|
executables:
|
@@ -224,6 +223,7 @@ files:
|
|
224
223
|
- lib/i18n/tasks/key/usages.rb
|
225
224
|
- lib/i18n/tasks/key_group.rb
|
226
225
|
- lib/i18n/tasks/key_pattern_matching.rb
|
226
|
+
- lib/i18n/tasks/logging.rb
|
227
227
|
- lib/i18n/tasks/missing_keys.rb
|
228
228
|
- lib/i18n/tasks/plural_keys.rb
|
229
229
|
- lib/i18n/tasks/relative_keys.rb
|
@@ -249,6 +249,7 @@ files:
|
|
249
249
|
- spec/key_group_spec.rb
|
250
250
|
- spec/key_pattern_matching_spec.rb
|
251
251
|
- spec/pattern_scanner_spec.rb
|
252
|
+
- spec/plural_keys_spec.rb
|
252
253
|
- spec/readme_spec.rb
|
253
254
|
- spec/relative_keys_spec.rb
|
254
255
|
- spec/spec_helper.rb
|
@@ -297,6 +298,7 @@ test_files:
|
|
297
298
|
- spec/key_group_spec.rb
|
298
299
|
- spec/key_pattern_matching_spec.rb
|
299
300
|
- spec/pattern_scanner_spec.rb
|
301
|
+
- spec/plural_keys_spec.rb
|
300
302
|
- spec/readme_spec.rb
|
301
303
|
- spec/relative_keys_spec.rb
|
302
304
|
- spec/spec_helper.rb
|