i18n-tasks 0.7.13 → 0.8.0
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 +11 -0
- data/Gemfile +5 -3
- data/README.md +27 -126
- data/bin/i18n-tasks +2 -45
- data/config/locales/en.yml +11 -14
- data/config/locales/ru.yml +0 -3
- data/i18n-tasks.gemspec +0 -1
- data/lib/i18n/tasks.rb +14 -2
- data/lib/i18n/tasks/cli.rb +195 -0
- data/lib/i18n/tasks/command/collection.rb +2 -2
- data/lib/i18n/tasks/command/commander.rb +4 -24
- data/lib/i18n/tasks/command/commands/data.rb +17 -19
- data/lib/i18n/tasks/command/commands/eq_base.rb +2 -2
- data/lib/i18n/tasks/command/commands/health.rb +2 -2
- data/lib/i18n/tasks/command/commands/meta.rb +2 -2
- data/lib/i18n/tasks/command/commands/missing.rb +22 -15
- data/lib/i18n/tasks/command/commands/tree.rb +31 -35
- data/lib/i18n/tasks/command/commands/usages.rb +10 -11
- data/lib/i18n/tasks/command/commands/xlsx.rb +3 -3
- data/lib/i18n/tasks/command/dsl.rb +22 -7
- data/lib/i18n/tasks/command/option_parsers/enum.rb +53 -0
- data/lib/i18n/tasks/command/option_parsers/locale.rb +48 -0
- data/lib/i18n/tasks/command/options/common.rb +21 -31
- data/lib/i18n/tasks/command/options/data.rb +91 -0
- data/lib/i18n/tasks/command/options/locales.rb +22 -42
- data/lib/i18n/tasks/data/file_system_base.rb +2 -2
- data/lib/i18n/tasks/data/tree/node.rb +3 -3
- data/lib/i18n/tasks/data/tree/nodes.rb +3 -2
- data/lib/i18n/tasks/data/tree/siblings.rb +0 -1
- data/lib/i18n/tasks/logging.rb +9 -5
- data/lib/i18n/tasks/scanners/base_scanner.rb +6 -7
- data/lib/i18n/tasks/scanners/relative_keys.rb +1 -1
- data/lib/i18n/tasks/version.rb +1 -1
- data/spec/commands/data_commands_spec.rb +4 -4
- data/spec/commands/tree_commands_spec.rb +5 -5
- data/spec/google_translate_spec.rb +2 -3
- data/spec/i18n_spec.rb +0 -1
- data/spec/i18n_tasks_spec.rb +44 -23
- data/spec/readme_spec.rb +1 -1
- data/spec/support/test_codebase.rb +21 -10
- data/templates/config/i18n-tasks.yml +51 -39
- data/templates/rspec/i18n_spec.rb +0 -1
- metadata +6 -23
- data/lib/i18n/tasks/command/dsl/cmd.rb +0 -19
- data/lib/i18n/tasks/command/dsl/cmd_opt.rb +0 -19
- data/lib/i18n/tasks/command/dsl/enum_opt.rb +0 -45
- data/lib/i18n/tasks/command/options/enum_opt.rb +0 -50
- data/lib/i18n/tasks/command/options/list_opt.rb +0 -11
- data/lib/i18n/tasks/command/options/trees.rb +0 -81
- data/lib/i18n/tasks/slop_command.rb +0 -41
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4ffa593b45f4a5d40746da85f93879fffce47423
|
4
|
+
data.tar.gz: 689a92c8047df2b9b56638e2a9f3b9c46c43e115
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6d988d11c0b8690cb5596845a61b818eb9aa0702c6b84075c65b99a9fe0670c2435dfdc746d1cb5b92fb1f6929e9fc73b9bf7e8e8c76ab199a7c2517bfda782d
|
7
|
+
data.tar.gz: b071f96e5d5b912c95848ea6b363185b26a216fc968ae9657e1d28950b753f0933b9fc9c8f29e105a1ff2e8a4a324fc706ed33e53128c9074411980830628d2f
|
data/CHANGES.md
CHANGED
@@ -1,3 +1,14 @@
|
|
1
|
+
## 0.8.0
|
2
|
+
|
3
|
+
* Parse command line arguments with `optparse`. Remove dependency on Slop.
|
4
|
+
Simplified commands DSL: options are mostly passed directly to optparse.
|
5
|
+
* `search.relative_roots` default changed from from `%w(app/views)` to
|
6
|
+
`%w(app/views app/controllers app/helpers app/presenters)`.
|
7
|
+
* `add-missing` now adds keys detected in source to all locales (previously just base) [#134](https://github.com/glebm/i18n-tasks/issues/134).
|
8
|
+
* The default spec template no long requires `spec_helper` by default [Daniel Levenson](https://github.com/dleve123) [#135](https://github.com/glebm/i18n-tasks/pull/135).
|
9
|
+
* `search.exclude` now appends to and not overrides the default exclude list. More extensions excluded by default:
|
10
|
+
*.css, *.sass, *.scss, *.less, *.yml, and *.json. [#137](https://github.com/glebm/i18n-tasks/issues/137).
|
11
|
+
|
1
12
|
## 0.7.13
|
2
13
|
|
3
14
|
* Fix relative keys when controller name consists of more than one word by [Yuji Nakayama](https://github.com/yujinakayama) [#132](https://github.com/glebm/i18n-tasks/pull/132).
|
data/Gemfile
CHANGED
@@ -3,9 +3,11 @@ source 'https://rubygems.org'
|
|
3
3
|
# Specify your gem's dependencies in i18n-tasks.gemspec
|
4
4
|
gemspec
|
5
5
|
|
6
|
-
|
7
|
-
|
8
|
-
|
6
|
+
unless ENV['TRAVIS']
|
7
|
+
group :development do
|
8
|
+
gem 'byebug', platforms: [:mri_21, :mri_22], require: false
|
9
|
+
gem 'rubinius-debugger', platform: :rbx, require: false
|
10
|
+
end
|
9
11
|
end
|
10
12
|
|
11
13
|
gem 'codeclimate-test-reporter', group: :test, require: nil
|
data/README.md
CHANGED
@@ -22,7 +22,7 @@ i18n-tasks can be used with any project using the ruby [i18n gem][i18n-gem] (def
|
|
22
22
|
Add it to the Gemfile:
|
23
23
|
|
24
24
|
```ruby
|
25
|
-
gem 'i18n-tasks', '~> 0.
|
25
|
+
gem 'i18n-tasks', '~> 0.8.0'
|
26
26
|
```
|
27
27
|
|
28
28
|
Copy default [configuration file](#configuration) (optional):
|
@@ -177,7 +177,7 @@ For now, you can disable dynamic key inference by passing `-s` or `--strict` to
|
|
177
177
|
Configuration is read from `config/i18n-tasks.yml` or `config/i18n-tasks.yml.erb`.
|
178
178
|
Inspect configuration with `i18n-tasks config`.
|
179
179
|
|
180
|
-
Install the default config file with:
|
180
|
+
Install the [default config file][config] with:
|
181
181
|
|
182
182
|
```console
|
183
183
|
$ cp $(i18n-tasks gem-path)/templates/config/i18n-tasks.yml config/
|
@@ -188,60 +188,16 @@ Settings are compatible with Rails by default.
|
|
188
188
|
### Locales
|
189
189
|
|
190
190
|
By default, `base_locale` is set to `en` and `locales` are inferred from the paths to data files.
|
191
|
-
You can override these in the config
|
192
|
-
|
193
|
-
```yaml
|
194
|
-
# config/i18n-tasks.yml
|
195
|
-
base_locale: en
|
196
|
-
locales: [es, fr] # This includes base_locale by default
|
197
|
-
```
|
198
|
-
|
199
|
-
`internal_locale` controls the language i18n-tasks reports in. Locales available are `en` and `ru` (pull request to add more!).
|
200
|
-
|
201
|
-
```yaml
|
202
|
-
internal_locale: en
|
203
|
-
```
|
191
|
+
You can override these in the [config][config].
|
204
192
|
|
205
193
|
### Storage
|
206
194
|
|
207
195
|
The default data adapter supports YAML and JSON files.
|
208
196
|
|
209
|
-
```yaml
|
210
|
-
# config/i18n-tasks.yml
|
211
|
-
data:
|
212
|
-
# configure YAML / JSON serializer options
|
213
|
-
# passed directly to load / dump / parse / serialize.
|
214
|
-
yaml:
|
215
|
-
write:
|
216
|
-
# do not wrap lines at 80 characters (override default)
|
217
|
-
line_width: -1
|
218
|
-
```
|
219
|
-
|
220
197
|
#### Multiple locale files
|
221
198
|
|
222
|
-
|
223
|
-
|
224
|
-
`data.read` accepts a list of file globs to read from per-locale:
|
225
|
-
|
226
|
-
```
|
227
|
-
# config/i18n-tasks.yml
|
228
|
-
data:
|
229
|
-
read:
|
230
|
-
# read from namespaced files, e.g. simple_form.en.yml
|
231
|
-
- 'config/locales/*.%{locale}.yml'
|
232
|
-
# read from a gem (config is parsed with ERB first, then YAML)
|
233
|
-
- "<%= %x[bundle show vagrant].chomp %>/templates/locales/%{locale}.yml"
|
234
|
-
# default
|
235
|
-
- 'config/locales/%{locale}.yml'
|
236
|
-
```
|
237
|
-
|
238
|
-
#### Key pattern syntax
|
239
|
-
|
240
|
-
| syntax | description |
|
241
|
-
|:------------:|:----------------------------------------------------------|
|
242
|
-
| `*` | matches everything |
|
243
|
-
| `:` | matches a single key |
|
244
|
-
| `{a, b.c}` | match any in set, can use `:` and `*`, match is captured |
|
199
|
+
i18n-tasks can manage multiple translation files and read translations from other gems.
|
200
|
+
To find out more the `data` options in the [config][config].
|
245
201
|
|
246
202
|
For writing to locale files i18n-tasks provides 2 options.
|
247
203
|
|
@@ -266,7 +222,7 @@ data:
|
|
266
222
|
|
267
223
|
Conservative router keeps the keys where they are found, or infers the path from base locale.
|
268
224
|
If the key is completely new, conservative router will fall back to pattern router behaviour.
|
269
|
-
Conservative router is the default router.
|
225
|
+
Conservative router is the **default** router.
|
270
226
|
|
271
227
|
```
|
272
228
|
data:
|
@@ -276,55 +232,26 @@ data:
|
|
276
232
|
- 'config/locales/%{locale}.yml'
|
277
233
|
```
|
278
234
|
|
279
|
-
|
280
|
-
|
281
|
-
If you store data somewhere but in the filesystem, e.g. in the database or mongodb, you can implement a custom adapter.
|
282
|
-
Implement [a handful of methods][adapter-example], then set `data.adapter` to the class name; the rest of the `data` config is passed to the initializer.
|
235
|
+
##### Key pattern syntax
|
283
236
|
|
284
|
-
|
285
|
-
# config/i18n-tasks.yml
|
286
|
-
data:
|
287
|
-
# file_system is the default adapter, you can provide a custom class name here:
|
288
|
-
adapter: file_system
|
289
|
-
```
|
237
|
+
A special syntax similar to file glob patterns is used throughout i18n-tasks to match translation keys:
|
290
238
|
|
291
|
-
|
239
|
+
| syntax | description |
|
240
|
+
|:------------:|:----------------------------------------------------------|
|
241
|
+
| `*` | matches everything |
|
242
|
+
| `:` | matches a single key |
|
243
|
+
| `{a, b.c}` | match any in set, can use `:` and `*`, match is captured |
|
292
244
|
|
293
245
|
|
294
|
-
|
246
|
+
#### Custom adapters
|
295
247
|
|
296
|
-
|
297
|
-
|
298
|
-
# i18n usage search in source
|
299
|
-
search:
|
300
|
-
# search these directories (relative to your Rails.root directory, default: 'app/')
|
301
|
-
paths:
|
302
|
-
- 'app/'
|
303
|
-
- 'vendor/'
|
304
|
-
# paths for relative key resolution:
|
305
|
-
relative_roots:
|
306
|
-
# default:
|
307
|
-
- app/views
|
308
|
-
# add a custom one:
|
309
|
-
- app/views-mobile
|
310
|
-
# include only files matching this glob pattern (default: blank = include all files)
|
311
|
-
include:
|
312
|
-
- '*.rb'
|
313
|
-
- '*.html.*'
|
314
|
-
- '*.text.*'
|
315
|
-
# explicitly exclude files (default: exclude common binary files)
|
316
|
-
exclude:
|
317
|
-
- '*.js'
|
318
|
-
# you can override the default key regex pattern:
|
319
|
-
pattern: "\\bt[( ]\\s*(:?\".+?\"|:?'.+?'|:\\w+)"
|
320
|
-
# comments are ignored by default
|
321
|
-
ignore_lines:
|
322
|
-
- "^\\s*[#/](?!\\si18n-tasks-use)"
|
323
|
-
```
|
248
|
+
If you store data somewhere but in the filesystem, e.g. in the database or mongodb, you can implement a custom adapter.
|
249
|
+
If you have implemented a custom adapter please share it on [the wiki][wiki].
|
324
250
|
|
325
|
-
|
326
|
-
See this basic [pattern scanner](/lib/i18n/tasks/scanners/pattern_scanner.rb) for reference.
|
251
|
+
### Usage search
|
327
252
|
|
253
|
+
See the `search` section in the [config file][config] for all available configuration options.
|
254
|
+
An example of a custom scanner can be found here: https://github.com/glebm/i18n-tasks/issues/138#issuecomment-87255708.
|
328
255
|
|
329
256
|
### Fine-tuning
|
330
257
|
|
@@ -335,33 +262,8 @@ Add hints to static analysis with magic comment hints (lines starting with `(#|/
|
|
335
262
|
User.model_name.human
|
336
263
|
```
|
337
264
|
|
338
|
-
You can also explicitly ignore keys appearing in locale files
|
339
|
-
|
340
|
-
```yaml
|
341
|
-
# config/i18n-tasks.yml
|
342
|
-
# do not report these keys as unused
|
343
|
-
ignore_unused:
|
344
|
-
- category.*.db_name
|
345
|
-
|
346
|
-
# do not report these keys as missing (both on blank value and no key)
|
347
|
-
ignore_missing:
|
348
|
-
- devise.errors.unauthorized # ignore this key
|
349
|
-
- pagination.views.* # ignore the whole pattern
|
350
|
-
# E.g to ignore all Rails number / currency keys:
|
351
|
-
- 'number.{format, percentage.format, precision.format, human.format, currency.format}.{strip_insignificant_zeros,significant,delimiter}'
|
352
|
-
- 'time.{pm,am}'
|
353
|
-
|
354
|
-
# do not report these keys when they have the same value as the base locale version
|
355
|
-
ignore_eq_base:
|
356
|
-
all:
|
357
|
-
- common.ok
|
358
|
-
es,fr:
|
359
|
-
- common.brand
|
360
|
-
|
361
|
-
# do not report these keys ever
|
362
|
-
ignore:
|
363
|
-
- kaminari.*
|
364
|
-
```
|
265
|
+
You can also explicitly ignore keys appearing in locale files via `ignore*` settings.
|
266
|
+
See the [config file][config] to find out more.
|
365
267
|
|
366
268
|
<a name="translation-config"></a>
|
367
269
|
### Google Translate
|
@@ -383,7 +285,7 @@ translation:
|
|
383
285
|
api_key: <Google Translate API key>
|
384
286
|
```
|
385
287
|
|
386
|
-
## Interactive
|
288
|
+
## Interactive console
|
387
289
|
|
388
290
|
`i18n-tasks irb` starts an IRB session in i18n-tasks context. Type `guide` for more information.
|
389
291
|
|
@@ -395,12 +297,7 @@ Export missing and unused data to XLSX:
|
|
395
297
|
$ i18n-tasks xlsx-report
|
396
298
|
```
|
397
299
|
|
398
|
-
|
399
|
-
|
400
|
-
While i18n-tasks does not provide an HTML version of the report, you can add [one like this](https://gist.github.com/glebm/bdd3ab6d12d915f0c81b).
|
401
|
-
|
402
|
-
|
403
|
-
## Add New Tasks
|
300
|
+
## Add new tasks
|
404
301
|
|
405
302
|
Tasks that come with the gem are defined in [lib/i18n/tasks/command/commands](lib/i18n/tasks/command/commands).
|
406
303
|
|
@@ -430,6 +327,8 @@ Run with:
|
|
430
327
|
$ i18n-tasks my-task
|
431
328
|
```
|
432
329
|
|
330
|
+
See more examples of custom tasks [on the wiki](https://github.com/glebm/i18n-tasks/wiki#custom-tasks).
|
331
|
+
|
433
332
|
[MIT license]: /LICENSE.txt
|
434
333
|
[travis]: https://travis-ci.org/glebm/i18n-tasks
|
435
334
|
[badge-travis]: http://img.shields.io/travis/glebm/i18n-tasks.svg
|
@@ -439,6 +338,8 @@ $ i18n-tasks my-task
|
|
439
338
|
[badge-gemnasium]: https://gemnasium.com/glebm/i18n-tasks.svg
|
440
339
|
[code-climate]: https://codeclimate.com/github/glebm/i18n-tasks
|
441
340
|
[badge-code-climate]: http://img.shields.io/codeclimate/github/glebm/i18n-tasks.svg
|
341
|
+
[config]: https://github.com/glebm/i18n-tasks/blob/master/templates/config/i18n-tasks.yml
|
342
|
+
[wiki]: https://github.com/glebm/i18n-tasks/wiki "i18n-tasks wiki"
|
442
343
|
[i18n-gem]: https://github.com/svenfuchs/i18n "svenfuchs/i18n on Github"
|
443
344
|
[screenshot-find]: https://raw.github.com/glebm/i18n-tasks/master/doc/img/i18n-usages.png "i18n-tasks find output screenshot"
|
444
345
|
[adapter-example]: https://github.com/glebm/i18n-tasks/blob/master/lib/i18n/tasks/data/file_system_base.rb
|
data/bin/i18n-tasks
CHANGED
@@ -8,49 +8,6 @@ if i18n_gem_config.respond_to?(:enforce_available_locales=) && i18n_gem_config.e
|
|
8
8
|
i18n_gem_config.enforce_available_locales = true
|
9
9
|
end
|
10
10
|
|
11
|
-
require 'i18n/tasks'
|
12
|
-
require 'i18n/tasks/commands'
|
13
|
-
require 'slop'
|
11
|
+
require 'i18n/tasks/cli'
|
14
12
|
|
15
|
-
|
16
|
-
if $stderr.isatty
|
17
|
-
$stderr.puts Term::ANSIColor.yellow('i18n-tasks: ' + message)
|
18
|
-
else
|
19
|
-
$stderr.puts message
|
20
|
-
end
|
21
|
-
exit exit_code
|
22
|
-
}
|
23
|
-
|
24
|
-
begin
|
25
|
-
ran = false
|
26
|
-
commander = ::I18n::Tasks::Commands
|
27
|
-
instance = commander.new
|
28
|
-
instance.set_internal_locale!
|
29
|
-
slop_adapter = ::I18n::Tasks::SlopCommand
|
30
|
-
args = ARGV.dup
|
31
|
-
args = ['--help'] if args.empty?
|
32
|
-
Slop.parse(args, help: true) do
|
33
|
-
on('-v', '--version', 'Print the version') {
|
34
|
-
puts I18n::Tasks::VERSION
|
35
|
-
exit
|
36
|
-
}
|
37
|
-
commander.cmds.each do |name, attr|
|
38
|
-
slop_dsl = slop_adapter.slop_command(name, attr) { |_name, opts|
|
39
|
-
begin
|
40
|
-
ran = true
|
41
|
-
instance.safe_run name, opts
|
42
|
-
rescue Errno::EPIPE
|
43
|
-
# ignore Errno::EPIPE which is throw when pipe breaks, e.g.:
|
44
|
-
# i18n-tasks missing | head
|
45
|
-
exit 1
|
46
|
-
end
|
47
|
-
}
|
48
|
-
instance_exec(&slop_dsl)
|
49
|
-
end
|
50
|
-
end
|
51
|
-
rescue Slop::Error => e
|
52
|
-
err.call(e.message, 64)
|
53
|
-
end
|
54
|
-
|
55
|
-
|
56
|
-
err.call("Command unknown: #{args[0]}", 64) if !ran && args[0]
|
13
|
+
I18n::Tasks::CLI.start(ARGV)
|
data/config/locales/en.yml
CHANGED
@@ -7,20 +7,19 @@ en:
|
|
7
7
|
other: Added %{count} keys
|
8
8
|
cmd:
|
9
9
|
args:
|
10
|
-
default_all: 'Default: all'
|
11
10
|
default_text: 'Default: %{value}'
|
12
11
|
desc:
|
13
12
|
confirm: Confirm automatically
|
14
|
-
data_format: 'Data format: %{valid_text}.
|
13
|
+
data_format: 'Data format: %{valid_text}.'
|
15
14
|
key_pattern: Filter by key pattern (e.g. 'common.*')
|
16
15
|
key_pattern_to_rename: Full key (pattern) to rename. Required
|
17
|
-
locale:
|
18
|
-
locale_to_translate_from:
|
19
|
-
locales_filter:
|
20
|
-
missing_types: 'Filter by types: %{valid}
|
16
|
+
locale: Locale
|
17
|
+
locale_to_translate_from: Locale to translate from
|
18
|
+
locales_filter: "Locale(s) to process. Special: base"
|
19
|
+
missing_types: 'Filter by types: %{valid}'
|
21
20
|
new_key_name: New name, interpolates original name as %{key}. Required
|
22
21
|
nostdin: Do not read from stdin
|
23
|
-
out_format: 'Output format: %{valid_text}
|
22
|
+
out_format: 'Output format: %{valid_text}'
|
24
23
|
pattern_router: 'Use pattern router: keys moved per config data.write'
|
25
24
|
strict: Do not infer dynamic key usage such as `t("category.\#{category.name}")`
|
26
25
|
value: 'Value. Interpolates: %{value}, %{human_key}, %{value_or_human_key}'
|
@@ -54,18 +53,16 @@ en:
|
|
54
53
|
- Well done!
|
55
54
|
- Perfect!
|
56
55
|
enum_list_opt:
|
57
|
-
desc: 'Comma-separated list of: %{valid_text}. %{default_text}'
|
58
56
|
invalid: "%{invalid} is not in: %{valid}."
|
59
57
|
enum_opt:
|
60
|
-
desc: "%{valid_text}. %{default_text}"
|
61
58
|
invalid: "%{invalid} is not one of: %{valid}."
|
62
59
|
errors:
|
63
|
-
invalid_format: '
|
64
|
-
invalid_locale:
|
60
|
+
invalid_format: 'invalid format: %{invalid}. valid: %{valid}.'
|
61
|
+
invalid_locale: 'invalid locale: %{invalid}'
|
65
62
|
invalid_missing_type:
|
66
|
-
one: '
|
67
|
-
other: '
|
68
|
-
pass_forest:
|
63
|
+
one: 'invalid type: %{invalid}. valid: %{valid}.'
|
64
|
+
other: 'unknown types: %{invalid}. valid: %{valid}.'
|
65
|
+
pass_forest: pass locale forest
|
69
66
|
common:
|
70
67
|
base_value: Base Value
|
71
68
|
continue_q: Continue?
|
data/config/locales/ru.yml
CHANGED
@@ -5,7 +5,6 @@ ru:
|
|
5
5
|
added: "Добавлены ключи (%{count})"
|
6
6
|
cmd:
|
7
7
|
args:
|
8
|
-
default_all: "По умолчанию: все"
|
9
8
|
default_text: "По умолчанию: %{value}"
|
10
9
|
desc:
|
11
10
|
confirm: "Подтвердить автоматом"
|
@@ -53,10 +52,8 @@ ru:
|
|
53
52
|
- "Отлично!"
|
54
53
|
- "Прекрасно!"
|
55
54
|
enum_list_opt:
|
56
|
-
desc: "Разделенных запятыми список: %{valid_text}. %{default_text}"
|
57
55
|
invalid: "%{invalid} не в: %{valid}."
|
58
56
|
enum_opt:
|
59
|
-
desc: "%{valid_text}. %{default_text}"
|
60
57
|
invalid: "%{invalid} не является одним из: %{valid}."
|
61
58
|
errors:
|
62
59
|
invalid_format: "Неизвестный формат %{invalid}. Форматы: %{valid}."
|
data/i18n-tasks.gemspec
CHANGED
@@ -39,7 +39,6 @@ TEXT
|
|
39
39
|
s.add_dependency 'term-ansicolor'
|
40
40
|
s.add_dependency 'terminal-table'
|
41
41
|
s.add_dependency 'highline'
|
42
|
-
s.add_dependency 'slop', '~> 3.5'
|
43
42
|
s.add_dependency 'i18n'
|
44
43
|
s.add_development_dependency 'axlsx', '~> 2.0'
|
45
44
|
s.add_development_dependency 'bundler', '~> 1.3'
|
data/lib/i18n/tasks.rb
CHANGED
@@ -2,11 +2,22 @@
|
|
2
2
|
# define all the modules to be able to use ::
|
3
3
|
module I18n
|
4
4
|
module Tasks
|
5
|
+
class << self
|
6
|
+
def gem_path
|
7
|
+
File.expand_path(File.join(File.dirname(__FILE__), '..', '..'))
|
8
|
+
end
|
5
9
|
|
6
|
-
|
7
|
-
|
10
|
+
def verbose?
|
11
|
+
@verbose
|
12
|
+
end
|
13
|
+
|
14
|
+
def verbose=(value)
|
15
|
+
@verbose = value
|
16
|
+
end
|
8
17
|
end
|
9
18
|
|
19
|
+
@verbose = !!ENV['VERBOSE']
|
20
|
+
|
10
21
|
module Data
|
11
22
|
end
|
12
23
|
end
|
@@ -15,6 +26,7 @@ end
|
|
15
26
|
|
16
27
|
require 'active_support/core_ext/hash'
|
17
28
|
require 'active_support/core_ext/string'
|
29
|
+
require 'active_support/core_ext/array/access'
|
18
30
|
require 'active_support/core_ext/module/delegation'
|
19
31
|
require 'active_support/core_ext/object/try'
|
20
32
|
require 'active_support/core_ext/object/blank'
|
@@ -0,0 +1,195 @@
|
|
1
|
+
require 'i18n/tasks'
|
2
|
+
require 'i18n/tasks/commands'
|
3
|
+
require 'optparse'
|
4
|
+
|
5
|
+
class I18n::Tasks::CLI
|
6
|
+
include ::I18n::Tasks::Logging
|
7
|
+
|
8
|
+
def self.start(argv)
|
9
|
+
new.start(argv)
|
10
|
+
end
|
11
|
+
|
12
|
+
def initialize
|
13
|
+
end
|
14
|
+
|
15
|
+
def start(argv)
|
16
|
+
auto_output_coloring do
|
17
|
+
begin
|
18
|
+
run(argv)
|
19
|
+
rescue OptionParser::ParseError => e
|
20
|
+
error e.message, 64
|
21
|
+
rescue I18n::Tasks::CommandError => e
|
22
|
+
begin
|
23
|
+
error e.message, 78
|
24
|
+
ensure
|
25
|
+
log_verbose e.backtrace * "\n"
|
26
|
+
end
|
27
|
+
rescue Errno::EPIPE
|
28
|
+
# ignore Errno::EPIPE which is throw when pipe breaks, e.g.:
|
29
|
+
# i18n-tasks missing | head
|
30
|
+
exit 1
|
31
|
+
end
|
32
|
+
end
|
33
|
+
rescue ExecutionError => e
|
34
|
+
exit e.exit_code
|
35
|
+
end
|
36
|
+
|
37
|
+
def run(argv)
|
38
|
+
name, *options = parse!(argv.dup)
|
39
|
+
context.run(name, *options)
|
40
|
+
end
|
41
|
+
|
42
|
+
def context
|
43
|
+
@context ||= ::I18n::Tasks::Commands.new.tap(&:set_internal_locale!)
|
44
|
+
end
|
45
|
+
|
46
|
+
def commands
|
47
|
+
@commands ||= ::I18n::Tasks::Commands.cmds.transform_keys { |k| k.to_s.tr('_', '-') }
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
|
52
|
+
def parse!(argv)
|
53
|
+
command = parse_command! argv
|
54
|
+
options = optparse! command, argv
|
55
|
+
parse_options! options, command, argv
|
56
|
+
[command.tr('-', '_'), options.update(arguments: argv)]
|
57
|
+
end
|
58
|
+
|
59
|
+
def optparse!(command, argv)
|
60
|
+
if command
|
61
|
+
optparse_command!(command, argv)
|
62
|
+
else
|
63
|
+
optparse_no_command!(argv)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def optparse_command!(command, argv)
|
68
|
+
cmd_conf = commands[command]
|
69
|
+
flags = cmd_conf[:args].dup
|
70
|
+
options = {}
|
71
|
+
OptionParser.new("Usage: #{program_name} #{command} [options] #{cmd_conf[:pos]}".strip) do |op|
|
72
|
+
flags.each do |flag|
|
73
|
+
op.on(*optparse_args(flag)) { |v| options[option_name(flag)] = v }
|
74
|
+
end
|
75
|
+
verbose_option op
|
76
|
+
help_option op
|
77
|
+
end.parse!(argv)
|
78
|
+
options
|
79
|
+
end
|
80
|
+
|
81
|
+
def optparse_no_command!(argv)
|
82
|
+
argv << '--help' if argv.empty?
|
83
|
+
OptionParser.new("Usage: #{program_name} [command] [options]") do |op|
|
84
|
+
op.on('-v', '--version', 'Print the version') do
|
85
|
+
puts I18n::Tasks::VERSION
|
86
|
+
exit
|
87
|
+
end
|
88
|
+
help_option op
|
89
|
+
commands_summary op
|
90
|
+
end.parse!(argv)
|
91
|
+
end
|
92
|
+
|
93
|
+
def allow_help_arg_first!(argv)
|
94
|
+
# allow `i18n-tasks --help command` in addition to `i18n-tasks command --help`
|
95
|
+
argv[0], argv[1] = argv[1], argv[0] if %w(-h --help).include?(argv[0]) && argv[1] && !argv[1].start_with?('-')
|
96
|
+
end
|
97
|
+
|
98
|
+
def parse_command!(argv)
|
99
|
+
allow_help_arg_first! argv
|
100
|
+
if argv[0] && !argv[0].start_with?('-')
|
101
|
+
if commands.keys.include?(argv[0])
|
102
|
+
argv.shift
|
103
|
+
else
|
104
|
+
error "unknown command: #{argv[0]}", 64
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
def verbose_option(op)
|
110
|
+
op.on('--verbose', 'Verbose output') {
|
111
|
+
::I18n::Tasks.verbose = true
|
112
|
+
}
|
113
|
+
end
|
114
|
+
|
115
|
+
def help_option(op)
|
116
|
+
op.on('-h', '--help', 'Show this message') do
|
117
|
+
$stderr.puts op
|
118
|
+
exit
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
# @param [OptionParser] op
|
123
|
+
def commands_summary(op)
|
124
|
+
op.separator ''
|
125
|
+
op.separator 'Available commands:'
|
126
|
+
op.separator ''
|
127
|
+
commands.each do |cmd, cmd_conf|
|
128
|
+
op.separator " #{cmd.ljust(op.summary_width + 1, ' ')}#{try_call cmd_conf[:desc]}"
|
129
|
+
end
|
130
|
+
op.separator ''
|
131
|
+
op.separator 'See `i18n-tasks <command> --help` for more information on a specific command.'
|
132
|
+
end
|
133
|
+
|
134
|
+
def optparse_args(flag)
|
135
|
+
args = flag.dup
|
136
|
+
args.map! { |v| try_call v }
|
137
|
+
conf = args.extract_options!
|
138
|
+
if conf.key?(:default)
|
139
|
+
args[-1] = "#{args[-1]}. #{I18n.t('i18n_tasks.cmd.args.default_text', value: conf[:default])}"
|
140
|
+
end
|
141
|
+
args
|
142
|
+
end
|
143
|
+
|
144
|
+
def parse_options!(options, command, argv)
|
145
|
+
commands[command][:args].each do |flag|
|
146
|
+
name = option_name flag
|
147
|
+
options[name] = parse_option flag, options[name], argv, self.context
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
def parse_option(flag, val, argv, context)
|
152
|
+
conf = flag.last.is_a?(Hash) ? flag.last : {}
|
153
|
+
if conf[:consume_positional]
|
154
|
+
val = Array(val) + Array(flag.include?(Array) ? argv.flat_map { |x| x.split(',') } : argv)
|
155
|
+
end
|
156
|
+
val = conf[:default] if val.nil? && conf.key?(:default)
|
157
|
+
val = conf[:parser].call(val, context) if conf.key?(:parser)
|
158
|
+
val
|
159
|
+
end
|
160
|
+
|
161
|
+
def option_name(flag)
|
162
|
+
flag.detect { |f| f.start_with?('--') }.sub(/\A--/, '').sub(/[^\-\w].*\z/, '').to_sym
|
163
|
+
end
|
164
|
+
|
165
|
+
def try_call(v)
|
166
|
+
if v.respond_to? :call
|
167
|
+
v.call
|
168
|
+
else
|
169
|
+
v
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
def error(message, exit_code)
|
174
|
+
log_error message
|
175
|
+
fail ExecutionError.new(message, exit_code)
|
176
|
+
end
|
177
|
+
|
178
|
+
class ExecutionError < Exception
|
179
|
+
attr_reader :exit_code
|
180
|
+
|
181
|
+
def initialize(message, exit_code)
|
182
|
+
super(message)
|
183
|
+
@exit_code = exit_code
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
def auto_output_coloring(coloring = ENV['I18N_TASKS_COLOR'] || STDOUT.isatty)
|
188
|
+
coloring_was = Term::ANSIColor.coloring?
|
189
|
+
Term::ANSIColor.coloring = coloring
|
190
|
+
yield
|
191
|
+
ensure
|
192
|
+
Term::ANSIColor.coloring = coloring_was
|
193
|
+
end
|
194
|
+
|
195
|
+
end
|