i18n-js 4.0.0 → 4.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0b2fdace9fca14d471ff34c3b24055d4093d82ce2a1f72f2df06364a98454a31
4
- data.tar.gz: 9ea6bd71626357c8fce24c28e991b9edc96f8a3230e55c4d55cf1dec3813c94e
3
+ metadata.gz: 60f1ad0e9477d8e6570573f64ac2a55136653da8e4791c6fc32e69c9547e197b
4
+ data.tar.gz: d46a3d8b8a25020635d9c108b2cb2caf3a256e419112a21a0d986f94e1e19c37
5
5
  SHA512:
6
- metadata.gz: 2c8da0348d02f04d805a013dadd24beb08fb7de555bfdded51e4e6c7c29ba392978a723b7e95be9d752dda2b35bbe6d6aefe4d4cf9166c1ddca09f003712533f
7
- data.tar.gz: 882af1975b1f2e479ad4d8bdcbe812175fae165c80a2f915223e14fc71fb0b3236774254e103754169eab5a3d577e219e10803fd05e14fa3bac82471e4c770e1
6
+ metadata.gz: a1d63d094866a836a69a9b3fc8f2989608a1b794daf5d5c82062e17b3bcb07ab7fb0ec8f2c05aa27a2585236cff33d974c313ca81be96de129340ecce8f78490
7
+ data.tar.gz: 7ec126b41663f765a421950c1ddcb215d460681355088fc77731673c44f3baf590cc58c6e5841bc9dda6f58732249488cdad3b020287b57d7d1de70cf8e95716
@@ -9,12 +9,15 @@ on:
9
9
 
10
10
  jobs:
11
11
  build:
12
- name: Tests with Ruby ${{ matrix.ruby }} and ${{ matrix.gemfile }}
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
@@ -9,3 +9,5 @@
9
9
  /vendor/
10
10
  *.log
11
11
  *.lock
12
+ /lib/**/*.js
13
+ /test/output
data/.rubocop.yml CHANGED
@@ -14,3 +14,6 @@ Naming/FileName:
14
14
  Exclude:
15
15
  - lib/i18n-js.rb
16
16
  - lib/guard/i18n-js.rb
17
+
18
+ Style/PerlBackrefs:
19
+ Enabled: false
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
- ## Jul 29, 2022
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/next">companion JavaScript package</a>.
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?include_prereleases" alt="Gem"></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
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
- - check: Check for missing translations
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 `i18n check`. This
103
- command will load your translations similarly to how `i18n export` does, but
104
- will output the list of keys that don't have a matching translation against the
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
- ![`i18n check` command in action](https://github.com/fnando/i18n-js/raw/main/images/i18njs-check.gif)
245
+ ![`i18n lint:translations` command in action](https://github.com/fnando/i18n-js/raw/main/images/i18njs-check.gif)
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
- check:
266
+ lint_translations:
129
267
  ignore:
130
268
  - en.mailer.login.subject
131
269
  - en.mailer.login.body
132
270
  ```
133
271
 
134
- > **Note**: In order to avoid mistakenly ignoring keys, this configuration
135
- > option only accepts the full translation scope, rather than accepting a
136
- > pattern like `pt.ignored.scope.*`.
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/packages/guard) and
188
- [guard-compat](https://rubygems.org/packages/guard-compat). Then create a
189
- Guardfile with the following configuration:
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 with
220
- `I18nJS.listen(config_file: "config/i18n.yml", locales_dir: "config/locales")`.
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
- Notice that you may not need to load ActiveSupport and ActionView lines, or even
250
- may need to add additional requires for other libs. With this approach you have
251
- full control on what's going to be loaded.
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