i18n-js 4.0.0.alpha2 → 4.0.0.alpha5
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 +7 -4
- data/.rubocop.yml +2 -3
- data/README.md +153 -16
- data/i18njs.png +0 -0
- data/images/i18njs-check.gif +0 -0
- data/lib/i18n-js/cli/check_command.rb +157 -0
- data/lib/i18n-js/cli/command.rb +26 -0
- data/lib/i18n-js/cli/export_command.rb +4 -31
- 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 +4 -3
- data/lib/i18n-js/schema.rb +13 -1
- data/lib/i18n-js/version.rb +1 -1
- data/lib/i18n-js.rb +17 -4
- metadata +11 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a5b5c71c903af1425bb6d7b12d0e74dc2da41894cf75a428da19bb11715dc371
|
4
|
+
data.tar.gz: 4914b448a0aca280c53412827d11b0148a7ec6393ff875fca78efea84bb68ce2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: dd4f1880a36a9bee698766b843b73489517c1e09c86e143f1e5582811275423714c4c4a741cd01e86c7af558a33866738c9235399b309d09b97fd71375af77cb
|
7
|
+
data.tar.gz: 47e0d59fb0d12e2203508ff0c1bef534c9e42a77a895d78bea0d811f97ab6e2d2e0cc4461e46a36ba07016d0d77a4ac488b88fabdf71eb94325080b2fe2acd10
|
@@ -2,7 +2,7 @@
|
|
2
2
|
name: ruby-tests
|
3
3
|
|
4
4
|
on:
|
5
|
-
|
5
|
+
pull_request_target:
|
6
6
|
push:
|
7
7
|
workflow_dispatch:
|
8
8
|
inputs: {}
|
@@ -14,14 +14,17 @@ jobs:
|
|
14
14
|
strategy:
|
15
15
|
fail-fast: false
|
16
16
|
matrix:
|
17
|
-
ruby: ["2.7", "3.0"]
|
17
|
+
ruby: ["2.7", "3.0", "3.1"]
|
18
18
|
gemfile:
|
19
19
|
- Gemfile
|
20
|
+
if: |
|
21
|
+
github.actor == 'dependabot[bot]' && github.event_name == 'pull_request_target' ||
|
22
|
+
github.actor != 'dependabot[bot]'
|
20
23
|
|
21
24
|
steps:
|
22
|
-
- uses: actions/checkout@
|
25
|
+
- uses: actions/checkout@v3
|
23
26
|
|
24
|
-
- uses: actions/cache@
|
27
|
+
- uses: actions/cache@v3
|
25
28
|
id: bundler-cache
|
26
29
|
with:
|
27
30
|
path: vendor/bundle
|
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
|
+
> **Warning**: This branch contains the code for v4, our next major release.
|
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,108 @@ 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
|
+
|
114
|
+
You can ignore keys by adding a list to the config file:
|
115
|
+
|
116
|
+
```yml
|
117
|
+
---
|
118
|
+
translations:
|
119
|
+
- file: app/frontend/locales/en.json
|
120
|
+
patterns:
|
121
|
+
- "*"
|
122
|
+
- "!*.activerecord"
|
123
|
+
- "!*.errors"
|
124
|
+
- "!*.number.nth"
|
125
|
+
|
126
|
+
- file: app/frontend/locales/:locale.:digest.json
|
127
|
+
patterns:
|
128
|
+
- "*"
|
129
|
+
|
130
|
+
check:
|
131
|
+
ignore:
|
132
|
+
- en.mailer.login.subject
|
133
|
+
- en.mailer.login.body
|
134
|
+
```
|
135
|
+
|
136
|
+
> **Note**: In order to avoid mistakenly ignoring keys, this configuration
|
137
|
+
> option only accepts the full translation scope, rather than accepting a
|
138
|
+
> pattern like `pt.ignored.scope.*`.
|
139
|
+
|
73
140
|
## Automatically export translations
|
74
141
|
|
142
|
+
### Using watchman
|
143
|
+
|
144
|
+
Create a script at `bin/i18n-watch`.
|
145
|
+
|
146
|
+
```bash
|
147
|
+
#!/usr/bin/env bash
|
148
|
+
|
149
|
+
root=`pwd`
|
150
|
+
|
151
|
+
watchman watch-del "$root"
|
152
|
+
watchman watch-project "$root"
|
153
|
+
watchman trigger-del "$root" i18n
|
154
|
+
|
155
|
+
watchman -j <<-JSON
|
156
|
+
[
|
157
|
+
"trigger",
|
158
|
+
"$root",
|
159
|
+
{
|
160
|
+
"name": "i18n",
|
161
|
+
"expression": [
|
162
|
+
"anyof",
|
163
|
+
["match", "config/locales/**/*.yml", "wholename"],
|
164
|
+
["match", "config/i18n.yml", "wholename"]
|
165
|
+
],
|
166
|
+
"command": ["i18n", "export"]
|
167
|
+
}
|
168
|
+
]
|
169
|
+
JSON
|
170
|
+
|
171
|
+
# If you're running this through Foreman,
|
172
|
+
# the uncomment the following lines:
|
173
|
+
# while true; do
|
174
|
+
# sleep 1
|
175
|
+
# done
|
176
|
+
```
|
177
|
+
|
178
|
+
Make it executable with `chmod +x bin/i18n-watch`. To watch for changes, run
|
179
|
+
`./bin/i18n-watch`. If you're using Foreman, make sure you uncommented the lines
|
180
|
+
that keep the process running (`while..`), and add something like the following
|
181
|
+
line to your Procfile:
|
182
|
+
|
183
|
+
```
|
184
|
+
i18n: ./bin/i18n-watch
|
185
|
+
```
|
186
|
+
|
75
187
|
### Using guard
|
76
188
|
|
77
189
|
Install [guard](https://rubygems.org/packages/guard) and
|
@@ -89,7 +201,7 @@ guard(:"i18n-js",
|
|
89
201
|
end
|
90
202
|
```
|
91
203
|
|
92
|
-
If
|
204
|
+
If your files are located in a different path, remember to configure file paths
|
93
205
|
accordingly.
|
94
206
|
|
95
207
|
Now you can run `guard start -i`.
|
@@ -115,6 +227,31 @@ You're done exporting files, now what? Well, go to
|
|
115
227
|
[i18n](https://github.com/fnando/i18n) to discover how to use the NPM package
|
116
228
|
that loads all the exported translation.
|
117
229
|
|
230
|
+
### FAQ
|
231
|
+
|
232
|
+
#### How can I export translations without having a database around?
|
233
|
+
|
234
|
+
Some people may have a build process using something like Docker that don't
|
235
|
+
necessarily have a database available. In this case, you may define your own
|
236
|
+
loading file by using something like
|
237
|
+
`i18n export --require ./config/i18n_export.rb`, where `i18n_export.rb` may look
|
238
|
+
like this:
|
239
|
+
|
240
|
+
```ruby
|
241
|
+
# frozen_string_literal: true
|
242
|
+
|
243
|
+
require "bundler/setup"
|
244
|
+
require "rails"
|
245
|
+
require "active_support/railtie"
|
246
|
+
require "action_view/railtie"
|
247
|
+
|
248
|
+
I18n.load_path += Dir["./config/locales/**/*.yml"]
|
249
|
+
```
|
250
|
+
|
251
|
+
Notice that you may not need to load ActiveSupport and ActionView lines, or even
|
252
|
+
may need to add additional requires for other libs. With this approach you have
|
253
|
+
full control on what's going to be loaded.
|
254
|
+
|
118
255
|
## Maintainer
|
119
256
|
|
120
257
|
- [Nando Vieira](https://github.com/fnando)
|
data/i18njs.png
ADDED
Binary file
|
Binary file
|
@@ -0,0 +1,157 @@
|
|
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
|
+
config = Glob::SymbolizeKeys.call(YAML.load_file(config_file))
|
73
|
+
Schema.validate!(config)
|
74
|
+
|
75
|
+
load_require_file!(require_file) if require_file
|
76
|
+
|
77
|
+
default_locale = I18n.default_locale
|
78
|
+
available_locales = I18n.available_locales
|
79
|
+
ignored_keys = config.dig(:check, :ignore) || []
|
80
|
+
|
81
|
+
mapping = available_locales.each_with_object({}) do |locale, buffer|
|
82
|
+
buffer[locale] =
|
83
|
+
Glob::Map.call(Glob.filter(I18nJS.translations, ["#{locale}.*"]))
|
84
|
+
.map {|key| key.gsub(/^.*?\./, "") }
|
85
|
+
end
|
86
|
+
|
87
|
+
default_locale_keys = mapping.delete(default_locale)
|
88
|
+
|
89
|
+
if ignored_keys.any?
|
90
|
+
ui.stdout_print "=> Check #{options[:config_file].inspect} for " \
|
91
|
+
"ignored keys."
|
92
|
+
end
|
93
|
+
|
94
|
+
ui.stdout_print "=> #{default_locale}: #{default_locale_keys.size} " \
|
95
|
+
"translations"
|
96
|
+
|
97
|
+
total_missing_count = 0
|
98
|
+
|
99
|
+
mapping.each do |locale, partial_keys|
|
100
|
+
ignored_count = 0
|
101
|
+
|
102
|
+
# Compute list of filtered keys (i.e. keys not ignored)
|
103
|
+
filtered_keys = partial_keys.reject do |key|
|
104
|
+
key = "#{locale}.#{key}"
|
105
|
+
|
106
|
+
ignored = ignored_keys.include?(key)
|
107
|
+
ignored_count += 1 if ignored
|
108
|
+
ignored
|
109
|
+
end
|
110
|
+
|
111
|
+
extraneous = (partial_keys - default_locale_keys).reject do |key|
|
112
|
+
key = "#{locale}.#{key}"
|
113
|
+
ignored = ignored_keys.include?(key)
|
114
|
+
ignored_count += 1 if ignored
|
115
|
+
ignored
|
116
|
+
end
|
117
|
+
|
118
|
+
missing = (default_locale_keys - (filtered_keys - extraneous))
|
119
|
+
.reject {|key| ignored_keys.include?("#{locale}.#{key}") }
|
120
|
+
|
121
|
+
ignored_count += extraneous.size
|
122
|
+
total_missing_count += missing.size
|
123
|
+
|
124
|
+
ui.stdout_print "=> #{locale}: #{missing.size} missing, " \
|
125
|
+
"#{extraneous.size} extraneous, " \
|
126
|
+
"#{ignored_count} ignored"
|
127
|
+
|
128
|
+
all_keys = (default_locale_keys + extraneous + missing).uniq.sort
|
129
|
+
|
130
|
+
all_keys.each do |key|
|
131
|
+
next if ignored_keys.include?("#{locale}.#{key}")
|
132
|
+
|
133
|
+
label = if extraneous.include?(key)
|
134
|
+
ui.yellow("extraneous")
|
135
|
+
elsif missing.include?(key)
|
136
|
+
ui.red("missing")
|
137
|
+
else
|
138
|
+
next
|
139
|
+
end
|
140
|
+
|
141
|
+
ui.stdout_print(" - #{locale}.#{key} (#{label})")
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
exit(1) if total_missing_count.nonzero?
|
146
|
+
end
|
147
|
+
|
148
|
+
private def set_defaults!
|
149
|
+
config_file = "./config/i18n.yml"
|
150
|
+
require_file = "./config/environment.rb"
|
151
|
+
|
152
|
+
options[:config_file] ||= config_file if File.file?(config_file)
|
153
|
+
options[:require_file] ||= require_file if File.file?(require_file)
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
157
|
+
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
|
@@ -35,16 +35,15 @@ module I18nJS
|
|
35
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
@@ -6,14 +6,15 @@ require_relative "cli/ui"
|
|
6
6
|
require_relative "cli/init_command"
|
7
7
|
require_relative "cli/version_command"
|
8
8
|
require_relative "cli/export_command"
|
9
|
+
require_relative "cli/check_command"
|
9
10
|
|
10
11
|
module I18nJS
|
11
12
|
class CLI
|
12
13
|
attr_reader :ui
|
13
14
|
|
14
|
-
def initialize(argv:, stdout:, stderr:)
|
15
|
+
def initialize(argv:, stdout:, stderr:, colored: stdout.tty?)
|
15
16
|
@argv = argv.dup
|
16
|
-
@ui = UI.new(stdout: stdout, stderr: stderr)
|
17
|
+
@ui = UI.new(stdout: stdout, stderr: stderr, colored: colored)
|
17
18
|
end
|
18
19
|
|
19
20
|
def call
|
@@ -26,7 +27,7 @@ module I18nJS
|
|
26
27
|
end
|
27
28
|
|
28
29
|
private def command_classes
|
29
|
-
[InitCommand, ExportCommand, VersionCommand]
|
30
|
+
[InitCommand, ExportCommand, VersionCommand, CheckCommand]
|
30
31
|
end
|
31
32
|
|
32
33
|
private def commands
|
data/lib/i18n-js/schema.rb
CHANGED
@@ -4,8 +4,9 @@ module I18nJS
|
|
4
4
|
class Schema
|
5
5
|
InvalidError = Class.new(StandardError)
|
6
6
|
|
7
|
-
ROOT_KEYS = %i[translations].freeze
|
7
|
+
ROOT_KEYS = %i[translations check].freeze
|
8
8
|
REQUIRED_ROOT_KEYS = %i[translations].freeze
|
9
|
+
REQUIRED_CHECK_KEYS = %i[ignore].freeze
|
9
10
|
REQUIRED_TRANSLATION_KEYS = %i[file patterns].freeze
|
10
11
|
TRANSLATION_KEYS = %i[file patterns].freeze
|
11
12
|
|
@@ -25,6 +26,17 @@ module I18nJS
|
|
25
26
|
expect_required_keys(REQUIRED_ROOT_KEYS, target)
|
26
27
|
reject_extraneous_keys(ROOT_KEYS, target)
|
27
28
|
validate_translations
|
29
|
+
validate_check
|
30
|
+
end
|
31
|
+
|
32
|
+
def validate_check
|
33
|
+
return unless target.key?(:check)
|
34
|
+
|
35
|
+
check = target[:check]
|
36
|
+
|
37
|
+
expect_type(:check, check, Hash, target)
|
38
|
+
expect_required_keys(REQUIRED_CHECK_KEYS, check)
|
39
|
+
expect_type(:ignore, check[:ignore], Array, check)
|
28
40
|
end
|
29
41
|
|
30
42
|
def validate_translations
|
data/lib/i18n-js/version.rb
CHANGED
data/lib/i18n-js.rb
CHANGED
@@ -21,32 +21,45 @@ module I18nJS
|
|
21
21
|
|
22
22
|
config = Glob::SymbolizeKeys.call(config || YAML.load_file(config_file))
|
23
23
|
Schema.validate!(config)
|
24
|
+
exported_files = []
|
24
25
|
|
25
26
|
config[:translations].each do |group|
|
26
|
-
export_group(group)
|
27
|
+
exported_files += export_group(group)
|
27
28
|
end
|
29
|
+
|
30
|
+
exported_files
|
28
31
|
end
|
29
32
|
|
30
33
|
def self.export_group(group)
|
31
34
|
filtered_translations = Glob.filter(translations, group[:patterns])
|
32
35
|
output_file_path = File.expand_path(group[:file])
|
36
|
+
exported_files = []
|
33
37
|
|
34
38
|
if output_file_path.include?(":locale")
|
35
39
|
filtered_translations.each_key do |locale|
|
36
40
|
locale_file_path = output_file_path.gsub(/:locale/, locale.to_s)
|
37
|
-
write_file(locale_file_path,
|
41
|
+
exported_files << write_file(locale_file_path,
|
42
|
+
locale => filtered_translations[locale])
|
38
43
|
end
|
39
44
|
else
|
40
|
-
write_file(output_file_path, filtered_translations)
|
45
|
+
exported_files << write_file(output_file_path, filtered_translations)
|
41
46
|
end
|
47
|
+
|
48
|
+
exported_files
|
42
49
|
end
|
43
50
|
|
44
51
|
def self.write_file(file_path, translations)
|
45
52
|
FileUtils.mkdir_p(File.dirname(file_path))
|
46
53
|
|
54
|
+
contents = ::JSON.pretty_generate(translations)
|
55
|
+
digest = Digest::MD5.hexdigest(contents)
|
56
|
+
file_path = file_path.gsub(/:digest/, digest)
|
57
|
+
|
47
58
|
File.open(file_path, "w") do |file|
|
48
|
-
file <<
|
59
|
+
file << contents
|
49
60
|
end
|
61
|
+
|
62
|
+
file_path
|
50
63
|
end
|
51
64
|
|
52
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.alpha5
|
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-22 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
|
@@ -196,10 +200,10 @@ metadata:
|
|
196
200
|
rubygems_mfa_required: 'true'
|
197
201
|
homepage_uri: https://github.com/fnando/i18n-js
|
198
202
|
bug_tracker_uri: https://github.com/fnando/i18n-js/issues
|
199
|
-
source_code_uri: https://github.com/fnando/i18n-js/tree/v4.0.0.
|
200
|
-
changelog_uri: https://github.com/fnando/i18n-js/tree/v4.0.0.
|
201
|
-
documentation_uri: https://github.com/fnando/i18n-js/tree/v4.0.0.
|
202
|
-
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.alpha5
|
204
|
+
changelog_uri: https://github.com/fnando/i18n-js/tree/v4.0.0.alpha5/CHANGELOG.md
|
205
|
+
documentation_uri: https://github.com/fnando/i18n-js/tree/v4.0.0.alpha5/README.md
|
206
|
+
license_uri: https://github.com/fnando/i18n-js/tree/v4.0.0.alpha5/LICENSE.md
|
203
207
|
post_install_message:
|
204
208
|
rdoc_options: []
|
205
209
|
require_paths:
|
@@ -215,7 +219,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
215
219
|
- !ruby/object:Gem::Version
|
216
220
|
version: 1.3.1
|
217
221
|
requirements: []
|
218
|
-
rubygems_version: 3.
|
222
|
+
rubygems_version: 3.3.7
|
219
223
|
signing_key:
|
220
224
|
specification_version: 4
|
221
225
|
summary: Export i18n translations and use them on JavaScript.
|