i18n-js 4.0.0 → 4.0.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0b2fdace9fca14d471ff34c3b24055d4093d82ce2a1f72f2df06364a98454a31
4
- data.tar.gz: 9ea6bd71626357c8fce24c28e991b9edc96f8a3230e55c4d55cf1dec3813c94e
3
+ metadata.gz: fb5f60568907f90a59b7d19a6b2f61cf9a3fff95ea419b1b8b31deab16529dc6
4
+ data.tar.gz: ca65b2bf6717b93218092e8c994cdbac8af6bc69fddab421ebef976c87dc5503
5
5
  SHA512:
6
- metadata.gz: 2c8da0348d02f04d805a013dadd24beb08fb7de555bfdded51e4e6c7c29ba392978a723b7e95be9d752dda2b35bbe6d6aefe4d4cf9166c1ddca09f003712533f
7
- data.tar.gz: 882af1975b1f2e479ad4d8bdcbe812175fae165c80a2f915223e14fc71fb0b3236774254e103754169eab5a3d577e219e10803fd05e14fa3bac82471e4c770e1
6
+ metadata.gz: 3e33c8605b5197cbdc6a8f30ef1cb7e5f911f84dd177d488489fcfc82e5dd2b8fb3e387b0fe89683c3e71c6025ff7b47685163317540c4e2c5c756936660be55
7
+ data.tar.gz: b4367db58b89392c42c94121ccdde7179e1ea455de6c20685ded2c034304ce4c8c44cbfa1a4967610443e4f91116058ee86bc14d2e913a2c6006ee648c189dd9
data/CHANGELOG.md CHANGED
@@ -11,6 +11,13 @@ Prefix your message with one of the following:
11
11
  - [Security] in case of vulnerabilities.
12
12
  -->
13
13
 
14
+ ## v4.0.1
15
+
16
+ - [Fixed] Shell out export to avoid handling I18n reloading heuristics.
17
+ - [Changed] `I18nJS.listen` now accepts a directories list to watch.
18
+ - [Changed] `I18nJS.listen` now accepts
19
+ [listen](https://rubygems.org/gems/listen) options via `:options`.
20
+
14
21
  ## Jul 29, 2022
15
22
 
16
23
  - 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/i18nyml` 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
 
@@ -131,13 +139,15 @@ check:
131
139
  - en.mailer.login.body
132
140
  ```
133
141
 
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.*`.
142
+ > **Note**:
143
+ >
144
+ > In order to avoid mistakenly ignoring keys, this configuration option only
145
+ > accepts the full translation scope, rather than accepting a pattern like
146
+ > `pt.ignored.scope.*`.
137
147
 
138
148
  ## Automatically export translations
139
149
 
140
- ### Using watchman
150
+ ### Using [watchman](https://facebook.github.io/watchman/)
141
151
 
142
152
  Create a script at `bin/i18n-watch`.
143
153
 
@@ -182,11 +192,11 @@ line to your Procfile:
182
192
  i18n: ./bin/i18n-watch
183
193
  ```
184
194
 
185
- ### Using guard
195
+ ### Using [guard](https://rubygems.org/gems/guard)
186
196
 
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:
197
+ Install [guard](https://rubygems.org/gems/guard) and
198
+ [guard-compat](https://rubygems.org/gems/guard-compat). Then create a Guardfile
199
+ with the following configuration:
190
200
 
191
201
  ```ruby
192
202
  guard(:"i18n-js",
@@ -204,7 +214,7 @@ accordingly.
204
214
 
205
215
  Now you can run `guard start -i`.
206
216
 
207
- ### Using listen
217
+ ### Using [listen](https://rubygems.org/gems/listen)
208
218
 
209
219
  Create a file under `config/initializers/i18n.rb` with the following content:
210
220
 
@@ -216,8 +226,21 @@ end
216
226
  ```
217
227
 
218
228
  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")`.
229
+ `config/locales`. You can customize these options:
230
+
231
+ - `config_file` - i18n-js configuration file
232
+ - `locales_dir` - one or multiple directories to watch for locales changes
233
+ - `options` - passed directly to [listen](https://github.com/guard/listen/#options)
234
+
235
+ Example:
236
+
237
+ ```ruby
238
+ I18nJS.listen(
239
+ config_file: "config/i18n.yml",
240
+ locales_dir: ["config/locales", "app/views"],
241
+ options: {only: %r{.yml$}
242
+ )
243
+ ```
221
244
 
222
245
  ### Integrating with your frontend
223
246
 
@@ -227,6 +250,13 @@ that loads all the exported translation.
227
250
 
228
251
  ### FAQ
229
252
 
253
+ #### I'm running v3. Is there a migration plan?
254
+
255
+ [There's a document](https://github.com/fnando/i18n-js/tree/main/MIGRATING_FROM_V3_TO_V4.md)
256
+ outlining some of the things you need to do to migrate from v3 to v4. It may not
257
+ be as complete as we'd like it to be, so let's know if you face any issues
258
+ during the migration is not outline is that document.
259
+
230
260
  #### How can I export translations without having a database around?
231
261
 
232
262
  Some people may have a build process using something like Docker that don't
@@ -246,9 +276,11 @@ require "action_view/railtie"
246
276
  I18n.load_path += Dir["./config/locales/**/*.yml"]
247
277
  ```
248
278
 
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.
279
+ > **Note**:
280
+ >
281
+ > You may not need to load ActiveSupport and ActionView lines, or even may need
282
+ > to add additional requires for other libs. With this approach you have full
283
+ > control on what's going to be loaded.
252
284
 
253
285
  ## Maintainer
254
286
 
data/i18n-js.gemspec CHANGED
@@ -28,7 +28,7 @@ Gem::Specification.new do |spec|
28
28
  spec.files = Dir.chdir(File.expand_path(__dir__)) do
29
29
  `git ls-files -z`
30
30
  .split("\x0")
31
- .reject {|f| f.match(%r{^(test|spec|features)/}) }
31
+ .reject {|f| f.match(%r{^(test|spec|features|images)/}) }
32
32
  end
33
33
 
34
34
  spec.bindir = "exe"
data/lib/guard/i18n-js.rb CHANGED
@@ -53,13 +53,30 @@ module Guard
53
53
  info("Changes detected: #{changes.join(', ')}") if changes
54
54
 
55
55
  @current_thread = Thread.new do
56
- require @require_file
57
- ::I18nJS.call(config_file: @config_file)
56
+ capture do
57
+ system "i18n",
58
+ "export",
59
+ "--config",
60
+ config_file.to_s,
61
+ "--require",
62
+ require_file.to_s,
63
+ "--quiet"
64
+ end
58
65
  end
59
66
 
60
67
  current_thread.join
61
68
  end
62
69
 
70
+ def capture
71
+ original = $stdout
72
+ $stdout = StringIO.new
73
+ yield
74
+ rescue StandardError
75
+ # noop
76
+ ensure
77
+ $stdout = original
78
+ end
79
+
63
80
  def validate_file(key, file)
64
81
  return true if file && File.file?(file)
65
82
 
@@ -68,11 +85,11 @@ module Guard
68
85
  end
69
86
 
70
87
  def error(message)
71
- ::Guard::UI.error "[guard-i18n-js] #{message}"
88
+ ::Guard::UI.error "[i18n-js] #{message}"
72
89
  end
73
90
 
74
91
  def info(message)
75
- ::Guard::UI.info "[guard-i18n-js] #{message}"
92
+ ::Guard::UI.info "[i18n-js] #{message}"
76
93
  end
77
94
  end
78
95
  end
@@ -27,6 +27,14 @@ module I18nJS
27
27
  options[:require_file] = require_file
28
28
  end
29
29
 
30
+ opts.on(
31
+ "-q",
32
+ "--quiet",
33
+ "A Ruby file that must be loaded"
34
+ ) do |quiet|
35
+ options[:quiet] = quiet
36
+ end
37
+
30
38
  opts.on("-h", "--help", "Prints this help") do
31
39
  ui.exit_with opts.to_s
32
40
  end
@@ -39,11 +47,11 @@ module I18nJS
39
47
  ui.fail_with("=> ERROR: you need to specify the config file")
40
48
  end
41
49
 
42
- ui.stdout_print("=> Config file:", options[:config_file].inspect)
50
+ log("=> Config file:", options[:config_file].inspect)
43
51
  config_file = File.expand_path(options[:config_file])
44
52
 
45
53
  if options[:require_file]
46
- ui.stdout_print("=> Require file:", options[:require_file].inspect)
54
+ log("=> Require file:", options[:require_file].inspect)
47
55
  require_file = File.expand_path(options[:require_file])
48
56
  end
49
57
 
@@ -66,7 +74,13 @@ module I18nJS
66
74
  I18nJS.call(config_file: config_file)
67
75
  end
68
76
 
69
- ui.stdout_print("=> Done in #{time.round(2)}s")
77
+ log("=> Done in #{time.round(2)}s")
78
+ end
79
+
80
+ private def log(*args)
81
+ return if options[:quiet]
82
+
83
+ ui.stdout_print(*args)
70
84
  end
71
85
 
72
86
  private def set_defaults!
@@ -7,7 +7,8 @@ module I18nJS
7
7
 
8
8
  def self.listen(
9
9
  config_file: Rails.root.join("config/i18n.yml"),
10
- locales_dir: Rails.root.join("config/locales")
10
+ locales_dir: Rails.root.join("config/locales"),
11
+ options: {}
11
12
  )
12
13
  return unless Rails.env.development?
13
14
  return if started
@@ -18,12 +19,14 @@ module I18nJS
18
19
 
19
20
  self.started = true
20
21
 
22
+ locales_dirs = Array(locales_dir)
23
+
21
24
  relative_paths =
22
- [config_file, locales_dir].map {|path| relative_path(path) }
25
+ [config_file, *locales_dirs].map {|path| relative_path(path) }
23
26
 
24
27
  debug("Watching #{relative_paths.inspect}")
25
28
 
26
- listener(config_file, locales_dir.to_s).start
29
+ listener(config_file, locales_dirs.map(&:to_s), options).start
27
30
  I18nJS.call(config_file: config_file)
28
31
  end
29
32
 
@@ -43,12 +46,12 @@ module I18nJS
43
46
  @logger ||= ActiveSupport::TaggedLogging.new(Rails.logger)
44
47
  end
45
48
 
46
- def self.listener(config_file, locales_dir)
47
- paths = [File.dirname(config_file), locales_dir]
49
+ def self.listener(config_file, locales_dirs, options)
50
+ paths = [File.dirname(config_file), *locales_dirs]
48
51
 
49
- Listen.to(*paths) do |changed, added, removed|
52
+ Listen.to(*paths, options) do |changed, added, removed|
50
53
  changes = compute_changes(
51
- [config_file, locales_dir],
54
+ [config_file, *locales_dirs],
52
55
  changed,
53
56
  added,
54
57
  removed
@@ -58,11 +61,22 @@ module I18nJS
58
61
 
59
62
  debug(changes.map {|key, value| "#{key}=#{value.inspect}" }.join(", "))
60
63
 
61
- ::I18n.backend.reload!
62
- I18nJS.call(config_file: config_file)
64
+ capture do
65
+ system "i18n", "export", "--config", config_file.to_s
66
+ end
63
67
  end
64
68
  end
65
69
 
70
+ def self.capture
71
+ original = $stdout
72
+ $stdout = StringIO.new
73
+ yield
74
+ rescue StandardError
75
+ # noop
76
+ ensure
77
+ $stdout = original
78
+ end
79
+
66
80
  def self.compute_changes(paths, changed, added, removed)
67
81
  paths = paths.map {|path| relative_path(path) }
68
82
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module I18nJS
4
- VERSION = "4.0.0"
4
+ VERSION = "4.0.1"
5
5
  end
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.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nando Vieira
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-07-29 00:00:00.000000000 Z
11
+ date: 2022-08-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: glob
@@ -173,12 +173,11 @@ files:
173
173
  - CONTRIBUTING.md
174
174
  - Gemfile
175
175
  - LICENSE.md
176
+ - MIGRATING_FROM_V3_TO_V4.md
176
177
  - README.md
177
178
  - Rakefile
178
179
  - exe/i18n
179
180
  - i18n-js.gemspec
180
- - i18njs.png
181
- - images/i18njs-check.gif
182
181
  - lib/guard/i18n-js.rb
183
182
  - lib/guard/i18n-js/templates/Guardfile
184
183
  - lib/guard/i18n-js/version.rb
@@ -200,10 +199,10 @@ metadata:
200
199
  rubygems_mfa_required: 'true'
201
200
  homepage_uri: https://github.com/fnando/i18n-js
202
201
  bug_tracker_uri: https://github.com/fnando/i18n-js/issues
203
- source_code_uri: https://github.com/fnando/i18n-js/tree/v4.0.0
204
- changelog_uri: https://github.com/fnando/i18n-js/tree/v4.0.0/CHANGELOG.md
205
- documentation_uri: https://github.com/fnando/i18n-js/tree/v4.0.0/README.md
206
- license_uri: https://github.com/fnando/i18n-js/tree/v4.0.0/LICENSE.md
202
+ source_code_uri: https://github.com/fnando/i18n-js/tree/v4.0.1
203
+ changelog_uri: https://github.com/fnando/i18n-js/tree/v4.0.1/CHANGELOG.md
204
+ documentation_uri: https://github.com/fnando/i18n-js/tree/v4.0.1/README.md
205
+ license_uri: https://github.com/fnando/i18n-js/tree/v4.0.1/LICENSE.md
207
206
  post_install_message:
208
207
  rdoc_options: []
209
208
  require_paths:
data/i18njs.png DELETED
Binary file
Binary file