i18n-tasks 1.0.15 → 1.1.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/README.md +85 -13
- data/Rakefile +4 -4
- data/bin/i18n-tasks +3 -3
- data/config/locales/en.yml +6 -0
- data/config/locales/ru.yml +7 -0
- data/i18n-tasks.gemspec +28 -41
- data/lib/i18n/tasks/base_task.rb +19 -19
- data/lib/i18n/tasks/cli.rb +37 -30
- data/lib/i18n/tasks/command/collection.rb +4 -4
- data/lib/i18n/tasks/command/commander.rb +5 -5
- data/lib/i18n/tasks/command/commands/check_prism.rb +126 -0
- data/lib/i18n/tasks/command/commands/data.rb +33 -33
- data/lib/i18n/tasks/command/commands/eq_base.rb +3 -3
- data/lib/i18n/tasks/command/commands/health.rb +6 -5
- data/lib/i18n/tasks/command/commands/interpolations.rb +14 -3
- data/lib/i18n/tasks/command/commands/meta.rb +6 -6
- data/lib/i18n/tasks/command/commands/missing.rb +25 -25
- data/lib/i18n/tasks/command/commands/tree.rb +33 -33
- data/lib/i18n/tasks/command/commands/usages.rb +24 -24
- data/lib/i18n/tasks/command/dsl.rb +1 -1
- data/lib/i18n/tasks/command/option_parsers/enum.rb +5 -5
- data/lib/i18n/tasks/command/option_parsers/locale.rb +4 -4
- data/lib/i18n/tasks/command/options/common.rb +16 -16
- data/lib/i18n/tasks/command/options/data.rb +18 -18
- data/lib/i18n/tasks/command/options/locales.rb +32 -32
- data/lib/i18n/tasks/commands.rb +14 -12
- data/lib/i18n/tasks/concurrent/cache.rb +1 -1
- data/lib/i18n/tasks/concurrent/cached_value.rb +1 -1
- data/lib/i18n/tasks/configuration.rb +22 -21
- data/lib/i18n/tasks/console_context.rb +11 -11
- data/lib/i18n/tasks/data/adapter/json_adapter.rb +1 -1
- data/lib/i18n/tasks/data/adapter/yaml_adapter.rb +5 -5
- data/lib/i18n/tasks/data/file_formats.rb +3 -3
- data/lib/i18n/tasks/data/file_system.rb +5 -5
- data/lib/i18n/tasks/data/file_system_base.rb +26 -26
- data/lib/i18n/tasks/data/language_names.rb +202 -0
- data/lib/i18n/tasks/data/router/conservative_router.rb +3 -3
- data/lib/i18n/tasks/data/router/isolating_router.rb +19 -19
- data/lib/i18n/tasks/data/router/pattern_router.rb +5 -5
- data/lib/i18n/tasks/data/tree/node.rb +27 -27
- data/lib/i18n/tasks/data/tree/nodes.rb +10 -10
- data/lib/i18n/tasks/data/tree/siblings.rb +20 -20
- data/lib/i18n/tasks/data/tree/traversal.rb +5 -5
- data/lib/i18n/tasks/data.rb +4 -4
- data/lib/i18n/tasks/html_keys.rb +2 -2
- data/lib/i18n/tasks/ignore_keys.rb +9 -9
- data/lib/i18n/tasks/interpolations.rb +21 -1
- data/lib/i18n/tasks/key_pattern_matching.rb +8 -8
- data/lib/i18n/tasks/logging.rb +2 -1
- data/lib/i18n/tasks/missing_keys.rb +24 -8
- data/lib/i18n/tasks/plural_keys.rb +6 -4
- data/lib/i18n/tasks/references.rb +4 -4
- data/lib/i18n/tasks/reports/base.rb +18 -14
- data/lib/i18n/tasks/reports/terminal.rb +64 -47
- data/lib/i18n/tasks/scanners/ast_matchers/base_matcher.rb +3 -3
- data/lib/i18n/tasks/scanners/ast_matchers/default_i18n_subject_matcher.rb +3 -3
- data/lib/i18n/tasks/scanners/ast_matchers/message_receivers_matcher.rb +10 -10
- data/lib/i18n/tasks/scanners/ast_matchers/rails_model_matcher.rb +1 -1
- data/lib/i18n/tasks/scanners/erb_ast_scanner.rb +69 -10
- data/lib/i18n/tasks/scanners/file_scanner.rb +5 -5
- data/lib/i18n/tasks/scanners/files/caching_file_finder.rb +3 -3
- data/lib/i18n/tasks/scanners/files/caching_file_finder_provider.rb +3 -3
- data/lib/i18n/tasks/scanners/files/caching_file_reader.rb +2 -2
- data/lib/i18n/tasks/scanners/files/file_finder.rb +8 -8
- data/lib/i18n/tasks/scanners/files/file_reader.rb +1 -1
- data/lib/i18n/tasks/scanners/local_ruby_parser.rb +8 -8
- data/lib/i18n/tasks/scanners/occurrence_from_position.rb +1 -1
- data/lib/i18n/tasks/scanners/pattern_mapper.rb +7 -7
- data/lib/i18n/tasks/scanners/pattern_scanner.rb +20 -20
- data/lib/i18n/tasks/scanners/pattern_with_scope_scanner.rb +8 -8
- data/lib/i18n/tasks/scanners/prism_scanners/arguments_visitor.rb +8 -1
- data/lib/i18n/tasks/scanners/prism_scanners/nodes.rb +101 -61
- data/lib/i18n/tasks/scanners/prism_scanners/visitor.rb +169 -105
- data/lib/i18n/tasks/scanners/relative_keys.rb +8 -8
- data/lib/i18n/tasks/scanners/results/key_occurrences.rb +3 -3
- data/lib/i18n/tasks/scanners/results/occurrence.rb +14 -10
- data/lib/i18n/tasks/scanners/ruby_ast_call_finder.rb +1 -1
- data/lib/i18n/tasks/scanners/ruby_key_literals.rb +6 -6
- data/lib/i18n/tasks/scanners/ruby_parser_factory.rb +1 -1
- data/lib/i18n/tasks/scanners/ruby_scanner.rb +225 -0
- data/lib/i18n/tasks/scanners/scanner.rb +2 -2
- data/lib/i18n/tasks/scanners/scanner_multiplexer.rb +1 -1
- data/lib/i18n/tasks/split_key.rb +4 -4
- data/lib/i18n/tasks/stats.rb +3 -3
- data/lib/i18n/tasks/translation.rb +5 -5
- data/lib/i18n/tasks/translators/base_translator.rb +40 -14
- data/lib/i18n/tasks/translators/deepl_translator.rb +17 -14
- data/lib/i18n/tasks/translators/google_translator.rb +169 -25
- data/lib/i18n/tasks/translators/openai_translator.rb +34 -23
- data/lib/i18n/tasks/translators/watsonx_translator.rb +16 -16
- data/lib/i18n/tasks/translators/yandex_translator.rb +8 -8
- data/lib/i18n/tasks/unused_keys.rb +1 -1
- data/lib/i18n/tasks/used_keys.rb +32 -33
- data/lib/i18n/tasks/version.rb +1 -1
- data/lib/i18n/tasks.rb +17 -17
- data/templates/config/i18n-tasks.yml +12 -0
- data/templates/minitest/i18n_test.rb +3 -3
- data/templates/rspec/i18n_spec.rb +7 -7
- metadata +25 -185
- data/lib/i18n/tasks/scanners/prism_scanner.rb +0 -83
- data/lib/i18n/tasks/scanners/ruby_ast_scanner.rb +0 -145
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 3231dd8c4f3772a49ed9db6862f6d34c9fabed656a1ba3588f2a0d24be158d50
|
|
4
|
+
data.tar.gz: b5db9e81af6eff9256acf3b84bbbcea4a738c987f0485e04e127eba0236f01fd
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 601af6d9cf98382b36cb7eebec4672c8918440f63899ef8e91cda798de0685971e331e352420c0f7d3c2f4a5dc056d80f7b0feb1b04e7aa847c69ebd273ff214
|
|
7
|
+
data.tar.gz: d8e0c5b7bb14a6ab061f60360e869f293b2c608fde5a02f7ebb90495f8c0d0adec69d4665818bd96b2fe6f3c590434aa94ad35462e2777bd9925ac3150aa4273
|
data/README.md
CHANGED
|
@@ -24,7 +24,7 @@ i18n-tasks can be used with any project using the ruby [i18n gem][i18n-gem] (def
|
|
|
24
24
|
Add i18n-tasks to the Gemfile:
|
|
25
25
|
|
|
26
26
|
```ruby
|
|
27
|
-
gem 'i18n-tasks', '~> 1.0
|
|
27
|
+
gem 'i18n-tasks', '~> 1.1.0', group: :development
|
|
28
28
|
```
|
|
29
29
|
|
|
30
30
|
Copy the default [configuration file](#configuration):
|
|
@@ -227,6 +227,27 @@ See the full list of tasks with `i18n-tasks --help`.
|
|
|
227
227
|
✔ Reference keys (keys with `:symbol` values) are fully supported. These keys are copied as-is in
|
|
228
228
|
`add/translate-missing`, and can be looked up by reference or value in `find`.
|
|
229
229
|
|
|
230
|
+
#### Unexpected normalization
|
|
231
|
+
`i18n-tasks` uses a yaml parser and emitter called `Psych` under the hood. `Psych` has it's own heuristic on when
|
|
232
|
+
to use `|`, `>`, or `""` for multi-line strings. This can have some unexpected consequences, eg when normalizing:
|
|
233
|
+
```yaml
|
|
234
|
+
a: |
|
|
235
|
+
Lorem ipsum dolor sit amet, consectetur
|
|
236
|
+
Lorem ipsum dolor sit amet, consectetur
|
|
237
|
+
b: |
|
|
238
|
+
Lorem ipsum dolor sit amet, consectetur
|
|
239
|
+
Lorem ipsum dolor sit amet, consectetur
|
|
240
|
+
```
|
|
241
|
+
we get the result
|
|
242
|
+
```yaml
|
|
243
|
+
a: |
|
|
244
|
+
Lorem ipsum dolor sit amet, consectetur
|
|
245
|
+
Lorem ipsum dolor sit amet, consectetur
|
|
246
|
+
b: "Lorem ipsum dolor sit amet, consectetur \nLorem ipsum dolor sit amet, consectetur\n"
|
|
247
|
+
```
|
|
248
|
+
The only difference between `a` and `b` is that `b` has an extra trailing space in each line.
|
|
249
|
+
This is an unfortunate side effect of `i18n-tasks` using `Psych`.
|
|
250
|
+
|
|
230
251
|
#### `t()` keyword arguments
|
|
231
252
|
|
|
232
253
|
✔ `scope` keyword argument is fully supported by the AST scanner, and also by the Regexp scanner but only when it is the first argument.
|
|
@@ -366,6 +387,22 @@ truck.contents.description_body ⮕ truck.attributes.description.body
|
|
|
366
387
|
If you store data somewhere but in the filesystem, e.g. in the database or mongodb, you can implement a custom adapter.
|
|
367
388
|
If you have implemented a custom adapter please share it on [the wiki][wiki].
|
|
368
389
|
|
|
390
|
+
#### Rails credentials
|
|
391
|
+
|
|
392
|
+
If you use Rails credentials and want to load e.g. credentials for translation backends, convert your `i18n-tasks.yml`to `i18n-tasks.yml.erb` and add
|
|
393
|
+
a `require "./config/application"` line to load Rails.
|
|
394
|
+
|
|
395
|
+
```yaml
|
|
396
|
+
# config/i18n-tasks.yml.erb
|
|
397
|
+
<% require "./config/application" %>
|
|
398
|
+
|
|
399
|
+
# ...
|
|
400
|
+
|
|
401
|
+
translation:
|
|
402
|
+
backend: google
|
|
403
|
+
google_translate_api_key: <%= Rails.application.credentials.google_translate_api_key %>
|
|
404
|
+
```
|
|
405
|
+
|
|
369
406
|
### Usage search
|
|
370
407
|
|
|
371
408
|
i18n-tasks uses an AST scanner for `.rb` and `.html.erb` files, and a regexp scanner for all other files.
|
|
@@ -392,6 +429,24 @@ For more complex cases, you can implement a [custom scanner][custom-scanner-docs
|
|
|
392
429
|
|
|
393
430
|
See the [config file][config] to find out more.
|
|
394
431
|
|
|
432
|
+
### Environment Variables and Dotenv
|
|
433
|
+
|
|
434
|
+
i18n-tasks supports loading environment variables from `.env` files using the [dotenv](https://github.com/bkeepers/dotenv) gem.
|
|
435
|
+
This is particularly useful for storing translation API keys and other sensitive configuration.
|
|
436
|
+
|
|
437
|
+
If you have `dotenv` in your Gemfile, i18n-tasks will automatically load environment variables from `.env` files
|
|
438
|
+
before executing commands. This means you can store your API keys in a `.env` file:
|
|
439
|
+
|
|
440
|
+
```bash
|
|
441
|
+
# .env
|
|
442
|
+
GOOGLE_TRANSLATE_API_KEY=your_google_api_key
|
|
443
|
+
DEEPL_AUTH_KEY=your_deepl_api_key
|
|
444
|
+
OPENAI_API_KEY=your_openai_api_key
|
|
445
|
+
```
|
|
446
|
+
|
|
447
|
+
The dotenv integration works seamlessly - no additional configuration is required. If `dotenv` is not available,
|
|
448
|
+
i18n-tasks will continue to work normally using system environment variables.
|
|
449
|
+
|
|
395
450
|
<a name="google-translation-config"></a>
|
|
396
451
|
### Google Translate
|
|
397
452
|
|
|
@@ -444,7 +499,7 @@ translation:
|
|
|
444
499
|
or via environment variables:
|
|
445
500
|
|
|
446
501
|
```bash
|
|
447
|
-
|
|
502
|
+
DEEPL_AUTH_KEY=<DeepL Pro API key>
|
|
448
503
|
DEEPL_HOST=<optional>
|
|
449
504
|
DEEPL_VERSION=<optional>
|
|
450
505
|
```
|
|
@@ -509,30 +564,47 @@ WATSONX_PROJECT_ID=<watsonx project id>
|
|
|
509
564
|
WATSONX_MODEL=<optional>
|
|
510
565
|
```
|
|
511
566
|
|
|
512
|
-
###
|
|
567
|
+
### Prism-based scanner for Ruby and ERB files
|
|
568
|
+
|
|
569
|
+
There is a scanner based on [Prism](https://github.com/ruby/prism) usable in two different modes.
|
|
513
570
|
|
|
514
|
-
|
|
571
|
+
- `rails` mode parses Rails code and handles context such as controllers, before_actions, model translations and more.
|
|
572
|
+
- `ruby` mode parses Ruby code only, and works similar to the existing whitequark/parser-implementation.
|
|
573
|
+
- The parser is used for both ruby and ERB files.
|
|
574
|
+
|
|
575
|
+
#### `rails` mode
|
|
576
|
+
|
|
577
|
+
It handles the following cases:
|
|
515
578
|
- Translations called in `before_actions`
|
|
516
579
|
- Translations called in nested methods
|
|
517
580
|
- `Model.human_attribute_name` calls
|
|
518
581
|
- `Model.model_name.human` calls
|
|
519
582
|
|
|
520
|
-
Enabled it by adding
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
'I18n::Tasks::Scanners::PrismScanner',
|
|
525
|
-
only: %w(*.rb)
|
|
526
|
-
) %>
|
|
583
|
+
Enabled it by adding:
|
|
584
|
+
```yaml
|
|
585
|
+
search:
|
|
586
|
+
prism: "rails"
|
|
527
587
|
```
|
|
528
588
|
|
|
529
|
-
|
|
589
|
+
to your `config/i18n-tasks.yml` file.
|
|
590
|
+
|
|
591
|
+
#### `ruby` mode
|
|
592
|
+
|
|
593
|
+
It finds all `I18n.t`, `I18n.translate`, `t` and `translate` calls in Ruby code. Enabled it by adding:
|
|
530
594
|
|
|
531
595
|
```yaml
|
|
532
596
|
search:
|
|
533
|
-
|
|
597
|
+
prism: "ruby"
|
|
534
598
|
```
|
|
535
599
|
|
|
600
|
+
The goal is to replace the whitequark/parser-based scanner with this one in the future.
|
|
601
|
+
|
|
602
|
+
#### Help us out with testing
|
|
603
|
+
|
|
604
|
+
Please install the latest version of the gem and run `i18n-tasks check-prism` which will parse everything with the whitequark/parser-based scanner and then everything with the Prism-scanner and try to compare the results.
|
|
605
|
+
|
|
606
|
+
Open up issues with any parser crashes, missed translations or false positives.
|
|
607
|
+
|
|
536
608
|
## Interactive console
|
|
537
609
|
|
|
538
610
|
`i18n-tasks irb` starts an IRB session in i18n-tasks context. Type `guide` for more information.
|
data/Rakefile
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require
|
|
4
|
-
require
|
|
3
|
+
require "bundler/gem_tasks"
|
|
4
|
+
require "rspec/core/rake_task"
|
|
5
5
|
RSpec::Core::RakeTask.new(:rspec)
|
|
6
6
|
task default: :rspec
|
|
7
7
|
|
|
8
8
|
task :irb do
|
|
9
9
|
# $: << File.expand_path('lib', __FILE__)
|
|
10
|
-
require
|
|
11
|
-
require
|
|
10
|
+
require "i18n/tasks"
|
|
11
|
+
require "i18n/tasks/commands"
|
|
12
12
|
I18n::Tasks::Commands.new(I18n::Tasks::BaseTask.new).irb
|
|
13
13
|
end
|
data/bin/i18n-tasks
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
#!/usr/bin/env ruby
|
|
2
2
|
# frozen_string_literal: true
|
|
3
3
|
|
|
4
|
-
require_relative
|
|
4
|
+
require_relative "../spec/bin_simplecov_helper" if ENV["I18N_TASKS_BIN_SIMPLECOV_COVERAGE"]
|
|
5
5
|
|
|
6
6
|
# prevent i18n gem warning
|
|
7
|
-
require
|
|
7
|
+
require "i18n"
|
|
8
8
|
i18n_gem_config = I18n.config
|
|
9
9
|
if i18n_gem_config.respond_to?(:enforce_available_locales=) && i18n_gem_config.enforce_available_locales.nil?
|
|
10
10
|
i18n_gem_config.enforce_available_locales = true
|
|
11
11
|
end
|
|
12
12
|
|
|
13
|
-
require
|
|
13
|
+
require "i18n/tasks/cli"
|
|
14
14
|
|
|
15
15
|
I18n::Tasks::CLI.start(ARGV)
|
data/config/locales/en.yml
CHANGED
|
@@ -34,6 +34,9 @@ en:
|
|
|
34
34
|
add_missing: add missing keys to locale data, optionally match a pattern
|
|
35
35
|
check_consistent_interpolations: verify that all translations use correct interpolation variables
|
|
36
36
|
check_normalized: verify that all translation data is normalized
|
|
37
|
+
check_prism: verify that Prism-scanner produces the same (or better) results as the default
|
|
38
|
+
parser
|
|
39
|
+
check_reserved_interpolations: verify that all translations avoid reserved interpolation variables
|
|
37
40
|
config: display i18n-tasks configuration
|
|
38
41
|
cp: copy the keys in locale data that match the given pattern
|
|
39
42
|
data: show locale data
|
|
@@ -124,6 +127,9 @@ en:
|
|
|
124
127
|
other: "%{count} translation will be removed from %{locales}."
|
|
125
128
|
noop: No unused keys to remove
|
|
126
129
|
removed: Removed %{count} keys
|
|
130
|
+
reserved_interpolations:
|
|
131
|
+
details_title: Reserved interpolation keys
|
|
132
|
+
none: No reserved interpolations found.
|
|
127
133
|
translate_missing:
|
|
128
134
|
translated: Translated %{count} keys
|
|
129
135
|
unused:
|
data/config/locales/ru.yml
CHANGED
|
@@ -32,6 +32,10 @@ ru:
|
|
|
32
32
|
check_consistent_interpolations: убедитесь, что во всех переводах используются правильные
|
|
33
33
|
интерполяционные переменные
|
|
34
34
|
check_normalized: проверить, что все файлы переводов нормализованы
|
|
35
|
+
check_prism: убедитесь, что Prism-scanner выдает те же (или лучшие) результаты, что и анализатор
|
|
36
|
+
по умолчанию
|
|
37
|
+
check_reserved_interpolations: проверьте, что все переводы обходятся без зарезервированных
|
|
38
|
+
интерполяционных переменных
|
|
35
39
|
config: показать конфигурацию
|
|
36
40
|
cp: скопируйте ключи в данных локали, соответствующие заданному шаблону
|
|
37
41
|
data: показать данные переводов
|
|
@@ -125,6 +129,9 @@ ru:
|
|
|
125
129
|
other: Переводы (%{count}) будут удалены из %{locales}.
|
|
126
130
|
noop: Нет неиспользуемых ключей
|
|
127
131
|
removed: Удалены ключи (%{count})
|
|
132
|
+
reserved_interpolations:
|
|
133
|
+
details_title: Зарезервированные ключи интерполяции
|
|
134
|
+
none: NЗарезервированных интерполяций не обнаружено.
|
|
128
135
|
translate_missing:
|
|
129
136
|
translated: Переведены ключи (%{count})
|
|
130
137
|
unused:
|
data/i18n-tasks.gemspec
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
lib = File.expand_path(
|
|
3
|
+
lib = File.expand_path("lib", __dir__)
|
|
4
4
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
5
|
-
require
|
|
5
|
+
require "i18n/tasks/version"
|
|
6
6
|
|
|
7
7
|
Gem::Specification.new do |s|
|
|
8
|
-
s.name
|
|
9
|
-
s.version
|
|
10
|
-
s.authors
|
|
11
|
-
s.email
|
|
12
|
-
s.license
|
|
13
|
-
s.summary
|
|
14
|
-
s.description
|
|
8
|
+
s.name = "i18n-tasks"
|
|
9
|
+
s.version = I18n::Tasks::VERSION
|
|
10
|
+
s.authors = ["glebm"]
|
|
11
|
+
s.email = ["glex.spb@gmail.com"]
|
|
12
|
+
s.license = "MIT"
|
|
13
|
+
s.summary = "Manage localization and translation with the awesome power of static analysis"
|
|
14
|
+
s.description = <<~TEXT
|
|
15
15
|
i18n-tasks helps you find and manage missing and unused translations.
|
|
16
16
|
|
|
17
17
|
It analyses code statically for key usages, such as `I18n.t('some.key')`, in order to report keys that are missing or unused,
|
|
@@ -25,42 +25,29 @@ Gem::Specification.new do |s|
|
|
|
25
25
|
# Or for minitest:
|
|
26
26
|
cp $(bundle exec i18n-tasks gem-path)/templates/minitest/i18n_test.rb test/
|
|
27
27
|
TEXT
|
|
28
|
-
s.homepage =
|
|
28
|
+
s.homepage = "https://github.com/glebm/i18n-tasks"
|
|
29
29
|
s.metadata = {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
30
|
+
"changelog_uri" => "https://github.com/glebm/i18n-tasks/blob/main/CHANGES.md",
|
|
31
|
+
"issue_tracker" => "https://github.com/glebm/i18n-tasks",
|
|
32
|
+
"rubygems_mfa_required" => "true",
|
|
33
|
+
"source_code_uri" => "https://github.com/glebm/i18n-tasks"
|
|
34
34
|
}
|
|
35
|
-
s.required_ruby_version =
|
|
35
|
+
s.required_ruby_version = ">= 3.1"
|
|
36
36
|
|
|
37
37
|
s.files = `git ls-files`.split($/)
|
|
38
38
|
s.files -= s.files.grep(%r{^(doc/|\.|spec/)}) + %w[CHANGES.md config/i18n-tasks.yml Gemfile]
|
|
39
|
-
s.executables
|
|
40
|
-
s.require_paths = [
|
|
39
|
+
s.executables = s.files.grep(%r{^bin/}) { |f| File.basename(f) } - %w[i18n-tasks.cmd]
|
|
40
|
+
s.require_paths = ["lib"]
|
|
41
41
|
|
|
42
|
-
s.add_dependency
|
|
43
|
-
s.add_dependency
|
|
44
|
-
s.add_dependency
|
|
45
|
-
s.add_dependency
|
|
46
|
-
s.add_dependency
|
|
47
|
-
s.add_dependency
|
|
48
|
-
s.add_dependency
|
|
49
|
-
s.add_dependency
|
|
50
|
-
s.add_dependency
|
|
51
|
-
s.add_dependency
|
|
52
|
-
s.
|
|
53
|
-
s.add_development_dependency 'overcommit', '~> 0.58.0'
|
|
54
|
-
s.add_development_dependency 'rake'
|
|
55
|
-
s.add_development_dependency 'rspec', '~> 3.3'
|
|
56
|
-
s.add_development_dependency 'rubocop', '~> 1.50.1'
|
|
57
|
-
s.add_development_dependency 'rubocop-rake', '~> 0.6.0'
|
|
58
|
-
s.add_development_dependency 'rubocop-rspec', '~> 2.19.0'
|
|
59
|
-
s.add_development_dependency 'simplecov'
|
|
60
|
-
s.add_development_dependency 'yard'
|
|
61
|
-
|
|
62
|
-
# Translation backends
|
|
63
|
-
s.add_development_dependency 'deepl-rb', '>= 2.1.0'
|
|
64
|
-
s.add_development_dependency 'easy_translate', '>= 0.5.1' # Google Translate
|
|
65
|
-
s.add_development_dependency 'yandex-translator', '>= 0.3.3'
|
|
42
|
+
s.add_dependency "activesupport", ">= 4.0.2"
|
|
43
|
+
s.add_dependency "ast", ">= 2.1.0"
|
|
44
|
+
s.add_dependency "erubi"
|
|
45
|
+
s.add_dependency "highline", ">= 3.0.0"
|
|
46
|
+
s.add_dependency "i18n"
|
|
47
|
+
s.add_dependency "parser", ">= 3.2.2.1"
|
|
48
|
+
s.add_dependency "prism"
|
|
49
|
+
s.add_dependency "rails-i18n"
|
|
50
|
+
s.add_dependency "rainbow", ">= 2.2.2", "< 4.0"
|
|
51
|
+
s.add_dependency "ruby-progressbar", "~> 1.8", ">= 1.8.1"
|
|
52
|
+
s.add_dependency "terminal-table", ">= 1.5.1"
|
|
66
53
|
end
|
data/lib/i18n/tasks/base_task.rb
CHANGED
|
@@ -1,24 +1,24 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require
|
|
4
|
-
require
|
|
5
|
-
require
|
|
6
|
-
require
|
|
7
|
-
require
|
|
8
|
-
require
|
|
9
|
-
require
|
|
10
|
-
require
|
|
11
|
-
require
|
|
12
|
-
require
|
|
13
|
-
require
|
|
14
|
-
require
|
|
15
|
-
require
|
|
16
|
-
require
|
|
17
|
-
require
|
|
18
|
-
require
|
|
19
|
-
require
|
|
20
|
-
require
|
|
21
|
-
require
|
|
3
|
+
require "i18n/tasks/command_error"
|
|
4
|
+
require "i18n/tasks/split_key"
|
|
5
|
+
require "i18n/tasks/key_pattern_matching"
|
|
6
|
+
require "i18n/tasks/logging"
|
|
7
|
+
require "i18n/tasks/plural_keys"
|
|
8
|
+
require "i18n/tasks/references"
|
|
9
|
+
require "i18n/tasks/html_keys"
|
|
10
|
+
require "i18n/tasks/used_keys"
|
|
11
|
+
require "i18n/tasks/ignore_keys"
|
|
12
|
+
require "i18n/tasks/missing_keys"
|
|
13
|
+
require "i18n/tasks/interpolations"
|
|
14
|
+
require "i18n/tasks/unused_keys"
|
|
15
|
+
require "i18n/tasks/translation"
|
|
16
|
+
require "i18n/tasks/locale_pathname"
|
|
17
|
+
require "i18n/tasks/locale_list"
|
|
18
|
+
require "i18n/tasks/string_interpolation"
|
|
19
|
+
require "i18n/tasks/data"
|
|
20
|
+
require "i18n/tasks/configuration"
|
|
21
|
+
require "i18n/tasks/stats"
|
|
22
22
|
|
|
23
23
|
module I18n
|
|
24
24
|
module Tasks
|
data/lib/i18n/tasks/cli.rb
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require
|
|
4
|
-
require
|
|
5
|
-
require
|
|
3
|
+
require "i18n/tasks"
|
|
4
|
+
require "i18n/tasks/commands"
|
|
5
|
+
require "optparse"
|
|
6
6
|
|
|
7
7
|
class I18n::Tasks::CLI
|
|
8
8
|
include ::I18n::Tasks::Logging
|
|
@@ -11,9 +11,9 @@ class I18n::Tasks::CLI
|
|
|
11
11
|
new.start(argv)
|
|
12
12
|
end
|
|
13
13
|
|
|
14
|
-
def initialize; end
|
|
15
|
-
|
|
16
14
|
def start(argv)
|
|
15
|
+
load_dotenv
|
|
16
|
+
|
|
17
17
|
auto_output_coloring do
|
|
18
18
|
exit 1 if run(argv) == :exit1
|
|
19
19
|
rescue OptionParser::ParseError => e
|
|
@@ -35,7 +35,7 @@ class I18n::Tasks::CLI
|
|
|
35
35
|
|
|
36
36
|
def run(argv)
|
|
37
37
|
argv.each_with_index do |arg, i|
|
|
38
|
-
next unless [
|
|
38
|
+
next unless ["--config", "-c"].include?(arg)
|
|
39
39
|
|
|
40
40
|
_, config_file = argv.slice!(i, 2)
|
|
41
41
|
if File.exist?(config_file)
|
|
@@ -59,7 +59,7 @@ class I18n::Tasks::CLI
|
|
|
59
59
|
def commands
|
|
60
60
|
# load base task to initialize plugins
|
|
61
61
|
base_task
|
|
62
|
-
@commands ||= ::I18n::Tasks::Commands.cmds.transform_keys { |k| k.to_s.tr(
|
|
62
|
+
@commands ||= ::I18n::Tasks::Commands.cmds.transform_keys { |k| k.to_s.tr("_", "-") }
|
|
63
63
|
end
|
|
64
64
|
|
|
65
65
|
private
|
|
@@ -72,7 +72,7 @@ class I18n::Tasks::CLI
|
|
|
72
72
|
command = parse_command! argv
|
|
73
73
|
options = optparse! command, argv
|
|
74
74
|
parse_options! options, command, argv
|
|
75
|
-
[command.tr(
|
|
75
|
+
[command.tr("-", "_"), options.update(arguments: argv)]
|
|
76
76
|
end
|
|
77
77
|
|
|
78
78
|
def optparse!(command, argv)
|
|
@@ -85,8 +85,8 @@ class I18n::Tasks::CLI
|
|
|
85
85
|
|
|
86
86
|
def optparse_command!(command, argv)
|
|
87
87
|
cmd_conf = commands[command]
|
|
88
|
-
flags
|
|
89
|
-
options
|
|
88
|
+
flags = cmd_conf[:args].dup
|
|
89
|
+
options = {}
|
|
90
90
|
OptionParser.new("Usage: #{program_name} #{command} [options] #{cmd_conf[:pos]}".strip) do |op|
|
|
91
91
|
flags.each do |flag|
|
|
92
92
|
op.on(*optparse_args(flag)) { |v| options[option_name(flag)] = v }
|
|
@@ -98,9 +98,9 @@ class I18n::Tasks::CLI
|
|
|
98
98
|
end
|
|
99
99
|
|
|
100
100
|
def optparse_no_command!(argv)
|
|
101
|
-
argv <<
|
|
101
|
+
argv << "--help" if argv.empty?
|
|
102
102
|
OptionParser.new("Usage: #{program_name} [command] [options]") do |op|
|
|
103
|
-
op.on(
|
|
103
|
+
op.on("-v", "--version", "Print the version") do
|
|
104
104
|
puts I18n::Tasks::VERSION
|
|
105
105
|
exit
|
|
106
106
|
end
|
|
@@ -111,12 +111,12 @@ class I18n::Tasks::CLI
|
|
|
111
111
|
|
|
112
112
|
def allow_help_arg_first!(argv)
|
|
113
113
|
# allow `i18n-tasks --help command` in addition to `i18n-tasks command --help`
|
|
114
|
-
argv[0], argv[1] = argv[1], argv[0] if %w[-h --help].include?(argv[0]) && argv[1] && !argv[1].start_with?(
|
|
114
|
+
argv[0], argv[1] = argv[1], argv[0] if %w[-h --help].include?(argv[0]) && argv[1] && !argv[1].start_with?("-")
|
|
115
115
|
end
|
|
116
116
|
|
|
117
117
|
def parse_command!(argv)
|
|
118
118
|
allow_help_arg_first! argv
|
|
119
|
-
if argv[0] && !argv[0].start_with?(
|
|
119
|
+
if argv[0] && !argv[0].start_with?("-")
|
|
120
120
|
if commands.keys.include?(argv[0])
|
|
121
121
|
argv.shift
|
|
122
122
|
else
|
|
@@ -126,28 +126,28 @@ class I18n::Tasks::CLI
|
|
|
126
126
|
end
|
|
127
127
|
|
|
128
128
|
def verbose_option(op)
|
|
129
|
-
op.on(
|
|
129
|
+
op.on("--verbose", "Verbose output") do
|
|
130
130
|
::I18n::Tasks.verbose = true
|
|
131
131
|
end
|
|
132
132
|
end
|
|
133
133
|
|
|
134
134
|
def help_option(op)
|
|
135
|
-
op.on(
|
|
136
|
-
|
|
135
|
+
op.on("-h", "--help", "Show this message") do
|
|
136
|
+
warn op
|
|
137
137
|
exit
|
|
138
138
|
end
|
|
139
139
|
end
|
|
140
140
|
|
|
141
141
|
# @param [OptionParser] op
|
|
142
142
|
def commands_summary(op)
|
|
143
|
-
op.separator
|
|
144
|
-
op.separator
|
|
145
|
-
op.separator
|
|
143
|
+
op.separator ""
|
|
144
|
+
op.separator "Available commands:"
|
|
145
|
+
op.separator ""
|
|
146
146
|
commands.each do |cmd, cmd_conf|
|
|
147
|
-
op.separator " #{cmd.ljust(op.summary_width + 1,
|
|
147
|
+
op.separator " #{cmd.ljust(op.summary_width + 1, " ")}#{try_call cmd_conf[:desc]}"
|
|
148
148
|
end
|
|
149
|
-
op.separator
|
|
150
|
-
op.separator
|
|
149
|
+
op.separator ""
|
|
150
|
+
op.separator "See `i18n-tasks <command> --help` for more information on a specific command."
|
|
151
151
|
end
|
|
152
152
|
|
|
153
153
|
def optparse_args(flag)
|
|
@@ -155,14 +155,14 @@ class I18n::Tasks::CLI
|
|
|
155
155
|
args.map! { |v| try_call v }
|
|
156
156
|
conf = args.extract_options!
|
|
157
157
|
if conf.key?(:default)
|
|
158
|
-
args[-1] = "#{args[-1]}. #{I18n.t(
|
|
158
|
+
args[-1] = "#{args[-1]}. #{I18n.t("i18n_tasks.cmd.args.default_text", value: conf[:default])}"
|
|
159
159
|
end
|
|
160
160
|
args
|
|
161
161
|
end
|
|
162
162
|
|
|
163
163
|
def parse_options!(options, command, argv)
|
|
164
164
|
commands[command][:args].each do |flag|
|
|
165
|
-
name
|
|
165
|
+
name = option_name flag
|
|
166
166
|
options[name] = parse_option flag, options[name], argv, context
|
|
167
167
|
end
|
|
168
168
|
end
|
|
@@ -170,7 +170,7 @@ class I18n::Tasks::CLI
|
|
|
170
170
|
def parse_option(flag, val, argv, context)
|
|
171
171
|
conf = flag.last.is_a?(Hash) ? flag.last : {}
|
|
172
172
|
if conf[:consume_positional]
|
|
173
|
-
val = Array(val) + Array(flag.include?(Array) ? argv.flat_map { |x| x.split(
|
|
173
|
+
val = Array(val) + Array(flag.include?(Array) ? argv.flat_map { |x| x.split(",") } : argv)
|
|
174
174
|
end
|
|
175
175
|
val = conf[:default] if val.nil? && conf.key?(:default)
|
|
176
176
|
val = conf[:parser].call(val, context) if conf.key?(:parser)
|
|
@@ -179,8 +179,8 @@ class I18n::Tasks::CLI
|
|
|
179
179
|
|
|
180
180
|
def option_name(flag)
|
|
181
181
|
flag.detect do |f|
|
|
182
|
-
f.start_with?(
|
|
183
|
-
end.sub(/\A--(\[no-\])?/,
|
|
182
|
+
f.start_with?("--")
|
|
183
|
+
end.sub(/\A--(\[no-\])?/, "").sub(/[^\-\w].*\z/, "").to_sym
|
|
184
184
|
end
|
|
185
185
|
|
|
186
186
|
def try_call(v)
|
|
@@ -205,11 +205,18 @@ class I18n::Tasks::CLI
|
|
|
205
205
|
end
|
|
206
206
|
end
|
|
207
207
|
|
|
208
|
-
def auto_output_coloring(coloring = ENV[
|
|
209
|
-
coloring_was
|
|
208
|
+
def auto_output_coloring(coloring = ENV["I18N_TASKS_COLOR"] || $stdout.isatty)
|
|
209
|
+
coloring_was = Rainbow.enabled
|
|
210
210
|
Rainbow.enabled = coloring
|
|
211
211
|
yield
|
|
212
212
|
ensure
|
|
213
213
|
Rainbow.enabled = coloring_was
|
|
214
214
|
end
|
|
215
|
+
|
|
216
|
+
def load_dotenv
|
|
217
|
+
require "dotenv"
|
|
218
|
+
Dotenv.load
|
|
219
|
+
rescue LoadError
|
|
220
|
+
# dotenv not available, continue without it
|
|
221
|
+
end
|
|
215
222
|
end
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require
|
|
4
|
-
require
|
|
5
|
-
require
|
|
6
|
-
require
|
|
3
|
+
require "i18n/tasks/command/dsl"
|
|
4
|
+
require "i18n/tasks/command/options/common"
|
|
5
|
+
require "i18n/tasks/command/options/locales"
|
|
6
|
+
require "i18n/tasks/command/options/data"
|
|
7
7
|
|
|
8
8
|
module I18n::Tasks
|
|
9
9
|
module Command
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require
|
|
4
|
-
require
|
|
3
|
+
require "i18n/tasks/cli"
|
|
4
|
+
require "i18n/tasks/reports/terminal"
|
|
5
5
|
|
|
6
6
|
module I18n::Tasks
|
|
7
7
|
module Command
|
|
@@ -16,10 +16,10 @@ module I18n::Tasks
|
|
|
16
16
|
end
|
|
17
17
|
|
|
18
18
|
def run(name, opts = {})
|
|
19
|
-
log_stderr "#{Rainbow(
|
|
19
|
+
log_stderr "#{Rainbow("#StandWith").bg(:blue)}#{Rainbow("Ukraine").bg(:yellow)}"
|
|
20
20
|
name = name.to_sym
|
|
21
|
-
public_name = name.to_s.tr
|
|
22
|
-
log_verbose "task: #{public_name}(#{opts.map { |k, v| "#{k}: #{v.inspect}" } *
|
|
21
|
+
public_name = name.to_s.tr "_", "-"
|
|
22
|
+
log_verbose "task: #{public_name}(#{opts.map { |k, v| "#{k}: #{v.inspect}" } * ", "})"
|
|
23
23
|
if opts.empty? || method(name).arity.zero?
|
|
24
24
|
send name
|
|
25
25
|
else
|