i18n-js 4.0.0 → 4.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/.github/workflows/ruby-tests.yml +22 -1
- data/.gitignore +2 -0
- data/.rubocop.yml +3 -0
- data/CHANGELOG.md +20 -1
- data/MIGRATING_FROM_V3_TO_V4.md +191 -0
- data/README.md +267 -25
- data/bin/pack +79 -0
- data/i18n-js.gemspec +5 -2
- data/lib/guard/i18n-js.rb +21 -4
- data/lib/i18n-js/cli/check_command.rb +7 -147
- data/lib/i18n-js/cli/command.rb +10 -0
- data/lib/i18n-js/cli/export_command.rb +17 -3
- data/lib/i18n-js/cli/lint_scripts_command.rb +157 -0
- data/lib/i18n-js/cli/lint_translations_command.rb +155 -0
- data/lib/i18n-js/cli/plugins_command.rb +67 -0
- data/lib/i18n-js/cli.rb +12 -1
- data/lib/i18n-js/embed_fallback_translations_plugin.rb +78 -0
- data/lib/i18n-js/lint.js +150645 -0
- data/lib/i18n-js/lint.ts +196 -0
- data/lib/i18n-js/listen.rb +25 -10
- data/lib/i18n-js/plugin.rb +38 -0
- data/lib/i18n-js/schema.rb +53 -14
- data/lib/i18n-js/version.rb +1 -1
- data/lib/i18n-js.rb +20 -3
- data/package.json +10 -0
- metadata +33 -11
- data/i18njs.png +0 -0
- data/images/i18njs-check.gif +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 60f1ad0e9477d8e6570573f64ac2a55136653da8e4791c6fc32e69c9547e197b
|
4
|
+
data.tar.gz: d46a3d8b8a25020635d9c108b2cb2caf3a256e419112a21a0d986f94e1e19c37
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a1d63d094866a836a69a9b3fc8f2989608a1b794daf5d5c82062e17b3bcb07ab7fb0ec8f2c05aa27a2585236cff33d974c313ca81be96de129340ecce8f78490
|
7
|
+
data.tar.gz: 7ec126b41663f765a421950c1ddcb215d460681355088fc77731673c44f3baf590cc58c6e5841bc9dda6f58732249488cdad3b020287b57d7d1de70cf8e95716
|
@@ -9,12 +9,15 @@ on:
|
|
9
9
|
|
10
10
|
jobs:
|
11
11
|
build:
|
12
|
-
name:
|
12
|
+
name:
|
13
|
+
Tests with Ruby ${{ matrix.ruby }}, Node ${{ matrix.node }} and ${{
|
14
|
+
matrix.gemfile }}
|
13
15
|
runs-on: "ubuntu-latest"
|
14
16
|
strategy:
|
15
17
|
fail-fast: false
|
16
18
|
matrix:
|
17
19
|
ruby: ["2.7", "3.0", "3.1"]
|
20
|
+
node: ["16", "18"]
|
18
21
|
gemfile:
|
19
22
|
- Gemfile
|
20
23
|
if: |
|
@@ -32,6 +35,23 @@ jobs:
|
|
32
35
|
${{ runner.os }}-${{ matrix.ruby }}-gems-${{
|
33
36
|
hashFiles(matrix.gemfile) }}
|
34
37
|
|
38
|
+
- uses: actions/cache@v3
|
39
|
+
id: npm-cache
|
40
|
+
with:
|
41
|
+
path: vendor/bundle
|
42
|
+
key: >
|
43
|
+
${{ runner.os }}-${{ matrix.node }}-npm-${{
|
44
|
+
hashFiles('package.json') }}
|
45
|
+
|
46
|
+
- name: Set up Node
|
47
|
+
uses: actions/setup-node@v2-beta
|
48
|
+
with:
|
49
|
+
node-version: ${{ matrix.node }}
|
50
|
+
|
51
|
+
- name: Install npm dependencies
|
52
|
+
run: |
|
53
|
+
yarn install
|
54
|
+
|
35
55
|
- name: Set up Ruby
|
36
56
|
uses: ruby/setup-ruby@v1
|
37
57
|
with:
|
@@ -49,4 +69,5 @@ jobs:
|
|
49
69
|
env:
|
50
70
|
BUNDLE_GEMFILE: ${{ matrix.gemfile }}
|
51
71
|
run: |
|
72
|
+
yarn compile
|
52
73
|
bundle exec rake
|
data/.gitignore
CHANGED
data/.rubocop.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -11,6 +11,25 @@ Prefix your message with one of the following:
|
|
11
11
|
- [Security] in case of vulnerabilities.
|
12
12
|
-->
|
13
13
|
|
14
|
-
##
|
14
|
+
## v4.1.0 - Dec 09, 2022
|
15
|
+
|
16
|
+
- [Added] Parse configuration files as erb.
|
17
|
+
- [Changed] `I18n.listen(run_on_start:)` was added to control if files should be
|
18
|
+
exported during `I18n.listen`'s boot. The default value is `true`.
|
19
|
+
- [Added] Now it's possible to transform translations before exporting them
|
20
|
+
using a stable plugin api.
|
21
|
+
- [Deprecated] The `i18n check` has been deprecated. Use
|
22
|
+
`i18n lint:translations` instead.
|
23
|
+
- [Added] Use `i18n lint:scripts` to lint JavaScript/TypeScript.
|
24
|
+
- [Fixed] Expand paths passed to `I18nJS.listen(locales_dir:)`.
|
25
|
+
|
26
|
+
## v4.0.1 - Aug 25, 2022
|
27
|
+
|
28
|
+
- [Fixed] Shell out export to avoid handling I18n reloading heuristics.
|
29
|
+
- [Changed] `I18nJS.listen` now accepts a directories list to watch.
|
30
|
+
- [Changed] `I18nJS.listen` now accepts
|
31
|
+
[listen](https://rubygems.org/gems/listen) options via `:options`.
|
32
|
+
|
33
|
+
## v4.0.0 - Jul 29, 2022
|
15
34
|
|
16
35
|
- Official release of i18n-js v4.0.0.
|
@@ -0,0 +1,191 @@
|
|
1
|
+
# Migrating from v3 to v4
|
2
|
+
|
3
|
+
I18n-js v4 is a breaking change release and diverges quite a lot from how the
|
4
|
+
previous version worked. This guides summarizes the process of upgrading an app
|
5
|
+
that uses i18n-js v3 to v4.
|
6
|
+
|
7
|
+
## Development
|
8
|
+
|
9
|
+
Previously, you could use a middleware to export translations (some people even
|
10
|
+
used this in production 😬). In development, you can now use whatever your want,
|
11
|
+
because i18n-js doesn't make any assumptions. All you need to do is running
|
12
|
+
`i18n export`, either manually or by using something that listens to file
|
13
|
+
changes.
|
14
|
+
|
15
|
+
If you like watchman, you can use something like this:
|
16
|
+
|
17
|
+
```bash
|
18
|
+
#!/usr/bin/env bash
|
19
|
+
|
20
|
+
root=`pwd`
|
21
|
+
|
22
|
+
watchman watch-del "$root"
|
23
|
+
watchman watch-project "$root"
|
24
|
+
watchman trigger-del "$root" i18n
|
25
|
+
|
26
|
+
watchman -j <<-JSON
|
27
|
+
[
|
28
|
+
"trigger",
|
29
|
+
"$root",
|
30
|
+
{
|
31
|
+
"name": "i18n",
|
32
|
+
"expression": [
|
33
|
+
"anyof",
|
34
|
+
["match", "config/locales/**/*.yml", "wholename"],
|
35
|
+
["match", "config/locales/**/*.po", "wholename"],
|
36
|
+
["match", "config/i18n.yml", "wholename"]
|
37
|
+
],
|
38
|
+
"command": ["i18n", "export"]
|
39
|
+
}
|
40
|
+
]
|
41
|
+
JSON
|
42
|
+
|
43
|
+
# If you're running this through Foreman, then uncomment the following lines:
|
44
|
+
# while true; do
|
45
|
+
# sleep 1
|
46
|
+
# done
|
47
|
+
```
|
48
|
+
|
49
|
+
You can also use guard. Make sure you have both
|
50
|
+
[guard](https://rubygems.org/packages/guard) and
|
51
|
+
[guard-compat](https://rubygems.org/packages/guard-compat) installed and use
|
52
|
+
Guardfile file with the following contents:
|
53
|
+
|
54
|
+
```ruby
|
55
|
+
guard(:"i18n-js",
|
56
|
+
run_on_start: true,
|
57
|
+
config_file: "./config/i18n.yml",
|
58
|
+
require_file: "./config/environment.rb") do
|
59
|
+
watch(%r{^config/locales/.+\.(yml|po)$})
|
60
|
+
watch(%r{^config/i18n.yml$})
|
61
|
+
watch("Gemfile")
|
62
|
+
end
|
63
|
+
```
|
64
|
+
|
65
|
+
To run guard, use `guard start -i`.
|
66
|
+
|
67
|
+
Finally, you can use [listen](https://rubygems.org/gems/listen). Create the file
|
68
|
+
`config/initializers/i18n.rb` with the following content:
|
69
|
+
|
70
|
+
```ruby
|
71
|
+
Rails.application.config.after_initialize do
|
72
|
+
require "i18n-js/listen"
|
73
|
+
# This will only run in development.
|
74
|
+
I18nJS.listen
|
75
|
+
end
|
76
|
+
```
|
77
|
+
|
78
|
+
> **Warning**:
|
79
|
+
>
|
80
|
+
> No matter which approach you choose, the idea is that you _precompile_ your
|
81
|
+
> translations when going to production. DO NOT RUN any of the above in
|
82
|
+
> production.
|
83
|
+
|
84
|
+
## Exporting translations
|
85
|
+
|
86
|
+
The build process for i18n now relies on an external CLI called `i18n`. All you
|
87
|
+
need to do is executing `i18n export` in your build step to generate the json
|
88
|
+
files for your translations.
|
89
|
+
|
90
|
+
## Using your translations
|
91
|
+
|
92
|
+
The JavaScript package is now a separate thing and need to be installed using
|
93
|
+
your favorite tooling (e.g. yarn, npm, pnpm, etc).
|
94
|
+
|
95
|
+
```console
|
96
|
+
$ yarn add i18n-js@latest
|
97
|
+
$ npm i --save-dev i18n-js@latest
|
98
|
+
```
|
99
|
+
|
100
|
+
From now on, the way you load translations and set up I18n-js is totally up to
|
101
|
+
you, but means you need to load the json files and attach to the I18n-js
|
102
|
+
instance. This is how I do it in a project I'm doing right now (Rails 7 +
|
103
|
+
esbuild + TypeScript). First, we need to load the I18n-js configuration from the
|
104
|
+
main JavaScript file:
|
105
|
+
|
106
|
+
```typescript
|
107
|
+
// app/javascript/application.ts
|
108
|
+
import { i18n } from "./config/i18n";
|
109
|
+
```
|
110
|
+
|
111
|
+
Then we need to load our translations and instantiate the I18n-js class.
|
112
|
+
|
113
|
+
```typescript
|
114
|
+
// app/javascript/config/i18n.ts
|
115
|
+
import { I18n } from "i18n-js";
|
116
|
+
import translations from "translations.json";
|
117
|
+
|
118
|
+
// Fetch user locale from html#lang.
|
119
|
+
// This value is being set on `app/views/layouts/application.html.erb` and
|
120
|
+
// is inferred from `ACCEPT-LANGUAGE` header.
|
121
|
+
const userLocale = document.documentElement.lang;
|
122
|
+
|
123
|
+
export const i18n = new I18n();
|
124
|
+
i18n.store(translations);
|
125
|
+
i18n.defaultLocale = "en";
|
126
|
+
i18n.enableFallback = true;
|
127
|
+
i18n.locale = userLocale;
|
128
|
+
```
|
129
|
+
|
130
|
+
The best thing about the above is that it is a pretty straightforward pattern in
|
131
|
+
the JavaScript community. It doesn't rely on specific parts from Sprockets (I'm
|
132
|
+
not even using it on my projects) or eRb files.
|
133
|
+
|
134
|
+
## Ruby on Rails
|
135
|
+
|
136
|
+
### Upgrading the configuration file
|
137
|
+
|
138
|
+
The configuration file loaded from `config/i18n.yml` has changed. Given the v3
|
139
|
+
configuration below
|
140
|
+
|
141
|
+
```yaml
|
142
|
+
---
|
143
|
+
translations:
|
144
|
+
- file: "app/assets/javascripts/date_formats.js"
|
145
|
+
only: "*.date.formats"
|
146
|
+
- file: "app/assets/javascripts/other.js"
|
147
|
+
only: ["*.activerecord", "*.admin.*.title"]
|
148
|
+
- file: "app/assets/javascripts/everything_else.js"
|
149
|
+
except:
|
150
|
+
- "*.activerecord"
|
151
|
+
- "*.admin.*.title"
|
152
|
+
- "*.date.formats"
|
153
|
+
```
|
154
|
+
|
155
|
+
the equivalent configuration file for v4 would be
|
156
|
+
|
157
|
+
```yaml
|
158
|
+
---
|
159
|
+
translations:
|
160
|
+
- file: "app/assets/javascripts/date_formats.js"
|
161
|
+
patterns:
|
162
|
+
- "*.date.formats"
|
163
|
+
- file: "app/assets/javascripts/other.js"
|
164
|
+
patterns:
|
165
|
+
- "*.activerecord"
|
166
|
+
- "*.admin.*.title"
|
167
|
+
- file: "app/assets/javascripts/everything_else.js"
|
168
|
+
patterns:
|
169
|
+
# Notice the exclamation mark.
|
170
|
+
- "!*.activerecord"
|
171
|
+
- "!*.admin.*.title"
|
172
|
+
- "!*.date.formats"
|
173
|
+
```
|
174
|
+
|
175
|
+
Other configuration options:
|
176
|
+
|
177
|
+
- `export_i18n_js`: removed without an equivalent
|
178
|
+
- `fallbacks`: removed without an equivalent
|
179
|
+
- `js_available_locales`: removed (on v4 you can use groups, like in
|
180
|
+
`{pt-BR,en}.*`)
|
181
|
+
- `namespace`: removed without an equivalent
|
182
|
+
- `sort_translation_keys`: removed (on v4 keys will always be sorted)
|
183
|
+
- `translations[].prefix`: removed without an equivalent
|
184
|
+
- `translations[].pretty_print`: removed (on v4 files will always be exported in
|
185
|
+
a readable format)
|
186
|
+
|
187
|
+
### Placeholders
|
188
|
+
|
189
|
+
Previously, v3 had the `%{locale}` placeholder, which can be used as part of the
|
190
|
+
directory and/or file name. Now, the syntax is just `:locale`. Additionally, you
|
191
|
+
can also use `:digest`, which uses a MD5 hex digest of the exported file.
|
data/README.md
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
<p align="center">
|
2
|
-
<img width="250" height="58" src="https://github.com/fnando/i18n-js/raw/main/i18njs.png" alt="i18n.js">
|
2
|
+
<img width="250" height="58" src="https://github.com/fnando/i18n-js/raw/main/images/i18njs.png" alt="i18n.js">
|
3
3
|
</p>
|
4
4
|
|
5
5
|
<p align="center">
|
@@ -12,14 +12,14 @@
|
|
12
12
|
<small>
|
13
13
|
Oh, you don't use Ruby? No problem! You can still use i18n-js
|
14
14
|
<br>
|
15
|
-
and the
|
16
|
-
<a href="https://www.npmjs.com/package/i18n-js/v/
|
15
|
+
and the
|
16
|
+
<a href="https://www.npmjs.com/package/i18n-js/v/latest">companion JavaScript package</a>.
|
17
17
|
</small>
|
18
18
|
</p>
|
19
19
|
|
20
20
|
<p align="center">
|
21
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
|
22
|
+
<a href="https://rubygems.org/gems/i18n-js"><img src="https://img.shields.io/gem/v/i18n-js.svg" alt="Gem"></a>
|
23
23
|
<a href="https://rubygems.org/gems/i18n-js"><img src="https://img.shields.io/gem/dt/i18n-js.svg" alt="Gem"></a>
|
24
24
|
<a href="https://tldrlegal.com/license/mit-license"><img src="https://img.shields.io/:License-MIT-blue.svg" alt="MIT License"></a>
|
25
25
|
</p>
|
@@ -45,6 +45,14 @@ About patterns:
|
|
45
45
|
- `*.messages.*`
|
46
46
|
- Patterns starting with `!` are excluded.
|
47
47
|
- `!*.activerecord.*` will exclude all ActiveRecord translations.
|
48
|
+
- You can use groups:
|
49
|
+
- `{pt-BR,en}.js.*` will include only `pt-BR` and `en` translations, even if
|
50
|
+
more languages are available.
|
51
|
+
|
52
|
+
> **Note**:
|
53
|
+
>
|
54
|
+
> Patterns use [glob](https://rubygems.org/gems/glob), so check it out for the
|
55
|
+
> most up-to-date documentation about what's available.
|
48
56
|
|
49
57
|
The config file:
|
50
58
|
|
@@ -68,6 +76,22 @@ The output path can use the following placeholders:
|
|
68
76
|
- `:locale`: the language that's being exported.
|
69
77
|
- `:digest`: the MD5 hex digest of the exported file.
|
70
78
|
|
79
|
+
The config file is processed as erb, so you can have dynamic content on it if
|
80
|
+
you want. The following example shows how to use groups from a variable.
|
81
|
+
|
82
|
+
```yml
|
83
|
+
---
|
84
|
+
<% group = "{en,pt}" %>
|
85
|
+
|
86
|
+
translations:
|
87
|
+
- file: app/frontend/translations.json
|
88
|
+
patterns:
|
89
|
+
- "<%= group %>.*"
|
90
|
+
- "!<%= group %>.activerecord"
|
91
|
+
- "!<%= group %>.errors"
|
92
|
+
- "!<%= group %>.number.nth"
|
93
|
+
```
|
94
|
+
|
71
95
|
The Ruby API:
|
72
96
|
|
73
97
|
```ruby
|
@@ -88,7 +112,9 @@ Commands:
|
|
88
112
|
- init: Initialize a project
|
89
113
|
- export: Export translations as JSON files
|
90
114
|
- version: Show package version
|
91
|
-
-
|
115
|
+
- plugins: List plugins that will be activated
|
116
|
+
- lint:translations: Check for missing translations
|
117
|
+
- lint:scripts: Lint files using TypeScript
|
92
118
|
|
93
119
|
Run `i18n COMMAND --help` for more information on specific commands.
|
94
120
|
```
|
@@ -97,14 +123,126 @@ By default, `i18n` will use `config/i18n.yml` and `config/environment.rb` as the
|
|
97
123
|
configuration files. If you don't have these files, then you'll need to specify
|
98
124
|
both `--config` and `--require`.
|
99
125
|
|
126
|
+
### Plugins
|
127
|
+
|
128
|
+
#### Built-in plugins:
|
129
|
+
|
130
|
+
##### `embed_fallback_translations`:
|
131
|
+
|
132
|
+
Embed fallback translations inferred from the default locale. This can be useful
|
133
|
+
in cases where you have multiple large translation files and don't want to load
|
134
|
+
the default locale together with the target locale.
|
135
|
+
|
136
|
+
To use it, add the following to your configuration file:
|
137
|
+
|
138
|
+
```yaml
|
139
|
+
embed_fallback_translations:
|
140
|
+
enabled: true
|
141
|
+
```
|
142
|
+
|
143
|
+
#### Plugin API
|
144
|
+
|
145
|
+
You can transform the exported translations by adding plugins. A plugin must
|
146
|
+
inherit from `I18nJS::Plugin` and can have 3 class methods. The following
|
147
|
+
example shows how the built-in `embed_fallback_translations` plugin is
|
148
|
+
implemented.
|
149
|
+
|
150
|
+
```ruby
|
151
|
+
# frozen_string_literal: true
|
152
|
+
|
153
|
+
module I18nJS
|
154
|
+
require "i18n-js/plugin"
|
155
|
+
|
156
|
+
class EmbedFallbackTranslationsPlugin < I18nJS::Plugin
|
157
|
+
CONFIG_KEY = :embed_fallback_translations
|
158
|
+
|
159
|
+
# This method must set up the basic plugin configuration, like adding the
|
160
|
+
# config's root key in case your plugin accepts configuration (defined via
|
161
|
+
# the config file).
|
162
|
+
#
|
163
|
+
# If you don't add this key, the linter will prevent non-default keys from
|
164
|
+
# being added to the configuration file.
|
165
|
+
def self.setup
|
166
|
+
I18nJS::Schema.root_keys << CONFIG_KEY
|
167
|
+
end
|
168
|
+
|
169
|
+
# In case your plugin accepts configuration, this is where you must validate
|
170
|
+
# the configuration, making sure only valid keys and type is provided.
|
171
|
+
# If the configuration contains invalid data, then you must raise an
|
172
|
+
# exception using something like
|
173
|
+
# `raise I18nJS::Schema::InvalidError, error_message`.
|
174
|
+
def self.validate_schema(config:)
|
175
|
+
return unless config.key?(CONFIG_KEY)
|
176
|
+
|
177
|
+
plugin_config = config[CONFIG_KEY]
|
178
|
+
valid_keys = %i[enabled]
|
179
|
+
schema = I18nJS::Schema.new(config)
|
180
|
+
|
181
|
+
schema.expect_required_keys(valid_keys, plugin_config)
|
182
|
+
schema.reject_extraneous_keys(valid_keys, plugin_config)
|
183
|
+
schema.expect_enabled_config(CONFIG_KEY, plugin_config[:enabled])
|
184
|
+
end
|
185
|
+
|
186
|
+
# This method is responsible for transforming the translations. The
|
187
|
+
# translations you'll receive may be already be filtered by other plugins
|
188
|
+
# and by the default filtering itself. If you need to access the original
|
189
|
+
# translations, use `I18nJS.translations`.
|
190
|
+
#
|
191
|
+
# Make sure you always check whether your plugin is active before
|
192
|
+
# transforming translations; otherwise, opting out transformation won't be
|
193
|
+
# possible.
|
194
|
+
def self.transform(translations:, config:)
|
195
|
+
return translations unless config.dig(CONFIG_KEY, :enabled)
|
196
|
+
|
197
|
+
translations_glob = Glob.new(translations)
|
198
|
+
translations_glob << "*"
|
199
|
+
|
200
|
+
mapping = translations.keys.each_with_object({}) do |locale, buffer|
|
201
|
+
buffer[locale] = Glob.new(translations[locale]).tap do |glob|
|
202
|
+
glob << "*"
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
default_locale = I18n.default_locale
|
207
|
+
default_locale_glob = mapping.delete(default_locale)
|
208
|
+
default_locale_paths = default_locale_glob.paths
|
209
|
+
|
210
|
+
mapping.each do |locale, glob|
|
211
|
+
missing_keys = default_locale_paths - glob.paths
|
212
|
+
|
213
|
+
missing_keys.each do |key|
|
214
|
+
components = key.split(".").map(&:to_sym)
|
215
|
+
fallback_translation = translations.dig(default_locale, *components)
|
216
|
+
|
217
|
+
next unless fallback_translation
|
218
|
+
|
219
|
+
translations_glob.set([locale, key].join("."), fallback_translation)
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
translations_glob.to_h
|
224
|
+
end
|
225
|
+
end
|
226
|
+
|
227
|
+
I18nJS.register_plugin(EmbedFallbackTranslationsPlugin)
|
228
|
+
end
|
229
|
+
```
|
230
|
+
|
231
|
+
To distribute this plugin, you need to create a gem package that matches the
|
232
|
+
pattern `i18n-js/*_plugin.rb`. You can test whether your plugin will be found by
|
233
|
+
installing your gem, opening a iRB session and running
|
234
|
+
`Gem.find_files("i18n-js/*_plugin.rb")`. If your plugin is not listed, then you
|
235
|
+
need to double check your gem load path and see why the file is not being
|
236
|
+
loaded.
|
237
|
+
|
100
238
|
### Listing missing translations
|
101
239
|
|
102
|
-
To list missing and extraneous translations, you can use
|
103
|
-
command will load your translations similarly to
|
104
|
-
will output the list of keys that don't have a
|
105
|
-
default locale. Here's an example:
|
240
|
+
To list missing and extraneous translations, you can use
|
241
|
+
`i18n lint:translations`. This command will load your translations similarly to
|
242
|
+
how `i18n export` does, but will output the list of keys that don't have a
|
243
|
+
matching translation against the default locale. Here's an example:
|
106
244
|
|
107
|
-

|
108
246
|
|
109
247
|
This command will exist with status 1 whenever there are missing translations.
|
110
248
|
This way you can use it as a CI linting.
|
@@ -125,19 +263,97 @@ translations:
|
|
125
263
|
patterns:
|
126
264
|
- "*"
|
127
265
|
|
128
|
-
|
266
|
+
lint_translations:
|
129
267
|
ignore:
|
130
268
|
- en.mailer.login.subject
|
131
269
|
- en.mailer.login.body
|
132
270
|
```
|
133
271
|
|
134
|
-
> **Note**:
|
135
|
-
>
|
136
|
-
>
|
272
|
+
> **Note**:
|
273
|
+
>
|
274
|
+
> In order to avoid mistakenly ignoring keys, this configuration option only
|
275
|
+
> accepts the full translation scope, rather than accepting a pattern like
|
276
|
+
> `pt.ignored.scope.*`.
|
277
|
+
|
278
|
+
### Linting your JavaScript/TypeScript files
|
279
|
+
|
280
|
+
To lint your script files and check for missing translations (which can signal
|
281
|
+
that you're either using wrong scopes or forgot to add the translation), use
|
282
|
+
`i18n lint:scripts`. This command will parse your JavaScript/TypeScript files
|
283
|
+
and extract all scopes being used. This command requires a Node.js runtime. You
|
284
|
+
can either specify one via `--node-path`, or let the plugin infer a binary from
|
285
|
+
your `$PATH`.
|
286
|
+
|
287
|
+
The comparison will be made against the export JSON files, which means it'll
|
288
|
+
consider transformations performed by plugins (e.g. the output files may be
|
289
|
+
affected by `embed_fallback_translations` plugin).
|
290
|
+
|
291
|
+
The translations that will be extract must be called as one of the following
|
292
|
+
ways:
|
293
|
+
|
294
|
+
- `i18n.t(scope, options)`
|
295
|
+
- `i18n.translate(scope, options)`
|
296
|
+
- `t(scope, options)`
|
297
|
+
|
298
|
+
Notice that only literal strings can be used, as in `i18n.t("message")`. If
|
299
|
+
you're using dynamic scoping through variables (e.g.
|
300
|
+
`const scope = "message"; i18n.t(scope)`), they will be skipped.
|
301
|
+
|
302
|
+
```console
|
303
|
+
$ i18n lint:scripts --config test/config/lint.yml --require test/config/require.rb
|
304
|
+
=> Config file: "test/config/lint.yml"
|
305
|
+
=> Require file: "test/config/require.rb"
|
306
|
+
=> Node: "/Users/fnando/.asdf/shims/node"
|
307
|
+
=> Available locales: [:en, :es, :pt]
|
308
|
+
=> Patterns: ["!(node_modules)/**/*.js", "!(node_modules)/**/*.ts", "!(node_modules)/**/*.jsx", "!(node_modules)/**/*.tsx"]
|
309
|
+
=> 9 translations, 11 missing, 4 ignored
|
310
|
+
- test/scripts/lint/file.js:1:1: en.js.missing
|
311
|
+
- test/scripts/lint/file.js:1:1: es.js.missing
|
312
|
+
- test/scripts/lint/file.js:1:1: pt.js.missing
|
313
|
+
- test/scripts/lint/file.js:2:8: en.base.js.missing
|
314
|
+
- test/scripts/lint/file.js:2:8: es.base.js.missing
|
315
|
+
- test/scripts/lint/file.js:2:8: pt.base.js.missing
|
316
|
+
- test/scripts/lint/file.js:4:8: en.js.missing
|
317
|
+
- test/scripts/lint/file.js:4:8: es.js.missing
|
318
|
+
- test/scripts/lint/file.js:4:8: pt.js.missing
|
319
|
+
- test/scripts/lint/file.js:6:1: en.another_ignore_scope
|
320
|
+
- test/scripts/lint/file.js:6:1: es.another_ignore_scope
|
321
|
+
```
|
322
|
+
|
323
|
+
This command will list all locales and their missing translations. Avoid listing
|
324
|
+
a particular translation, you can set `lint.ignore` on your config file.
|
325
|
+
|
326
|
+
```yaml
|
327
|
+
---
|
328
|
+
translations:
|
329
|
+
- file: app/frontend/translations.json
|
330
|
+
patterns:
|
331
|
+
- "*"
|
332
|
+
|
333
|
+
lint_scripts:
|
334
|
+
ignore:
|
335
|
+
- ignore_scope # will ignore this scope on all languages
|
336
|
+
- pt.another_ignore_scope # will ignore this scope only on `pt`
|
337
|
+
```
|
338
|
+
|
339
|
+
You can also set the patterns that will be looked up. By default, it scans all
|
340
|
+
JavaScript and TypeScript files that don't live on `node_modules`.
|
341
|
+
|
342
|
+
```yaml
|
343
|
+
---
|
344
|
+
translations:
|
345
|
+
- file: app/frontend/translations.json
|
346
|
+
patterns:
|
347
|
+
- "*"
|
348
|
+
|
349
|
+
lint:
|
350
|
+
patterns:
|
351
|
+
- "app/assets/**/*.ts"
|
352
|
+
```
|
137
353
|
|
138
354
|
## Automatically export translations
|
139
355
|
|
140
|
-
### Using watchman
|
356
|
+
### Using [watchman](https://facebook.github.io/watchman/)
|
141
357
|
|
142
358
|
Create a script at `bin/i18n-watch`.
|
143
359
|
|
@@ -182,11 +398,11 @@ line to your Procfile:
|
|
182
398
|
i18n: ./bin/i18n-watch
|
183
399
|
```
|
184
400
|
|
185
|
-
### Using guard
|
401
|
+
### Using [guard](https://rubygems.org/gems/guard)
|
186
402
|
|
187
|
-
Install [guard](https://rubygems.org/
|
188
|
-
[guard-compat](https://rubygems.org/
|
189
|
-
|
403
|
+
Install [guard](https://rubygems.org/gems/guard) and
|
404
|
+
[guard-compat](https://rubygems.org/gems/guard-compat). Then create a Guardfile
|
405
|
+
with the following configuration:
|
190
406
|
|
191
407
|
```ruby
|
192
408
|
guard(:"i18n-js",
|
@@ -204,7 +420,7 @@ accordingly.
|
|
204
420
|
|
205
421
|
Now you can run `guard start -i`.
|
206
422
|
|
207
|
-
### Using listen
|
423
|
+
### Using [listen](https://rubygems.org/gems/listen)
|
208
424
|
|
209
425
|
Create a file under `config/initializers/i18n.rb` with the following content:
|
210
426
|
|
@@ -216,8 +432,25 @@ end
|
|
216
432
|
```
|
217
433
|
|
218
434
|
The code above will watch for changes based on `config/i18n.yml` and
|
219
|
-
`config/locales`. You can customize these options
|
220
|
-
|
435
|
+
`config/locales`. You can customize these options:
|
436
|
+
|
437
|
+
- `config_file` - i18n-js configuration file
|
438
|
+
- `locales_dir` - one or multiple directories to watch for locales changes
|
439
|
+
- `options` - passed directly to
|
440
|
+
[listen](https://github.com/guard/listen/#options)
|
441
|
+
- `run_on_start` - export files on start. Defaults to `true`. When disabled,
|
442
|
+
files will be exported only when there are file changes.
|
443
|
+
|
444
|
+
Example:
|
445
|
+
|
446
|
+
```ruby
|
447
|
+
I18nJS.listen(
|
448
|
+
config_file: "config/i18n.yml",
|
449
|
+
locales_dir: ["config/locales", "app/views"],
|
450
|
+
options: {only: %r{.yml$}},
|
451
|
+
run_on_start: false
|
452
|
+
)
|
453
|
+
```
|
221
454
|
|
222
455
|
### Integrating with your frontend
|
223
456
|
|
@@ -227,6 +460,13 @@ that loads all the exported translation.
|
|
227
460
|
|
228
461
|
### FAQ
|
229
462
|
|
463
|
+
#### I'm running v3. Is there a migration plan?
|
464
|
+
|
465
|
+
[There's a document](https://github.com/fnando/i18n-js/tree/main/MIGRATING_FROM_V3_TO_V4.md)
|
466
|
+
outlining some of the things you need to do to migrate from v3 to v4. It may not
|
467
|
+
be as complete as we'd like it to be, so let's know if you face any issues
|
468
|
+
during the migration is not outline is that document.
|
469
|
+
|
230
470
|
#### How can I export translations without having a database around?
|
231
471
|
|
232
472
|
Some people may have a build process using something like Docker that don't
|
@@ -246,9 +486,11 @@ require "action_view/railtie"
|
|
246
486
|
I18n.load_path += Dir["./config/locales/**/*.yml"]
|
247
487
|
```
|
248
488
|
|
249
|
-
|
250
|
-
|
251
|
-
|
489
|
+
> **Note**:
|
490
|
+
>
|
491
|
+
> You may not need to load ActiveSupport and ActionView lines, or even may need
|
492
|
+
> to add additional requires for other libs. With this approach you have full
|
493
|
+
> control on what's going to be loaded.
|
252
494
|
|
253
495
|
## Maintainer
|
254
496
|
|