i18n-js 4.0.0.alpha1 → 4.0.0.alpha4
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/.github/ISSUE_TEMPLATE/config.yml +5 -0
- data/.github/workflows/ruby-tests.yml +9 -18
- data/.rubocop.yml +4 -0
- data/README.md +131 -21
- data/exe/i18n +1 -1
- data/i18n-js.gemspec +1 -0
- data/i18njs.png +0 -0
- data/images/i18njs-check.gif +0 -0
- data/lib/i18n-js/cli/check_command.rb +123 -0
- data/lib/i18n-js/cli/command.rb +26 -0
- data/lib/i18n-js/cli/export_command.rb +5 -32
- data/lib/i18n-js/cli/init_command.rb +3 -1
- data/lib/i18n-js/cli/ui.rb +37 -3
- data/lib/i18n-js/cli.rb +11 -3
- data/lib/i18n-js/listen.rb +6 -5
- data/lib/i18n-js/version.rb +1 -1
- data/lib/i18n-js.rb +19 -12
- metadata +12 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3ecf4853a33adc9a67520a585c733a55e7b05e07bdc436830c519213bfc728b6
|
4
|
+
data.tar.gz: 5a1b68a4182bc30fcc3c57438ab226ba72a97a7f16dd6c29ac938106f4c5e00c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f8468f07c440fa8c29c84a6550ef8b7d5914cf08ce93d0b02f77caf65838a4057f8a7653cc221c33a1dfaf1ab0486aa195a368248ca9509af4af7071ab76ddaa
|
7
|
+
data.tar.gz: cb3822d5fe66aa90b20a4a596869a0adb93c3154d5877f66b1374794961536bc2916c051f8d5ce5f61d2d57c66951c25b477f8b808b7d737b39941875e545afb
|
@@ -2,18 +2,8 @@
|
|
2
2
|
name: ruby-tests
|
3
3
|
|
4
4
|
on:
|
5
|
-
|
6
|
-
branches:
|
7
|
-
- main
|
8
|
-
|
5
|
+
pull_request_target:
|
9
6
|
push:
|
10
|
-
branches:
|
11
|
-
- main
|
12
|
-
- v4
|
13
|
-
|
14
|
-
schedule:
|
15
|
-
- cron: "0 10 * * *"
|
16
|
-
|
17
7
|
workflow_dispatch:
|
18
8
|
inputs: {}
|
19
9
|
|
@@ -24,25 +14,26 @@ jobs:
|
|
24
14
|
strategy:
|
25
15
|
fail-fast: false
|
26
16
|
matrix:
|
27
|
-
ruby: [2.
|
17
|
+
ruby: ["2.7", "3.0", "3.1"]
|
28
18
|
gemfile:
|
29
19
|
- Gemfile
|
20
|
+
if: |
|
21
|
+
github.actor == 'dependabot[bot]' && github.event_name == 'pull_request_target' ||
|
22
|
+
github.actor != 'dependabot[bot]'
|
30
23
|
|
31
24
|
steps:
|
32
|
-
- uses: actions/checkout@
|
25
|
+
- uses: actions/checkout@v3
|
33
26
|
|
34
|
-
- uses: actions/cache@
|
27
|
+
- uses: actions/cache@v3
|
28
|
+
id: bundler-cache
|
35
29
|
with:
|
36
30
|
path: vendor/bundle
|
37
31
|
key: >
|
38
32
|
${{ runner.os }}-${{ matrix.ruby }}-gems-${{
|
39
33
|
hashFiles(matrix.gemfile) }}
|
40
|
-
restore-keys: >
|
41
|
-
${{ runner.os }}-${{ matrix.ruby }}-gems-${{
|
42
|
-
hashFiles(matrix.gemfile) }}
|
43
34
|
|
44
35
|
- name: Set up Ruby
|
45
|
-
uses:
|
36
|
+
uses: ruby/setup-ruby@v1
|
46
37
|
with:
|
47
38
|
ruby-version: ${{ matrix.ruby }}
|
48
39
|
|
data/.rubocop.yml
CHANGED
data/README.md
CHANGED
@@ -1,15 +1,30 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
1
|
+
<p align="center">
|
2
|
+
<img width="250" height="58" src="https://github.com/fnando/i18n-js/raw/main/i18njs.png" alt="i18n.js">
|
3
|
+
</p>
|
4
|
+
|
5
|
+
<p align="center">
|
6
|
+
Export <a href="https://rubygems.org/gems/i18n">i18n</a> translations to JSON.
|
7
|
+
<br>
|
8
|
+
A perfect fit if you want to export translations to JavaScript.
|
9
|
+
</p>
|
10
|
+
|
11
|
+
<p align="center">
|
12
|
+
<small>
|
13
|
+
Oh, you don't use Ruby? No problem! You can still use i18n-js
|
14
|
+
<br>
|
15
|
+
and the
|
16
|
+
<a href="https://www.npmjs.com/package/i18n-js/v/next">companion JavaScript package</a>.
|
17
|
+
</small>
|
18
|
+
</p>
|
19
|
+
|
20
|
+
<p align="center">
|
21
|
+
<a href="https://github.com/fnando/i18n-js"><img src="https://github.com/fnando/i18n-js/workflows/ruby-tests/badge.svg" alt="Tests"></a>
|
22
|
+
<a href="https://rubygems.org/gems/i18n-js"><img src="https://img.shields.io/gem/v/i18n-js.svg" alt="Gem"></a>
|
23
|
+
<a href="https://rubygems.org/gems/i18n-js"><img src="https://img.shields.io/gem/dt/i18n-js.svg" alt="Gem"></a>
|
24
|
+
<a href="https://tldrlegal.com/license/mit-license"><img src="https://img.shields.io/:License-MIT-blue.svg" alt="MIT License"></a>
|
25
|
+
</p>
|
26
|
+
|
27
|
+

|
13
28
|
|
14
29
|
## Installation
|
15
30
|
|
@@ -45,11 +60,16 @@ translations:
|
|
45
60
|
- "!*.errors"
|
46
61
|
- "!*.number.nth"
|
47
62
|
|
48
|
-
- file: app/frontend/locales/:locale.json
|
63
|
+
- file: app/frontend/locales/:locale.:digest.json
|
49
64
|
patterns:
|
50
65
|
- "*"
|
51
66
|
```
|
52
67
|
|
68
|
+
The output path can use the following placeholders:
|
69
|
+
|
70
|
+
- `:locale`: the language that's being exported.
|
71
|
+
- `:digest`: the MD5 hex digest of the exported file.
|
72
|
+
|
53
73
|
The Ruby API:
|
54
74
|
|
55
75
|
```ruby
|
@@ -62,16 +82,82 @@ I18nJS.call(config: config)
|
|
62
82
|
The CLI API:
|
63
83
|
|
64
84
|
```console
|
65
|
-
$ i18n
|
66
|
-
|
85
|
+
$ i18n --help
|
86
|
+
Usage: i18n COMMAND FLAGS
|
87
|
+
|
88
|
+
Commands:
|
89
|
+
|
90
|
+
- init: Initialize a project
|
91
|
+
- export: Export translations as JSON files
|
92
|
+
- version: Show package version
|
93
|
+
- check: Check for missing translations
|
94
|
+
|
95
|
+
Run `i18n COMMAND --help` for more information on specific commands.
|
67
96
|
```
|
68
97
|
|
69
98
|
By default, `i18n` will use `config/i18n.yml` and `config/environment.rb` as the
|
70
99
|
configuration files. If you don't have these files, then you'll need to specify
|
71
100
|
both `--config` and `--require`.
|
72
101
|
|
102
|
+
### Listing missing translations
|
103
|
+
|
104
|
+
To list missing and extraneous translations, you can use `i18n check`. This
|
105
|
+
command will load your translations similarly to how `i18n export` does, but
|
106
|
+
will output the list of keys that don't have a matching translation against the
|
107
|
+
default locale. Here's an example:
|
108
|
+
|
109
|
+

|
110
|
+
|
111
|
+
This command will exist with status 1 whenever there are missing translations.
|
112
|
+
This way you can use it as a CI linting.
|
113
|
+
|
73
114
|
## Automatically export translations
|
74
115
|
|
116
|
+
### Using watchman
|
117
|
+
|
118
|
+
Create a script at `bin/i18n-watch`.
|
119
|
+
|
120
|
+
```bash
|
121
|
+
#!/usr/bin/env bash
|
122
|
+
|
123
|
+
root=`pwd`
|
124
|
+
|
125
|
+
watchman watch-del "$root"
|
126
|
+
watchman watch-project "$root"
|
127
|
+
watchman trigger-del "$root" i18n
|
128
|
+
|
129
|
+
watchman -j <<-JSON
|
130
|
+
[
|
131
|
+
"trigger",
|
132
|
+
"$root",
|
133
|
+
{
|
134
|
+
"name": "i18n",
|
135
|
+
"expression": [
|
136
|
+
"anyof",
|
137
|
+
["match", "config/locales/**/*.yml", "wholename"],
|
138
|
+
["match", "config/i18n.yml", "wholename"]
|
139
|
+
],
|
140
|
+
"command": ["i18n", "export"]
|
141
|
+
}
|
142
|
+
]
|
143
|
+
JSON
|
144
|
+
|
145
|
+
# If you're running this through Foreman,
|
146
|
+
# the uncomment the following lines:
|
147
|
+
# while true; do
|
148
|
+
# sleep 1
|
149
|
+
# done
|
150
|
+
```
|
151
|
+
|
152
|
+
Make it executable with `chmod +x bin/i18n-watch`. To watch for changes, run
|
153
|
+
`./bin/i18n-watch`. If you're using Foreman, make sure you uncommented the lines
|
154
|
+
that keep the process running (`while..`), and add something like the following
|
155
|
+
line to your Procfile:
|
156
|
+
|
157
|
+
```
|
158
|
+
i18n: ./bin/i18n-watch
|
159
|
+
```
|
160
|
+
|
75
161
|
### Using guard
|
76
162
|
|
77
163
|
Install [guard](https://rubygems.org/packages/guard) and
|
@@ -89,7 +175,7 @@ guard(:"i18n-js",
|
|
89
175
|
end
|
90
176
|
```
|
91
177
|
|
92
|
-
If
|
178
|
+
If your files are located in a different path, remember to configure file paths
|
93
179
|
accordingly.
|
94
180
|
|
95
181
|
Now you can run `guard start -i`.
|
@@ -99,11 +185,10 @@ Now you can run `guard start -i`.
|
|
99
185
|
Create a file under `config/initializers/i18n.rb` with the following content:
|
100
186
|
|
101
187
|
```ruby
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
I18nJS.listen
|
188
|
+
Rails.application.config.after_initialize do
|
189
|
+
require "i18n-js/listen"
|
190
|
+
I18nJS.listen
|
191
|
+
end
|
107
192
|
```
|
108
193
|
|
109
194
|
The code above will watch for changes based on `config/i18n.yml` and
|
@@ -116,6 +201,31 @@ You're done exporting files, now what? Well, go to
|
|
116
201
|
[i18n](https://github.com/fnando/i18n) to discover how to use the NPM package
|
117
202
|
that loads all the exported translation.
|
118
203
|
|
204
|
+
### FAQ
|
205
|
+
|
206
|
+
#### How can I export translations without having a database around?
|
207
|
+
|
208
|
+
Some people may have a build process using something like Docker that don't
|
209
|
+
necessarily have a database available. In this case, you may define your own
|
210
|
+
loading file by using something like
|
211
|
+
`i18n export --require ./config/i18n_export.rb`, where `i18n_export.rb` may look
|
212
|
+
like this:
|
213
|
+
|
214
|
+
```ruby
|
215
|
+
# frozen_string_literal: true
|
216
|
+
|
217
|
+
require "bundler/setup"
|
218
|
+
require "rails"
|
219
|
+
require "active_support/railtie"
|
220
|
+
require "action_view/railtie"
|
221
|
+
|
222
|
+
I18n.load_path += Dir["./config/locales/**/*.yml"]
|
223
|
+
```
|
224
|
+
|
225
|
+
Notice that you may not need to load ActiveSupport and ActionView lines, or even
|
226
|
+
may need to add additional requires for other libs. With this approach you have
|
227
|
+
full control on what's going to be loaded.
|
228
|
+
|
119
229
|
## Maintainer
|
120
230
|
|
121
231
|
- [Nando Vieira](https://github.com/fnando)
|
data/exe/i18n
CHANGED
data/i18n-js.gemspec
CHANGED
@@ -12,6 +12,7 @@ Gem::Specification.new do |spec|
|
|
12
12
|
spec.description = spec.summary
|
13
13
|
spec.license = "MIT"
|
14
14
|
spec.required_ruby_version = Gem::Requirement.new(">= 2.6.0")
|
15
|
+
spec.metadata = {"rubygems_mfa_required" => "true"}
|
15
16
|
|
16
17
|
github_url = "https://github.com/fnando/i18n-js"
|
17
18
|
github_tree_url = "#{github_url}/tree/v#{spec.version}"
|
data/i18njs.png
ADDED
Binary file
|
Binary file
|
@@ -0,0 +1,123 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "benchmark"
|
4
|
+
|
5
|
+
module I18nJS
|
6
|
+
class CLI
|
7
|
+
class CheckCommand < Command
|
8
|
+
command_name "check"
|
9
|
+
description "Check for missing translations"
|
10
|
+
|
11
|
+
parse do |opts|
|
12
|
+
opts.banner = "Usage: i18n #{name} [options]"
|
13
|
+
|
14
|
+
opts.on(
|
15
|
+
"-cCONFIG_FILE",
|
16
|
+
"--config=CONFIG_FILE",
|
17
|
+
"The configuration file that will be used"
|
18
|
+
) do |config_file|
|
19
|
+
options[:config_file] = config_file
|
20
|
+
end
|
21
|
+
|
22
|
+
opts.on(
|
23
|
+
"-rREQUIRE_FILE",
|
24
|
+
"--require=REQUIRE_FILE",
|
25
|
+
"A Ruby file that must be loaded"
|
26
|
+
) do |require_file|
|
27
|
+
options[:require_file] = require_file
|
28
|
+
end
|
29
|
+
|
30
|
+
opts.on(
|
31
|
+
"--[no-]color",
|
32
|
+
"Force colored output"
|
33
|
+
) do |colored|
|
34
|
+
options[:colored] = colored
|
35
|
+
end
|
36
|
+
|
37
|
+
opts.on("-h", "--help", "Prints this help") do
|
38
|
+
ui.exit_with opts.to_s
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
command do
|
43
|
+
set_defaults!
|
44
|
+
ui.colored = options[:colored]
|
45
|
+
|
46
|
+
unless options[:config_file]
|
47
|
+
ui.fail_with("=> ERROR: you need to specify the config file")
|
48
|
+
end
|
49
|
+
|
50
|
+
ui.stdout_print("=> Config file:", options[:config_file].inspect)
|
51
|
+
config_file = File.expand_path(options[:config_file])
|
52
|
+
|
53
|
+
if options[:require_file]
|
54
|
+
ui.stdout_print("=> Require file:", options[:require_file].inspect)
|
55
|
+
require_file = File.expand_path(options[:require_file])
|
56
|
+
end
|
57
|
+
|
58
|
+
unless File.file?(config_file)
|
59
|
+
ui.fail_with(
|
60
|
+
"=> ERROR: config file doesn't exist at",
|
61
|
+
config_file.inspect
|
62
|
+
)
|
63
|
+
end
|
64
|
+
|
65
|
+
if require_file && !File.file?(require_file)
|
66
|
+
ui.fail_with(
|
67
|
+
"=> ERROR: require file doesn't exist at",
|
68
|
+
require_file.inspect
|
69
|
+
)
|
70
|
+
end
|
71
|
+
|
72
|
+
load_require_file!(require_file) if require_file
|
73
|
+
default_locale = I18n.default_locale
|
74
|
+
available_locales = I18n.available_locales
|
75
|
+
|
76
|
+
mapping = available_locales.each_with_object({}) do |locale, buffer|
|
77
|
+
buffer[locale] =
|
78
|
+
Glob::Map.call(Glob.filter(I18nJS.translations, ["#{locale}.*"]))
|
79
|
+
.map {|key| key.gsub(/^.*?\./, "") }
|
80
|
+
end
|
81
|
+
|
82
|
+
default_locale_keys = mapping.delete(default_locale)
|
83
|
+
|
84
|
+
ui.stdout_print "=> #{default_locale}: #{default_locale_keys.size} " \
|
85
|
+
"translations"
|
86
|
+
|
87
|
+
total_missing_count = 0
|
88
|
+
|
89
|
+
mapping.each do |locale, partial_keys|
|
90
|
+
extraneous = partial_keys - default_locale_keys
|
91
|
+
missing = default_locale_keys - (partial_keys - extraneous)
|
92
|
+
total_missing_count += missing.size
|
93
|
+
ui.stdout_print "=> #{locale}: #{missing.size} missing, " \
|
94
|
+
"#{extraneous.size} extraneous"
|
95
|
+
|
96
|
+
all_keys = (default_locale_keys + extraneous + missing).uniq.sort
|
97
|
+
|
98
|
+
all_keys.each do |key|
|
99
|
+
label = if extraneous.include?(key)
|
100
|
+
ui.yellow("extraneous")
|
101
|
+
elsif missing.include?(key)
|
102
|
+
ui.red("missing")
|
103
|
+
else
|
104
|
+
next
|
105
|
+
end
|
106
|
+
|
107
|
+
ui.stdout_print(" - #{locale}.#{key} (#{label})")
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
exit(1) if total_missing_count.nonzero?
|
112
|
+
end
|
113
|
+
|
114
|
+
private def set_defaults!
|
115
|
+
config_file = "./config/i18n.yml"
|
116
|
+
require_file = "./config/environment.rb"
|
117
|
+
|
118
|
+
options[:config_file] ||= config_file if File.file?(config_file)
|
119
|
+
options[:require_file] ||= require_file if File.file?(require_file)
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
data/lib/i18n-js/cli/command.rb
CHANGED
@@ -38,6 +38,32 @@ module I18nJS
|
|
38
38
|
def options
|
39
39
|
@options ||= {}
|
40
40
|
end
|
41
|
+
|
42
|
+
private def load_require_file!(require_file)
|
43
|
+
require_without_warnings(require_file)
|
44
|
+
rescue Exception => error # rubocop:disable Lint/RescueException
|
45
|
+
ui.stderr_print("=> ERROR: couldn't load",
|
46
|
+
options[:require_file].inspect)
|
47
|
+
ui.fail_with(
|
48
|
+
"\n#{error_description(error)}\n#{error.backtrace.join("\n")}"
|
49
|
+
)
|
50
|
+
end
|
51
|
+
|
52
|
+
private def error_description(error)
|
53
|
+
[
|
54
|
+
error.class.name,
|
55
|
+
error.message
|
56
|
+
].reject(&:empty?).join(" => ")
|
57
|
+
end
|
58
|
+
|
59
|
+
private def require_without_warnings(path)
|
60
|
+
old_verbose = $VERBOSE
|
61
|
+
$VERBOSE = nil
|
62
|
+
|
63
|
+
load path
|
64
|
+
ensure
|
65
|
+
$VERBOSE = old_verbose
|
66
|
+
end
|
41
67
|
end
|
42
68
|
end
|
43
69
|
end
|
@@ -14,7 +14,7 @@ module I18nJS
|
|
14
14
|
opts.on(
|
15
15
|
"-cCONFIG_FILE",
|
16
16
|
"--config=CONFIG_FILE",
|
17
|
-
"The configuration file that will be
|
17
|
+
"The configuration file that will be used"
|
18
18
|
) do |config_file|
|
19
19
|
options[:config_file] = config_file
|
20
20
|
end
|
@@ -32,19 +32,18 @@ module I18nJS
|
|
32
32
|
end
|
33
33
|
end
|
34
34
|
|
35
|
-
command do
|
35
|
+
command do
|
36
36
|
set_defaults!
|
37
37
|
|
38
|
-
ui.stdout_print("=> config file:", options[:config_file].inspect)
|
39
|
-
ui.stdout_print("=> require file:", options[:require_file].inspect)
|
40
|
-
|
41
38
|
unless options[:config_file]
|
42
39
|
ui.fail_with("=> ERROR: you need to specify the config file")
|
43
40
|
end
|
44
41
|
|
42
|
+
ui.stdout_print("=> Config file:", options[:config_file].inspect)
|
45
43
|
config_file = File.expand_path(options[:config_file])
|
46
44
|
|
47
45
|
if options[:require_file]
|
46
|
+
ui.stdout_print("=> Require file:", options[:require_file].inspect)
|
48
47
|
require_file = File.expand_path(options[:require_file])
|
49
48
|
end
|
50
49
|
|
@@ -67,7 +66,7 @@ module I18nJS
|
|
67
66
|
I18nJS.call(config_file: config_file)
|
68
67
|
end
|
69
68
|
|
70
|
-
ui.stdout_print("=>
|
69
|
+
ui.stdout_print("=> Done in #{time.round(2)}s")
|
71
70
|
end
|
72
71
|
|
73
72
|
private def set_defaults!
|
@@ -77,32 +76,6 @@ module I18nJS
|
|
77
76
|
options[:config_file] ||= config_file if File.file?(config_file)
|
78
77
|
options[:require_file] ||= require_file if File.file?(require_file)
|
79
78
|
end
|
80
|
-
|
81
|
-
private def load_require_file!(require_file)
|
82
|
-
require_without_warnings(require_file)
|
83
|
-
rescue Exception => error # rubocop:disable Lint/RescueException
|
84
|
-
ui.stderr_print("=> ERROR: couldn't load",
|
85
|
-
options[:require_file].inspect)
|
86
|
-
ui.fail_with(
|
87
|
-
"\n#{error_description(error)}\n#{error.backtrace.join("\n")}"
|
88
|
-
)
|
89
|
-
end
|
90
|
-
|
91
|
-
private def error_description(error)
|
92
|
-
[
|
93
|
-
error.class.name,
|
94
|
-
error.message
|
95
|
-
].reject(&:empty?).join(" => ")
|
96
|
-
end
|
97
|
-
|
98
|
-
private def require_without_warnings(path)
|
99
|
-
old_verbose = $VERBOSE
|
100
|
-
$VERBOSE = nil
|
101
|
-
|
102
|
-
require path
|
103
|
-
ensure
|
104
|
-
$VERBOSE = old_verbose
|
105
|
-
end
|
106
79
|
end
|
107
80
|
end
|
108
81
|
end
|
@@ -23,7 +23,9 @@ module I18nJS
|
|
23
23
|
end
|
24
24
|
|
25
25
|
command do
|
26
|
-
file_path = File.expand_path(
|
26
|
+
file_path = File.expand_path(
|
27
|
+
options.fetch(:config_file, "config/i18n.yml")
|
28
|
+
)
|
27
29
|
|
28
30
|
if File.file?(file_path)
|
29
31
|
ui.fail_with("ERROR: #{file_path} already exists!")
|
data/lib/i18n-js/cli/ui.rb
CHANGED
@@ -3,17 +3,21 @@
|
|
3
3
|
module I18nJS
|
4
4
|
class CLI
|
5
5
|
class UI
|
6
|
-
|
6
|
+
attr_reader :stdout, :stderr
|
7
|
+
attr_accessor :colored
|
8
|
+
|
9
|
+
def initialize(stdout:, stderr:, colored: nil)
|
7
10
|
@stdout = stdout
|
8
11
|
@stderr = stderr
|
12
|
+
@colored = colored
|
9
13
|
end
|
10
14
|
|
11
15
|
def stdout_print(*message)
|
12
|
-
|
16
|
+
stdout << "#{message.join(' ')}\n"
|
13
17
|
end
|
14
18
|
|
15
19
|
def stderr_print(*message)
|
16
|
-
|
20
|
+
stderr << "#{message.join(' ')}\n"
|
17
21
|
end
|
18
22
|
|
19
23
|
def fail_with(*message)
|
@@ -25,6 +29,36 @@ module I18nJS
|
|
25
29
|
stdout_print(message)
|
26
30
|
exit(0)
|
27
31
|
end
|
32
|
+
|
33
|
+
def yellow(text)
|
34
|
+
ansi(text, 33)
|
35
|
+
end
|
36
|
+
|
37
|
+
def red(text)
|
38
|
+
ansi(text, 31)
|
39
|
+
end
|
40
|
+
|
41
|
+
def colored?
|
42
|
+
colored_output = if colored.nil?
|
43
|
+
stdout.tty?
|
44
|
+
else
|
45
|
+
colored
|
46
|
+
end
|
47
|
+
|
48
|
+
colored_output && !no_color?
|
49
|
+
end
|
50
|
+
|
51
|
+
def ansi(text, code)
|
52
|
+
if colored?
|
53
|
+
"\e[#{code}m#{text}\e[0m"
|
54
|
+
else
|
55
|
+
text
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def no_color?
|
60
|
+
!ENV["NO_COLOR"].nil? && ENV["NO_COLOR"] == "1"
|
61
|
+
end
|
28
62
|
end
|
29
63
|
end
|
30
64
|
end
|
data/lib/i18n-js/cli.rb
CHANGED
@@ -1,12 +1,20 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require_relative "../i18n-js"
|
4
|
+
require_relative "cli/command"
|
5
|
+
require_relative "cli/ui"
|
6
|
+
require_relative "cli/init_command"
|
7
|
+
require_relative "cli/version_command"
|
8
|
+
require_relative "cli/export_command"
|
9
|
+
require_relative "cli/check_command"
|
10
|
+
|
3
11
|
module I18nJS
|
4
12
|
class CLI
|
5
13
|
attr_reader :ui
|
6
14
|
|
7
|
-
def initialize(argv:, stdout:, stderr:)
|
15
|
+
def initialize(argv:, stdout:, stderr:, colored: stdout.tty?)
|
8
16
|
@argv = argv.dup
|
9
|
-
@ui = UI.new(stdout: stdout, stderr: stderr)
|
17
|
+
@ui = UI.new(stdout: stdout, stderr: stderr, colored: colored)
|
10
18
|
end
|
11
19
|
|
12
20
|
def call
|
@@ -19,7 +27,7 @@ module I18nJS
|
|
19
27
|
end
|
20
28
|
|
21
29
|
private def command_classes
|
22
|
-
[InitCommand, ExportCommand, VersionCommand]
|
30
|
+
[InitCommand, ExportCommand, VersionCommand, CheckCommand]
|
23
31
|
end
|
24
32
|
|
25
33
|
private def commands
|
data/lib/i18n-js/listen.rb
CHANGED
@@ -1,9 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
gem "listen"
|
4
|
-
require "listen"
|
5
|
-
require "i18n-js"
|
6
|
-
|
7
3
|
module I18nJS
|
8
4
|
class << self
|
9
5
|
attr_accessor :started
|
@@ -16,6 +12,10 @@ module I18nJS
|
|
16
12
|
return unless Rails.env.development?
|
17
13
|
return if started
|
18
14
|
|
15
|
+
gem "listen"
|
16
|
+
require "listen"
|
17
|
+
require "i18n-js"
|
18
|
+
|
19
19
|
self.started = true
|
20
20
|
|
21
21
|
relative_paths =
|
@@ -43,7 +43,7 @@ module I18nJS
|
|
43
43
|
@logger ||= ActiveSupport::TaggedLogging.new(Rails.logger)
|
44
44
|
end
|
45
45
|
|
46
|
-
def self.listener(config_file, locales_dir)
|
46
|
+
def self.listener(config_file, locales_dir)
|
47
47
|
paths = [File.dirname(config_file), locales_dir]
|
48
48
|
|
49
49
|
Listen.to(*paths) do |changed, added, removed|
|
@@ -58,6 +58,7 @@ module I18nJS
|
|
58
58
|
|
59
59
|
debug(changes.map {|key, value| "#{key}=#{value.inspect}" }.join(", "))
|
60
60
|
|
61
|
+
::I18n.backend.reload!
|
61
62
|
I18nJS.call(config_file: config_file)
|
62
63
|
end
|
63
64
|
end
|
data/lib/i18n-js/version.rb
CHANGED
data/lib/i18n-js.rb
CHANGED
@@ -7,14 +7,8 @@ require "glob"
|
|
7
7
|
require "fileutils"
|
8
8
|
require "optparse"
|
9
9
|
|
10
|
-
require_relative "
|
11
|
-
require_relative "
|
12
|
-
require_relative "./i18n-js/cli/ui"
|
13
|
-
require_relative "./i18n-js/cli/init_command"
|
14
|
-
require_relative "./i18n-js/cli/version_command"
|
15
|
-
require_relative "./i18n-js/cli/export_command"
|
16
|
-
require_relative "./i18n-js/schema"
|
17
|
-
require_relative "./i18n-js/version"
|
10
|
+
require_relative "i18n-js/schema"
|
11
|
+
require_relative "i18n-js/version"
|
18
12
|
|
19
13
|
module I18nJS
|
20
14
|
MissingConfigError = Class.new(StandardError)
|
@@ -27,32 +21,45 @@ module I18nJS
|
|
27
21
|
|
28
22
|
config = Glob::SymbolizeKeys.call(config || YAML.load_file(config_file))
|
29
23
|
Schema.validate!(config)
|
24
|
+
exported_files = []
|
30
25
|
|
31
26
|
config[:translations].each do |group|
|
32
|
-
export_group(group)
|
27
|
+
exported_files += export_group(group)
|
33
28
|
end
|
29
|
+
|
30
|
+
exported_files
|
34
31
|
end
|
35
32
|
|
36
33
|
def self.export_group(group)
|
37
34
|
filtered_translations = Glob.filter(translations, group[:patterns])
|
38
35
|
output_file_path = File.expand_path(group[:file])
|
36
|
+
exported_files = []
|
39
37
|
|
40
38
|
if output_file_path.include?(":locale")
|
41
39
|
filtered_translations.each_key do |locale|
|
42
40
|
locale_file_path = output_file_path.gsub(/:locale/, locale.to_s)
|
43
|
-
write_file(locale_file_path,
|
41
|
+
exported_files << write_file(locale_file_path,
|
42
|
+
locale => filtered_translations[locale])
|
44
43
|
end
|
45
44
|
else
|
46
|
-
write_file(output_file_path, filtered_translations)
|
45
|
+
exported_files << write_file(output_file_path, filtered_translations)
|
47
46
|
end
|
47
|
+
|
48
|
+
exported_files
|
48
49
|
end
|
49
50
|
|
50
51
|
def self.write_file(file_path, translations)
|
51
52
|
FileUtils.mkdir_p(File.dirname(file_path))
|
52
53
|
|
54
|
+
contents = ::JSON.pretty_generate(translations)
|
55
|
+
digest = Digest::MD5.hexdigest(contents)
|
56
|
+
file_path = file_path.gsub(/:digest/, digest)
|
57
|
+
|
53
58
|
File.open(file_path, "w") do |file|
|
54
|
-
file <<
|
59
|
+
file << contents
|
55
60
|
end
|
61
|
+
|
62
|
+
file_path
|
56
63
|
end
|
57
64
|
|
58
65
|
def self.translations
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: i18n-js
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 4.0.0.
|
4
|
+
version: 4.0.0.alpha4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Nando Vieira
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2022-07-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: glob
|
@@ -161,6 +161,7 @@ files:
|
|
161
161
|
- ".github/CODEOWNERS"
|
162
162
|
- ".github/FUNDING.yml"
|
163
163
|
- ".github/ISSUE_TEMPLATE/bug_report.md"
|
164
|
+
- ".github/ISSUE_TEMPLATE/config.yml"
|
164
165
|
- ".github/ISSUE_TEMPLATE/feature_request.md"
|
165
166
|
- ".github/PULL_REQUEST_TEMPLATE.md"
|
166
167
|
- ".github/dependabot.yml"
|
@@ -176,11 +177,14 @@ files:
|
|
176
177
|
- Rakefile
|
177
178
|
- exe/i18n
|
178
179
|
- i18n-js.gemspec
|
180
|
+
- i18njs.png
|
181
|
+
- images/i18njs-check.gif
|
179
182
|
- lib/guard/i18n-js.rb
|
180
183
|
- lib/guard/i18n-js/templates/Guardfile
|
181
184
|
- lib/guard/i18n-js/version.rb
|
182
185
|
- lib/i18n-js.rb
|
183
186
|
- lib/i18n-js/cli.rb
|
187
|
+
- lib/i18n-js/cli/check_command.rb
|
184
188
|
- lib/i18n-js/cli/command.rb
|
185
189
|
- lib/i18n-js/cli/export_command.rb
|
186
190
|
- lib/i18n-js/cli/init_command.rb
|
@@ -193,12 +197,13 @@ homepage: https://github.com/fnando/i18n-js
|
|
193
197
|
licenses:
|
194
198
|
- MIT
|
195
199
|
metadata:
|
200
|
+
rubygems_mfa_required: 'true'
|
196
201
|
homepage_uri: https://github.com/fnando/i18n-js
|
197
202
|
bug_tracker_uri: https://github.com/fnando/i18n-js/issues
|
198
|
-
source_code_uri: https://github.com/fnando/i18n-js/tree/v4.0.0.
|
199
|
-
changelog_uri: https://github.com/fnando/i18n-js/tree/v4.0.0.
|
200
|
-
documentation_uri: https://github.com/fnando/i18n-js/tree/v4.0.0.
|
201
|
-
license_uri: https://github.com/fnando/i18n-js/tree/v4.0.0.
|
203
|
+
source_code_uri: https://github.com/fnando/i18n-js/tree/v4.0.0.alpha4
|
204
|
+
changelog_uri: https://github.com/fnando/i18n-js/tree/v4.0.0.alpha4/CHANGELOG.md
|
205
|
+
documentation_uri: https://github.com/fnando/i18n-js/tree/v4.0.0.alpha4/README.md
|
206
|
+
license_uri: https://github.com/fnando/i18n-js/tree/v4.0.0.alpha4/LICENSE.md
|
202
207
|
post_install_message:
|
203
208
|
rdoc_options: []
|
204
209
|
require_paths:
|
@@ -214,7 +219,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
214
219
|
- !ruby/object:Gem::Version
|
215
220
|
version: 1.3.1
|
216
221
|
requirements: []
|
217
|
-
rubygems_version: 3.
|
222
|
+
rubygems_version: 3.3.7
|
218
223
|
signing_key:
|
219
224
|
specification_version: 4
|
220
225
|
summary: Export i18n translations and use them on JavaScript.
|