i18n-js 3.9.2 → 4.2.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/CODEOWNERS +4 -0
- data/.github/FUNDING.yml +1 -1
- data/.github/ISSUE_TEMPLATE/bug_report.md +41 -0
- data/.github/ISSUE_TEMPLATE/config.yml +5 -0
- data/.github/ISSUE_TEMPLATE/feature_request.md +23 -0
- data/.github/PULL_REQUEST_TEMPLATE.md +38 -0
- data/.github/dependabot.yml +15 -0
- data/.github/workflows/ruby-tests.yml +73 -0
- data/.gitignore +13 -7
- data/.rubocop.yml +19 -0
- data/CHANGELOG.md +45 -561
- data/CODE_OF_CONDUCT.md +74 -0
- data/CONTRIBUTING.md +79 -0
- data/Gemfile +3 -0
- data/LICENSE.md +20 -0
- data/MIGRATING_FROM_V3_TO_V4.md +191 -0
- data/README.md +425 -951
- data/Rakefile +10 -20
- data/bin/release +81 -0
- data/exe/i18n +5 -0
- data/i18n-js.gemspec +51 -29
- data/lib/guard/i18n-js/templates/Guardfile +10 -0
- data/lib/guard/i18n-js/version.rb +13 -0
- data/lib/guard/i18n-js.rb +95 -0
- data/lib/i18n-js/clean_hash.rb +13 -0
- data/lib/i18n-js/cli/check_command.rb +17 -0
- data/lib/i18n-js/cli/command.rb +79 -0
- data/lib/i18n-js/cli/export_command.rb +95 -0
- data/lib/i18n-js/cli/init_command.rb +52 -0
- 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/ui.rb +64 -0
- data/lib/i18n-js/cli/version_command.rb +18 -0
- data/lib/i18n-js/cli.rb +66 -0
- data/lib/i18n-js/embed_fallback_translations_plugin.rb +70 -0
- data/lib/i18n-js/export_files_plugin.rb +103 -0
- data/lib/i18n-js/lint.js +150645 -0
- data/lib/i18n-js/lint.ts +196 -0
- data/lib/i18n-js/listen.rb +96 -0
- data/lib/i18n-js/plugin.rb +103 -0
- data/lib/i18n-js/schema.rb +216 -0
- data/lib/i18n-js/sort_hash.rb +12 -0
- data/lib/i18n-js/version.rb +5 -0
- data/lib/i18n-js.rb +107 -1
- data/package.json +5 -20
- metadata +152 -198
- data/.editorconfig +0 -24
- data/.github/workflows/tests.yaml +0 -106
- data/.npmignore +0 -27
- data/Appraisals +0 -52
- data/app/assets/javascripts/i18n/filtered.js.erb +0 -23
- data/app/assets/javascripts/i18n/shims.js +0 -240
- data/app/assets/javascripts/i18n/translations.js +0 -3
- data/app/assets/javascripts/i18n.js +0 -1095
- data/gemfiles/i18n_0_6.gemfile +0 -7
- data/gemfiles/i18n_0_7.gemfile +0 -7
- data/gemfiles/i18n_0_8.gemfile +0 -7
- data/gemfiles/i18n_0_9.gemfile +0 -7
- data/gemfiles/i18n_1_0.gemfile +0 -7
- data/gemfiles/i18n_1_1.gemfile +0 -7
- data/gemfiles/i18n_1_10.gemfile +0 -7
- data/gemfiles/i18n_1_2.gemfile +0 -7
- data/gemfiles/i18n_1_3.gemfile +0 -7
- data/gemfiles/i18n_1_4.gemfile +0 -7
- data/gemfiles/i18n_1_5.gemfile +0 -7
- data/gemfiles/i18n_1_6.gemfile +0 -7
- data/gemfiles/i18n_1_7.gemfile +0 -7
- data/gemfiles/i18n_1_8.gemfile +0 -7
- data/gemfiles/i18n_1_9.gemfile +0 -7
- data/i18njs.png +0 -0
- data/lib/i18n/js/dependencies.rb +0 -67
- data/lib/i18n/js/engine.rb +0 -87
- data/lib/i18n/js/fallback_locales.rb +0 -70
- data/lib/i18n/js/formatters/base.rb +0 -25
- data/lib/i18n/js/formatters/js.rb +0 -39
- data/lib/i18n/js/formatters/json.rb +0 -13
- data/lib/i18n/js/middleware.rb +0 -82
- data/lib/i18n/js/private/config_store.rb +0 -31
- data/lib/i18n/js/private/hash_with_symbol_keys.rb +0 -36
- data/lib/i18n/js/segment.rb +0 -81
- data/lib/i18n/js/utils.rb +0 -91
- data/lib/i18n/js/version.rb +0 -7
- data/lib/i18n/js.rb +0 -274
- data/lib/rails/generators/i18n/js/config/config_generator.rb +0 -19
- data/lib/rails/generators/i18n/js/config/templates/i18n-js.yml +0 -27
- data/lib/tasks/export.rake +0 -8
- data/spec/fixtures/custom_path.yml +0 -5
- data/spec/fixtures/default.yml +0 -5
- data/spec/fixtures/erb.yml +0 -5
- data/spec/fixtures/except_condition.yml +0 -7
- data/spec/fixtures/js_available_locales_custom.yml +0 -1
- data/spec/fixtures/js_export_dir_custom.yml +0 -7
- data/spec/fixtures/js_export_dir_none.yml +0 -6
- data/spec/fixtures/js_extend_parent.yml +0 -6
- data/spec/fixtures/js_extend_segment.yml +0 -6
- data/spec/fixtures/js_file_per_locale.yml +0 -7
- data/spec/fixtures/js_file_per_locale_with_fallbacks_as_default_locale_symbol.yml +0 -4
- data/spec/fixtures/js_file_per_locale_with_fallbacks_as_hash.yml +0 -6
- data/spec/fixtures/js_file_per_locale_with_fallbacks_as_locale.yml +0 -4
- data/spec/fixtures/js_file_per_locale_with_fallbacks_as_locale_without_fallback_translations.yml +0 -4
- data/spec/fixtures/js_file_per_locale_with_fallbacks_enabled.yml +0 -4
- data/spec/fixtures/js_file_per_locale_without_fallbacks.yml +0 -4
- data/spec/fixtures/js_file_with_namespace_prefix_and_pretty_print.yml +0 -9
- data/spec/fixtures/js_sort_translation_keys_false.yml +0 -6
- data/spec/fixtures/js_sort_translation_keys_true.yml +0 -6
- data/spec/fixtures/json_only.yml +0 -18
- data/spec/fixtures/locales.yml +0 -133
- data/spec/fixtures/merge_plurals.yml +0 -6
- data/spec/fixtures/merge_plurals_with_no_overrides.yml +0 -4
- data/spec/fixtures/merge_plurals_with_partial_overrides.yml +0 -4
- data/spec/fixtures/millions.yml +0 -4
- data/spec/fixtures/multiple_conditions.yml +0 -7
- data/spec/fixtures/multiple_conditions_per_locale.yml +0 -7
- data/spec/fixtures/multiple_files.yml +0 -7
- data/spec/fixtures/no_config.yml +0 -2
- data/spec/fixtures/no_scope.yml +0 -4
- data/spec/fixtures/simple_scope.yml +0 -5
- data/spec/js/currency.spec.js +0 -62
- data/spec/js/current_locale.spec.js +0 -19
- data/spec/js/dates.spec.js +0 -276
- data/spec/js/defaults.spec.js +0 -31
- data/spec/js/extend.spec.js +0 -110
- data/spec/js/interpolation.spec.js +0 -124
- data/spec/js/jasmine/MIT.LICENSE +0 -20
- data/spec/js/jasmine/jasmine-html.js +0 -190
- data/spec/js/jasmine/jasmine.css +0 -166
- data/spec/js/jasmine/jasmine.js +0 -2476
- data/spec/js/jasmine/jasmine_favicon.png +0 -0
- data/spec/js/json_parsable.spec.js +0 -14
- data/spec/js/locales.spec.js +0 -31
- data/spec/js/localization.spec.js +0 -78
- data/spec/js/numbers.spec.js +0 -174
- data/spec/js/placeholder.spec.js +0 -24
- data/spec/js/pluralization.spec.js +0 -228
- data/spec/js/prepare_options.spec.js +0 -41
- data/spec/js/require.js +0 -2083
- data/spec/js/specs.html +0 -49
- data/spec/js/specs_requirejs.html +0 -72
- data/spec/js/translate.spec.js +0 -304
- data/spec/js/translations.js +0 -188
- data/spec/js/utility_functions.spec.js +0 -20
- data/spec/ruby/i18n/js/fallback_locales_spec.rb +0 -84
- data/spec/ruby/i18n/js/segment_spec.rb +0 -286
- data/spec/ruby/i18n/js/utils_spec.rb +0 -138
- data/spec/ruby/i18n/js_spec.rb +0 -797
- data/spec/spec_helper.rb +0 -80
- data/yarn.lock +0 -138
data/README.md
CHANGED
@@ -1,1099 +1,573 @@
|
|
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">
|
6
|
-
|
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.
|
7
9
|
</p>
|
8
10
|
|
9
11
|
<p align="center">
|
10
|
-
<
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
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/latest">companion JavaScript package</a>.
|
17
|
+
</small>
|
16
18
|
</p>
|
17
19
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
-
|
23
|
-
|
24
|
-
- Number localization
|
25
|
-
- Locale fallback
|
26
|
-
- Asset pipeline support
|
27
|
-
- Lots more! :)
|
28
|
-
|
29
|
-
## Version Notice
|
30
|
-
|
31
|
-
The `main` branch (including this README) is for latest `3.0.0` instead of
|
32
|
-
`2.x`.
|
33
|
-
|
34
|
-
## Usage
|
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>
|
35
26
|
|
36
|
-
|
27
|
+
## Installation
|
37
28
|
|
38
|
-
|
29
|
+
```bash
|
30
|
+
gem install i18n-js
|
31
|
+
```
|
39
32
|
|
40
|
-
|
33
|
+
Or add the following line to your project's Gemfile:
|
41
34
|
|
42
35
|
```ruby
|
43
36
|
gem "i18n-js"
|
44
37
|
```
|
45
38
|
|
46
|
-
|
47
|
-
|
48
|
-
If you're using `webpacker`, you may need to add the dependencies to your client
|
49
|
-
with:
|
50
|
-
|
51
|
-
```
|
52
|
-
yarn add i18n-js
|
53
|
-
# or, if you're using npm,
|
54
|
-
npm install i18n-js
|
55
|
-
```
|
56
|
-
|
57
|
-
For more details, see:
|
58
|
-
- [this gist](https://gist.github.com/bazzel/ecdff4718962e57c2d5569cf01d332fe)
|
59
|
-
- https://github.com/fnando/i18n-js/issues/597
|
60
|
-
|
61
|
-
#### Rails app with [Asset Pipeline](https://guides.rubyonrails.org/asset_pipeline.html)
|
62
|
-
|
63
|
-
If you're using the
|
64
|
-
[asset pipeline](https://guides.rubyonrails.org/asset_pipeline.html), then you
|
65
|
-
must add the following line to your `app/assets/javascripts/application.js`.
|
66
|
-
|
67
|
-
```javascript
|
68
|
-
//
|
69
|
-
// This is optional (in case you have `I18n is not defined` error)
|
70
|
-
// If you want to put this line, you must put it BEFORE `i18n/translations`
|
71
|
-
//= require i18n
|
72
|
-
// Some people even need to add the extension to make it work, see https://github.com/fnando/i18n-js/issues/283
|
73
|
-
//= require i18n.js
|
74
|
-
//
|
75
|
-
// This is a must
|
76
|
-
//= require i18n/translations
|
77
|
-
```
|
78
|
-
|
79
|
-
#### Rails app without [Asset Pipeline](https://guides.rubyonrails.org/asset_pipeline.html)
|
80
|
-
|
81
|
-
First, put this in your `application.html` (layout file). Then get the JS files
|
82
|
-
following the instructions below.
|
83
|
-
|
84
|
-
```erb
|
85
|
-
<%# This is just an example, you can put `i18n.js` and `translations.js` anywhere you like %>
|
86
|
-
<%# Unlike the Asset Pipeline example, you need to require both **in order** %>
|
87
|
-
<%= javascript_include_tag "i18n" %>
|
88
|
-
<%= javascript_include_tag "translations", skip_pipeline: true %>
|
89
|
-
```
|
90
|
-
|
91
|
-
**There are two ways to get `translations.js` (For Rails app without Asset
|
92
|
-
Pipeline).**
|
93
|
-
|
94
|
-
1. This `translations.js` file can be automatically generated by the
|
95
|
-
`I18n::JS::Middleware`. Just add `config.middleware.use I18n::JS::Middleware`
|
96
|
-
to your `config/application.rb` file.
|
97
|
-
2. If you can't or prefer not to generate this file, you can move the middleware
|
98
|
-
line to your `config/environments/development.rb` file and run
|
99
|
-
`rake i18n:js:export` before deploying. This will export all translation
|
100
|
-
files, including the custom scopes you may have defined on
|
101
|
-
`config/i18n-js.yml`. If `I18n.available_locales` is set (e.g. in your Rails
|
102
|
-
`config/application.rb` file) then only the specified locales will be
|
103
|
-
exported. Current version of `i18n.js` will also be exported to avoid version
|
104
|
-
mismatching by downloading.
|
105
|
-
|
106
|
-
#### Export Configuration (For translations)
|
107
|
-
|
108
|
-
Exported translation files generated by `I18n::JS::Middleware` or
|
109
|
-
`rake i18n:js:export` can be customized with config file `config/i18n-js.yml`
|
110
|
-
(use `rails generate i18n:js:config` to create it). You can even get more files
|
111
|
-
generated to different folders and with different translations to best suit your
|
112
|
-
needs. The config file also affects developers using Asset Pipeline to require
|
113
|
-
translations. Except the option `file`, since all translations are required by
|
114
|
-
adding `//= require i18n/translations`.
|
115
|
-
|
116
|
-
Examples:
|
117
|
-
|
118
|
-
```yaml
|
119
|
-
translations:
|
120
|
-
- file: "public/javascripts/path-to-your-messages-file.js"
|
121
|
-
only: "*.date.formats"
|
122
|
-
- file: "public/javascripts/path-to-your-second-file.js"
|
123
|
-
only: ["*.activerecord", "*.admin.*.title"]
|
124
|
-
```
|
125
|
-
|
126
|
-
If `only` is omitted all the translations will be saved. Also, make sure you add
|
127
|
-
that initial `*`; it specifies that all languages will be exported. If you want
|
128
|
-
to export only one language, you can do something like this:
|
129
|
-
|
130
|
-
```yaml
|
131
|
-
translations:
|
132
|
-
- file: "public/javascripts/en.js"
|
133
|
-
only: "en.*"
|
134
|
-
- file: "public/javascripts/pt-BR.js"
|
135
|
-
only: "pt-BR.*"
|
136
|
-
```
|
137
|
-
|
138
|
-
Optionally, you can auto generate a translation file per available locale if you
|
139
|
-
specify the `%{locale}` placeholder.
|
140
|
-
|
141
|
-
```yaml
|
142
|
-
translations:
|
143
|
-
- file: "public/javascripts/i18n/%{locale}.js"
|
144
|
-
only: "*"
|
145
|
-
- file: "public/javascripts/frontend/i18n/%{locale}.js"
|
146
|
-
only: ["*.frontend", "*.users.*"]
|
147
|
-
```
|
148
|
-
|
149
|
-
You can also include ERB in your config file.
|
150
|
-
|
151
|
-
```yaml
|
152
|
-
translations:
|
153
|
-
<% Widgets.each do |widget| %>
|
154
|
-
- file: <%= "'#{widget.file}'" %>
|
155
|
-
only: <%= "'#{widget.only}'" %>
|
156
|
-
<% end %>
|
157
|
-
```
|
158
|
-
|
159
|
-
You are able to exclude certain phrases or whole groups of phrases by specifying
|
160
|
-
the YAML key(s) in the `except` configuration option. The outputted JS
|
161
|
-
translations file (exported or generated by the middleware) will omit any keys
|
162
|
-
listed in `except` configuration param:
|
163
|
-
|
164
|
-
```yaml
|
165
|
-
translations:
|
166
|
-
- except: ["*.active_admin", "*.ransack", "*.activerecord.errors"]
|
167
|
-
```
|
168
|
-
|
169
|
-
#### Export Configuration (For other things)
|
170
|
-
|
171
|
-
- `I18n::JS.config_file_path` Expected Type: `String` Default:
|
172
|
-
`config/i18n-js.yml` Behaviour: Try to read the config file from that location
|
173
|
-
|
174
|
-
- `I18n::JS.export_i18n_js_dir_path` Expected Type: `String` Default:
|
175
|
-
`public/javascripts` Behaviour:
|
176
|
-
|
177
|
-
- Any `String`: considered as a relative path for a folder to `Rails.root` and
|
178
|
-
export `i18n.js` to that folder for `rake i18n:js:export`
|
179
|
-
- Any non-`String` (`nil`, `false`, `:none`, etc): Disable `i18n.js` exporting
|
180
|
-
|
181
|
-
- `I18n::JS.sort_translation_keys` Expected Type: `Boolean` Default: `true`
|
182
|
-
Behaviour:
|
183
|
-
|
184
|
-
- Sets whether or not to deep sort all translation keys in order to generate
|
185
|
-
identical output for the same translations
|
186
|
-
- Set to true to ensure identical asset fingerprints for the asset pipeline
|
187
|
-
|
188
|
-
- You may also set `export_i18n_js` and `sort_translation_keys` in your config
|
189
|
-
file, e.g.:
|
190
|
-
|
191
|
-
```yaml
|
192
|
-
export_i18n_js: false
|
193
|
-
# OR
|
194
|
-
export_i18n_js: "my/path"
|
195
|
-
|
196
|
-
sort_translation_keys: false
|
197
|
-
|
198
|
-
translations:
|
199
|
-
- ...
|
200
|
-
```
|
201
|
-
|
202
|
-
To find more examples on how to use the configuration file please refer to the
|
203
|
-
tests.
|
204
|
-
|
205
|
-
#### Fallbacks
|
206
|
-
|
207
|
-
If you specify the `fallbacks` option, you will be able to fill missing
|
208
|
-
translations with those inside fallback locale(s). Default value is `true`.
|
209
|
-
|
210
|
-
Examples:
|
39
|
+
## Usage
|
211
40
|
|
212
|
-
|
213
|
-
fallbacks: true
|
41
|
+
About patterns:
|
214
42
|
|
215
|
-
|
216
|
-
-
|
217
|
-
|
218
|
-
|
43
|
+
- Patterns can use `*` as a wildcard and can appear more than once.
|
44
|
+
- `*` will include everything
|
45
|
+
- `*.messages.*`
|
46
|
+
- Patterns starting with `!` are excluded.
|
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.
|
219
51
|
|
220
|
-
|
221
|
-
|
222
|
-
|
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.
|
223
56
|
|
224
|
-
|
225
|
-
fallbacks: :de
|
57
|
+
The config file:
|
226
58
|
|
59
|
+
```yml
|
60
|
+
---
|
227
61
|
translations:
|
228
|
-
- file:
|
229
|
-
|
230
|
-
|
62
|
+
- file: app/frontend/locales/en.json
|
63
|
+
patterns:
|
64
|
+
- "*"
|
65
|
+
- "!*.activerecord"
|
66
|
+
- "!*.errors"
|
67
|
+
- "!*.number.nth"
|
231
68
|
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
fallbacks:
|
236
|
-
fr: ["de", "en"]
|
237
|
-
de: "en"
|
238
|
-
|
239
|
-
translations:
|
240
|
-
- file: "public/javascripts/i18n/%{locale}.js"
|
241
|
-
only: "*"
|
69
|
+
- file: app/frontend/locales/:locale.:digest.json
|
70
|
+
patterns:
|
71
|
+
- "*"
|
242
72
|
```
|
243
73
|
|
244
|
-
|
245
|
-
`I18n.default_locale` will be used.
|
246
|
-
|
247
|
-
```yaml
|
248
|
-
fallbacks: :default_locale
|
249
|
-
|
250
|
-
translations:
|
251
|
-
- file: "public/javascripts/i18n/%{locale}.js"
|
252
|
-
only: "*"
|
253
|
-
```
|
74
|
+
The output path can use the following placeholders:
|
254
75
|
|
255
|
-
|
256
|
-
|
76
|
+
- `:locale`: the language that's being exported.
|
77
|
+
- `:digest`: the MD5 hex digest of the exported file.
|
257
78
|
|
258
|
-
|
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.
|
259
81
|
|
260
|
-
```
|
261
|
-
|
82
|
+
```yml
|
83
|
+
---
|
84
|
+
<% group = "{en,pt}" %>
|
262
85
|
|
263
86
|
translations:
|
264
|
-
- file:
|
265
|
-
|
87
|
+
- file: app/frontend/translations.json
|
88
|
+
patterns:
|
89
|
+
- "<%= group %>.*"
|
90
|
+
- "!<%= group %>.activerecord"
|
91
|
+
- "!<%= group %>.errors"
|
92
|
+
- "!<%= group %>.number.nth"
|
266
93
|
```
|
267
94
|
|
268
|
-
|
269
|
-
|
270
|
-
To find more examples on how to use the configuration file please refer to the
|
271
|
-
tests.
|
272
|
-
|
273
|
-
#### Available locales
|
274
|
-
|
275
|
-
By specifying option `js_available_locales` with a list of locales, this list
|
276
|
-
would be used instead of default `I18n.available_locales` to generate translations.
|
95
|
+
The Ruby API:
|
277
96
|
|
278
|
-
|
97
|
+
```ruby
|
98
|
+
require "i18n-js"
|
279
99
|
|
280
|
-
|
281
|
-
|
100
|
+
I18nJS.call(config_file: "config/i18n.yml")
|
101
|
+
I18nJS.call(config: config)
|
282
102
|
```
|
283
103
|
|
284
|
-
|
104
|
+
The CLI API:
|
285
105
|
|
286
|
-
|
287
|
-
|
288
|
-
|
106
|
+
```console
|
107
|
+
$ i18n --help
|
108
|
+
Usage: i18n COMMAND FLAGS
|
289
109
|
|
290
|
-
|
291
|
-
translations:
|
292
|
-
- file: "public/javascripts/i18n/translations.js"
|
293
|
-
namespace: "MyNamespace"
|
294
|
-
```
|
110
|
+
Commands:
|
295
111
|
|
296
|
-
|
112
|
+
- init: Initialize a project
|
113
|
+
- export: Export translations as JSON files
|
114
|
+
- version: Show package version
|
115
|
+
- plugins: List plugins that will be activated
|
116
|
+
- lint:translations: Check for missing translations
|
117
|
+
- lint:scripts: Lint files using TypeScript
|
297
118
|
|
119
|
+
Run `i18n COMMAND --help` for more information on specific commands.
|
298
120
|
```
|
299
|
-
MyNamespace.translations || (MyNamespace.translations = {});
|
300
|
-
MyNamespace.translations["en"] = { ... }
|
301
|
-
```
|
302
|
-
|
303
|
-
### Adding prefix & suffix to the translations file(s)
|
304
|
-
|
305
|
-
Setting the `prefix: "import I18n from 'i18n-js';\n"` option will add the line
|
306
|
-
at the beginning of the resultant translation file. This can be useful to use
|
307
|
-
this gem with the [i18n-js](https://www.npmjs.com/package/i18n-js) npm package,
|
308
|
-
which is quite useful to use it with webpack. The user should provide the
|
309
|
-
semi-colon and the newline character if needed.
|
310
121
|
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
translations:
|
315
|
-
- file: "public/javascripts/i18n/translations.js"
|
316
|
-
prefix: "import I18n from 'i18n-js';\n"
|
317
|
-
```
|
122
|
+
By default, `i18n` will use `config/i18n.yml` and `config/environment.rb` as the
|
123
|
+
configuration files. If you don't have these files, then you'll need to specify
|
124
|
+
both `--config` and `--require`.
|
318
125
|
|
319
|
-
|
126
|
+
### Plugins
|
320
127
|
|
321
|
-
|
322
|
-
import I18n from 'i18n-js';
|
323
|
-
I18n.translations || (I18n.translations = {});
|
324
|
-
```
|
128
|
+
#### Built-in plugins:
|
325
129
|
|
326
|
-
`
|
327
|
-
It's similar to `prefix` so won't explain it in details.
|
130
|
+
##### `embed_fallback_translations`:
|
328
131
|
|
329
|
-
|
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.
|
330
135
|
|
331
|
-
|
332
|
-
your output file (default: false)
|
136
|
+
To use it, add the following to your configuration file:
|
333
137
|
|
334
138
|
```yaml
|
335
|
-
|
336
|
-
|
337
|
-
pretty_print: true
|
139
|
+
embed_fallback_translations:
|
140
|
+
enabled: true
|
338
141
|
```
|
339
142
|
|
340
|
-
|
143
|
+
##### `export_files`:
|
341
144
|
|
342
|
-
By default,
|
343
|
-
|
344
|
-
|
345
|
-
`js_extend` option to false
|
145
|
+
By default, i18n-js will export only JSON files out of your translations. This
|
146
|
+
plugin allows exporting other file formats. To use it, add the following to your
|
147
|
+
configuration file:
|
346
148
|
|
347
149
|
```yaml
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
150
|
+
export_files:
|
151
|
+
enabled: true
|
152
|
+
files:
|
153
|
+
- template: path/to/template.erb
|
154
|
+
output: "%{dir}/%{base_name}.ts"
|
352
155
|
```
|
353
156
|
|
354
|
-
|
355
|
-
|
356
|
-
Just add the `i18n.js` file to your page. You'll have to build the translations
|
357
|
-
object by hand or using your favorite programming language. More info below.
|
157
|
+
You can export multiple files by define more entries.
|
358
158
|
|
359
|
-
|
159
|
+
The output name can use the following placeholders:
|
360
160
|
|
361
|
-
|
362
|
-
|
161
|
+
- `%{dir}`: the directory where the translation file is.
|
162
|
+
- `%{name}`: file name with extension.
|
163
|
+
- `%{base_name}`: file name without extension.
|
164
|
+
- `%{digest}`: MD5 hexdigest from the generated file.
|
363
165
|
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
// Or if you want unreleased version
|
368
|
-
// npm install requires it to be the gzipped tarball, see [npm install](https://www.npmjs.org/doc/cli/npm-install.html)
|
369
|
-
"i18n-js": "https://github.com/fnando/i18n-js/archive/{tag_name_or_branch_name_or_commit_sha}.tar.gz"
|
370
|
-
```
|
371
|
-
|
372
|
-
Run npm install then use via
|
373
|
-
|
374
|
-
```javascript
|
375
|
-
var i18n = require("i18n-js");
|
376
|
-
```
|
377
|
-
|
378
|
-
### Setting up
|
379
|
-
|
380
|
-
You **don't** need to set up a thing. The default settings will work just okay.
|
381
|
-
But if you want to split translations into several files or specify contexts,
|
382
|
-
you can follow the rest of this setting up section.
|
383
|
-
|
384
|
-
Set your locale is easy as
|
385
|
-
|
386
|
-
```javascript
|
387
|
-
I18n.defaultLocale = "pt-BR";
|
388
|
-
I18n.locale = "pt-BR";
|
389
|
-
I18n.currentLocale();
|
390
|
-
// pt-BR
|
391
|
-
```
|
392
|
-
|
393
|
-
**NOTE:** You can now apply your configuration **before I18n** is loaded like
|
394
|
-
this:
|
395
|
-
|
396
|
-
```javascript
|
397
|
-
I18n = {}; // You must define this object in top namespace, which should be `window`
|
398
|
-
I18n.defaultLocale = "pt-BR";
|
399
|
-
I18n.locale = "pt-BR";
|
400
|
-
|
401
|
-
// Load I18n from `i18n.js`, `application.js` or whatever
|
402
|
-
|
403
|
-
I18n.currentLocale();
|
404
|
-
// pt-BR
|
405
|
-
```
|
406
|
-
|
407
|
-
In practice, you'll have something like the following in your
|
408
|
-
`application.html.erb`:
|
166
|
+
The template file must be a valid eRB template. You can execute arbitrary Ruby
|
167
|
+
code, so be careful. An example of how you can generate a file can be seen
|
168
|
+
below:
|
409
169
|
|
410
170
|
```erb
|
411
|
-
|
412
|
-
|
413
|
-
I18n.locale = "<%= I18n.locale %>";
|
414
|
-
</script>
|
415
|
-
```
|
171
|
+
/* eslint-disable */
|
172
|
+
<%= banner %>
|
416
173
|
|
417
|
-
|
174
|
+
import { i18n } from "config/i18n";
|
418
175
|
|
419
|
-
|
420
|
-
I18n.t("some.scoped.translation");
|
421
|
-
// or translate with explicit setting of locale
|
422
|
-
I18n.t("some.scoped.translation", { locale: "fr" });
|
176
|
+
i18n.store(<%= JSON.pretty_generate(translations) %>);
|
423
177
|
```
|
424
178
|
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
I18n.translations["en"] = {
|
430
|
-
greeting: "Hello %{name}",
|
431
|
-
};
|
432
|
-
|
433
|
-
I18n.t("greeting", { name: "John Doe" });
|
434
|
-
```
|
435
|
-
|
436
|
-
You can set default values for missing scopes:
|
437
|
-
|
438
|
-
```javascript
|
439
|
-
// simple translation
|
440
|
-
I18n.t("some.missing.scope", { defaultValue: "A default message" });
|
179
|
+
This template is loading the instance from `config/i18n` and storing the
|
180
|
+
translations that have been loaded. The
|
181
|
+
`banner(comment: "// ", include_time: true)` method is built-in. The generated
|
182
|
+
file will look something like this:
|
441
183
|
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
You can also provide a list of default fallbacks for missing scopes:
|
447
|
-
|
448
|
-
```javascript
|
449
|
-
// As a scope
|
450
|
-
I18n.t("some.missing.scope", { defaults: [{ scope: "some.existing.scope" }] });
|
451
|
-
|
452
|
-
// As a simple translation
|
453
|
-
I18n.t("some.missing.scope", { defaults: [{ message: "Some message" }] });
|
454
|
-
```
|
455
|
-
|
456
|
-
Default values must be provided as an array of hashes where the key is the type
|
457
|
-
of translation desired, a `scope` or a `message`. The translation returned will
|
458
|
-
be either the first scope recognized, or the first message defined.
|
459
|
-
|
460
|
-
The translation will fallback to the `defaultValue` translation if no scope in
|
461
|
-
`defaults` matches and if no default of type `message` is found.
|
462
|
-
|
463
|
-
Translation fallback can be enabled by enabling the `I18n.fallbacks` option:
|
464
|
-
|
465
|
-
```erb
|
466
|
-
<script type="text/javascript">
|
467
|
-
I18n.fallbacks = true;
|
468
|
-
</script>
|
469
|
-
```
|
470
|
-
|
471
|
-
By default missing translations will first be looked for in less specific
|
472
|
-
versions of the requested locale and if that fails by taking them from your
|
473
|
-
`I18n.defaultLocale`.
|
474
|
-
|
475
|
-
```javascript
|
476
|
-
// if I18n.defaultLocale = "en" and translation doesn't exist
|
477
|
-
// for I18n.locale = "de-DE" this key will be taken from "de" locale scope
|
478
|
-
// or, if that also doesn't exist, from "en" locale scope
|
479
|
-
I18n.t("some.missing.scope");
|
480
|
-
```
|
481
|
-
|
482
|
-
Custom fallback rules can also be specified for a particular language. There are
|
483
|
-
three different ways of doing it so:
|
484
|
-
|
485
|
-
```javascript
|
486
|
-
I18n.locales.no = ["nb", "en"];
|
487
|
-
I18n.locales.no = "nb";
|
488
|
-
I18n.locales.no = function (locale) {
|
489
|
-
return ["nb"];
|
490
|
-
};
|
491
|
-
```
|
184
|
+
```typescript
|
185
|
+
/* eslint-disable */
|
186
|
+
// File generated by i18n-js on 2022-12-10 15:37:00 +0000
|
492
187
|
|
493
|
-
|
188
|
+
import { i18n } from "config/i18n";
|
494
189
|
|
495
|
-
|
496
|
-
|
497
|
-
|
498
|
-
|
499
|
-
|
500
|
-
|
501
|
-
|
502
|
-
|
503
|
-
|
190
|
+
i18n.store({
|
191
|
+
en: {
|
192
|
+
"bunny rabbit adventure": "bunny rabbit adventure",
|
193
|
+
"hello sunshine!": "hello sunshine!",
|
194
|
+
"time for bed!": "time for bed!",
|
195
|
+
},
|
196
|
+
es: {
|
197
|
+
"bunny rabbit adventure": "conejito conejo aventura",
|
198
|
+
bye: "adios",
|
199
|
+
"time for bed!": "hora de acostarse!",
|
200
|
+
},
|
201
|
+
pt: {
|
202
|
+
"bunny rabbit adventure": "a aventura da coelhinha",
|
203
|
+
bye: "tchau",
|
204
|
+
"time for bed!": "hora de dormir!",
|
205
|
+
},
|
206
|
+
});
|
504
207
|
```
|
505
208
|
|
506
|
-
|
507
|
-
Camel case becomes lower cased text and underscores are replaced with space
|
209
|
+
#### Plugin API
|
508
210
|
|
509
|
-
|
211
|
+
You can transform the exported translations by adding plugins. A plugin must
|
212
|
+
inherit from `I18nJS::Plugin` and can have 4 class methods (they're all optional
|
213
|
+
and will default to a noop implementation). For real examples, see [lib/i18n-js/embed_fallback_translations_plugin.rb](https://github.com/fnando/i18n-js/blob/main/lib/i18n-js/embed_fallback_translations_plugin.rb) and [lib/i18n-js/export_files_plugin.rb](https://github.com/fnando/i18n-js/blob/main/lib/i18n-js/export_files_plugin.rb)
|
510
214
|
|
511
|
-
|
215
|
+
```ruby
|
216
|
+
# frozen_string_literal: true
|
217
|
+
|
218
|
+
module I18nJS
|
219
|
+
class SamplePlugin < I18nJS::Plugin
|
220
|
+
# This method is responsible for transforming the translations. The
|
221
|
+
# translations you'll receive may be already be filtered by other plugins
|
222
|
+
# and by the default filtering itself. If you need to access the original
|
223
|
+
# translations, use `I18nJS.translations`.
|
224
|
+
def transform(translations:)
|
225
|
+
# transform `translations` here…
|
226
|
+
|
227
|
+
translations
|
228
|
+
end
|
512
229
|
|
513
|
-
|
230
|
+
# In case your plugin accepts configuration, this is where you must validate
|
231
|
+
# the configuration, making sure only valid keys and type is provided.
|
232
|
+
# If the configuration contains invalid data, then you must raise an
|
233
|
+
# exception using something like
|
234
|
+
# `raise I18nJS::Schema::InvalidError, error_message`.
|
235
|
+
#
|
236
|
+
# Notice the validation will only happen when the plugin configuration is
|
237
|
+
# set (i.e. the configuration contains your config key).
|
238
|
+
def validate_schema
|
239
|
+
# validate plugin schema here…
|
240
|
+
end
|
514
241
|
|
515
|
-
|
516
|
-
|
242
|
+
# This method must set up the basic plugin configuration, like adding the
|
243
|
+
# config's root key in case your plugin accepts configuration (defined via
|
244
|
+
# the config file).
|
245
|
+
#
|
246
|
+
# If you don't add this key, the linter will prevent non-default keys from
|
247
|
+
# being added to the configuration file.
|
248
|
+
def setup
|
249
|
+
# If you plugin has configuration, uncomment the line below
|
250
|
+
# I18nJS::Schema.root_keys << config_key
|
251
|
+
end
|
517
252
|
|
518
|
-
|
519
|
-
|
253
|
+
# This method is called whenever `I18nJS.call(**kwargs)` finishes exporting
|
254
|
+
# JSON files based on your configuration.
|
255
|
+
#
|
256
|
+
# You can use it to further process exported files, or generate new files
|
257
|
+
# based on the translations that have been exported.
|
258
|
+
def after_export(files:)
|
259
|
+
# process exported files here…
|
260
|
+
end
|
261
|
+
end
|
262
|
+
end
|
520
263
|
```
|
521
264
|
|
522
|
-
|
265
|
+
The class `I18nJS::Plugin` implements some helper methods that you can use:
|
523
266
|
|
524
|
-
|
525
|
-
|
267
|
+
- `I18nJS::Plugin#config_key`: the configuration key that was inferred out of
|
268
|
+
your plugin's class name.
|
269
|
+
- `I18nJS::Plugin#config`: the plugin configuration.
|
270
|
+
- `I18nJS::Plugin#enabled?`: whether the plugin is enabled or not based on the
|
271
|
+
plugin's configuration.
|
526
272
|
|
527
|
-
|
528
|
-
|
529
|
-
|
273
|
+
To distribute this plugin, you need to create a gem package that matches the
|
274
|
+
pattern `i18n-js/*_plugin.rb`. You can test whether your plugin will be found by
|
275
|
+
installing your gem, opening a iRB session and running
|
276
|
+
`Gem.find_files("i18n-js/*_plugin.rb")`. If your plugin is not listed, then you
|
277
|
+
need to double check your gem load path and see why the file is not being
|
278
|
+
loaded.
|
530
279
|
|
531
|
-
|
280
|
+
### Listing missing translations
|
532
281
|
|
533
|
-
|
282
|
+
To list missing and extraneous translations, you can use
|
283
|
+
`i18n lint:translations`. This command will load your translations similarly to
|
284
|
+
how `i18n export` does, but will output the list of keys that don't have a
|
285
|
+
matching translation against the default locale. Here's an example:
|
534
286
|
|
535
|
-
```
|
536
|
-
|
537
|
-
|
538
|
-
|
287
|
+
```console
|
288
|
+
$ i18n lint:translations
|
289
|
+
=> Config file: "./config/i18n.yml"
|
290
|
+
=> Require file: "./config/environment.rb"
|
291
|
+
=> Check "./config/i18n.yml" for ignored keys.
|
292
|
+
=> en: 232 translations
|
293
|
+
=> pt-BR: 5 missing, 1 extraneous, 1 ignored
|
294
|
+
- pt-BR.actors.github.metrics (missing)
|
295
|
+
- pt-BR.actors.github.metrics_hint (missing)
|
296
|
+
- pt-BR.actors.github.repo_metrics (missing)
|
297
|
+
- pt-BR.actors.github.repository (missing)
|
298
|
+
- pt-BR.actors.github.user_metrics (missing)
|
299
|
+
- pt-BR.github.repository (extraneous)
|
539
300
|
```
|
540
301
|
|
541
|
-
|
542
|
-
|
543
|
-
Default separator of translation key is `.` (dot)
|
544
|
-
Meaning `I18n.t("scope.entry")` would search for translation entry `I18n.translations[locale].scope.entry`
|
545
|
-
Using a different separator can be done either globally or locally.
|
546
|
-
|
547
|
-
Globally: `I18n.defaultSeparator = newSeparator`
|
548
|
-
Locally: `I18n.t("full_sentences|Server Busy. Please retry later", {separator: '|'})`
|
302
|
+
This command will exist with status 1 whenever there are missing translations.
|
303
|
+
This way you can use it as a CI linting.
|
549
304
|
|
550
|
-
|
305
|
+
You can ignore keys by adding a list to the config file:
|
551
306
|
|
552
|
-
|
553
|
-
|
554
|
-
|
555
|
-
|
556
|
-
|
557
|
-
|
558
|
-
|
307
|
+
```yml
|
308
|
+
---
|
309
|
+
translations:
|
310
|
+
- file: app/frontend/locales/en.json
|
311
|
+
patterns:
|
312
|
+
- "*"
|
313
|
+
- "!*.activerecord"
|
314
|
+
- "!*.errors"
|
315
|
+
- "!*.number.nth"
|
316
|
+
|
317
|
+
- file: app/frontend/locales/:locale.:digest.json
|
318
|
+
patterns:
|
319
|
+
- "*"
|
320
|
+
|
321
|
+
lint_translations:
|
322
|
+
ignore:
|
323
|
+
- en.mailer.login.subject
|
324
|
+
- en.mailer.login.body
|
325
|
+
```
|
326
|
+
|
327
|
+
> **Note**:
|
328
|
+
>
|
329
|
+
> In order to avoid mistakenly ignoring keys, this configuration option only
|
330
|
+
> accepts the full translation scope, rather than accepting a pattern like
|
331
|
+
> `pt.ignored.scope.*`.
|
332
|
+
|
333
|
+
### Linting your JavaScript/TypeScript files
|
334
|
+
|
335
|
+
To lint your script files and check for missing translations (which can signal
|
336
|
+
that you're either using wrong scopes or forgot to add the translation), use
|
337
|
+
`i18n lint:scripts`. This command will parse your JavaScript/TypeScript files
|
338
|
+
and extract all scopes being used. This command requires a Node.js runtime. You
|
339
|
+
can either specify one via `--node-path`, or let the plugin infer a binary from
|
340
|
+
your `$PATH`.
|
341
|
+
|
342
|
+
The comparison will be made against the export JSON files, which means it'll
|
343
|
+
consider transformations performed by plugins (e.g. the output files may be
|
344
|
+
affected by `embed_fallback_translations` plugin).
|
345
|
+
|
346
|
+
The translations that will be extract must be called as one of the following
|
347
|
+
ways:
|
348
|
+
|
349
|
+
- `i18n.t(scope, options)`
|
350
|
+
- `i18n.translate(scope, options)`
|
351
|
+
- `t(scope, options)`
|
352
|
+
|
353
|
+
Notice that only literal strings can be used, as in `i18n.t("message")`. If
|
354
|
+
you're using dynamic scoping through variables (e.g.
|
355
|
+
`const scope = "message"; i18n.t(scope)`), they will be skipped.
|
356
|
+
|
357
|
+
```console
|
358
|
+
$ i18n lint:scripts
|
359
|
+
=> Config file: "./config/i18n.yml"
|
360
|
+
=> Require file: "./config/environment.rb"
|
361
|
+
=> Node: "/Users/fnando/.asdf/shims/node"
|
362
|
+
=> Available locales: [:en, :es, :pt]
|
363
|
+
=> Patterns: ["!(node_modules)/**/*.js", "!(node_modules)/**/*.ts", "!(node_modules)/**/*.jsx", "!(node_modules)/**/*.tsx"]
|
364
|
+
=> 9 translations, 11 missing, 4 ignored
|
365
|
+
- test/scripts/lint/file.js:1:1: en.js.missing
|
366
|
+
- test/scripts/lint/file.js:1:1: es.js.missing
|
367
|
+
- test/scripts/lint/file.js:1:1: pt.js.missing
|
368
|
+
- test/scripts/lint/file.js:2:8: en.base.js.missing
|
369
|
+
- test/scripts/lint/file.js:2:8: es.base.js.missing
|
370
|
+
- test/scripts/lint/file.js:2:8: pt.base.js.missing
|
371
|
+
- test/scripts/lint/file.js:4:8: en.js.missing
|
372
|
+
- test/scripts/lint/file.js:4:8: es.js.missing
|
373
|
+
- test/scripts/lint/file.js:4:8: pt.js.missing
|
374
|
+
- test/scripts/lint/file.js:6:1: en.another_ignore_scope
|
375
|
+
- test/scripts/lint/file.js:6:1: es.another_ignore_scope
|
376
|
+
```
|
377
|
+
|
378
|
+
This command will list all locales and their missing translations. Avoid listing
|
379
|
+
a particular translation, you can set `lint.ignore` on your config file.
|
559
380
|
|
560
381
|
```yaml
|
561
|
-
|
562
|
-
|
563
|
-
|
564
|
-
|
565
|
-
|
566
|
-
zero: You have no messages
|
567
|
-
```
|
568
|
-
|
569
|
-
**NOTE:** Rails I18n recognizes the `zero` option.
|
570
|
-
|
571
|
-
If you need special rules just define them for your language, for example
|
572
|
-
Russian, just add a new pluralizer:
|
573
|
-
|
574
|
-
```javascript
|
575
|
-
I18n.pluralization["ru"] = function (count) {
|
576
|
-
var key =
|
577
|
-
count % 10 == 1 && count % 100 != 11
|
578
|
-
? "one"
|
579
|
-
: [2, 3, 4].indexOf(count % 10) >= 0 &&
|
580
|
-
[12, 13, 14].indexOf(count % 100) < 0
|
581
|
-
? "few"
|
582
|
-
: count % 10 == 0 ||
|
583
|
-
[5, 6, 7, 8, 9].indexOf(count % 10) >= 0 ||
|
584
|
-
[11, 12, 13, 14].indexOf(count % 100) >= 0
|
585
|
-
? "many"
|
586
|
-
: "other";
|
587
|
-
return [key];
|
588
|
-
};
|
589
|
-
```
|
590
|
-
|
591
|
-
You can find all rules on
|
592
|
-
<https://unicode-org.github.io/cldr-staging/charts/37/supplemental/language_plural_rules.html>.
|
593
|
-
|
594
|
-
If you're using the same scope over and over again, you may use the `scope`
|
595
|
-
option.
|
596
|
-
|
597
|
-
```javascript
|
598
|
-
var options = { scope: "activerecord.attributes.user" };
|
599
|
-
|
600
|
-
I18n.t("name", options);
|
601
|
-
I18n.t("email", options);
|
602
|
-
I18n.t("username", options);
|
603
|
-
```
|
604
|
-
|
605
|
-
You can also provide an array as scope.
|
606
|
-
|
607
|
-
```javascript
|
608
|
-
// use the greetings.hello scope
|
609
|
-
I18n.t(["greetings", "hello"]);
|
610
|
-
```
|
611
|
-
|
612
|
-
#### Number formatting
|
613
|
-
|
614
|
-
Similar to Rails helpers, you have localized number and currency formatting.
|
615
|
-
|
616
|
-
```javascript
|
617
|
-
I18n.l("currency", 1990.99);
|
618
|
-
// $1,990.99
|
619
|
-
|
620
|
-
I18n.l("number", 1990.99);
|
621
|
-
// 1,990.99
|
622
|
-
|
623
|
-
I18n.l("percentage", 123.45);
|
624
|
-
// 123.450%
|
625
|
-
```
|
626
|
-
|
627
|
-
To have more control over number formatting, you can use the `I18n.toNumber`,
|
628
|
-
`I18n.toPercentage`, `I18n.toCurrency` and `I18n.toHumanSize` functions.
|
629
|
-
|
630
|
-
```javascript
|
631
|
-
I18n.toNumber(1000); // 1,000.000
|
632
|
-
I18n.toCurrency(1000); // $1,000.00
|
633
|
-
I18n.toPercentage(100); // 100.000%
|
634
|
-
```
|
635
|
-
|
636
|
-
The `toNumber` and `toPercentage` functions accept the following options:
|
637
|
-
|
638
|
-
- `precision`: defaults to `3`
|
639
|
-
- `separator`: defaults to `.`
|
640
|
-
- `delimiter`: defaults to `,`
|
641
|
-
- `strip_insignificant_zeros`: defaults to `false`
|
642
|
-
|
643
|
-
See some number formatting examples:
|
644
|
-
|
645
|
-
```javascript
|
646
|
-
I18n.toNumber(1000, { precision: 0 }); // 1,000
|
647
|
-
I18n.toNumber(1000, { delimiter: ".", separator: "," }); // 1.000,000
|
648
|
-
I18n.toNumber(1000, { delimiter: ".", precision: 0 }); // 1.000
|
649
|
-
```
|
650
|
-
|
651
|
-
The `toCurrency` function accepts the following options:
|
652
|
-
|
653
|
-
- `precision`: sets the level of precision
|
654
|
-
- `separator`: sets the separator between the units
|
655
|
-
- `delimiter`: sets the thousands delimiter
|
656
|
-
- `format`: sets the format of the output string
|
657
|
-
- `unit`: sets the denomination of the currency
|
658
|
-
- `strip_insignificant_zeros`: defaults to `false`
|
659
|
-
- `sign_first`: defaults to `true`
|
660
|
-
|
661
|
-
You can provide only the options you want to override:
|
382
|
+
---
|
383
|
+
translations:
|
384
|
+
- file: app/frontend/translations.json
|
385
|
+
patterns:
|
386
|
+
- "*"
|
662
387
|
|
663
|
-
|
664
|
-
|
388
|
+
lint_scripts:
|
389
|
+
ignore:
|
390
|
+
- ignore_scope # will ignore this scope on all languages
|
391
|
+
- pt.another_ignore_scope # will ignore this scope only on `pt`
|
665
392
|
```
|
666
393
|
|
667
|
-
|
668
|
-
|
669
|
-
- `precision`: defaults to `1`
|
670
|
-
- `separator`: defaults to `.`
|
671
|
-
- `delimiter`: defaults to `""`
|
672
|
-
- `strip_insignificant_zeros`: defaults to `false`
|
673
|
-
- `format`: defaults to `%n%u`
|
674
|
-
- `scope`: defaults to `""`
|
394
|
+
You can also set the patterns that will be looked up. By default, it scans all
|
395
|
+
JavaScript and TypeScript files that don't live on `node_modules`.
|
675
396
|
|
676
|
-
|
397
|
+
```yaml
|
398
|
+
---
|
399
|
+
translations:
|
400
|
+
- file: app/frontend/translations.json
|
401
|
+
patterns:
|
402
|
+
- "*"
|
677
403
|
|
678
|
-
|
679
|
-
|
680
|
-
|
404
|
+
lint:
|
405
|
+
patterns:
|
406
|
+
- "app/assets/**/*.ts"
|
681
407
|
```
|
682
408
|
|
683
|
-
|
684
|
-
|
685
|
-
```javascript
|
686
|
-
// accepted formats
|
687
|
-
I18n.l("date.formats.short", "2009-09-18"); // yyyy-mm-dd
|
688
|
-
I18n.l("time.formats.short", "2009-09-18 23:12:43"); // yyyy-mm-dd hh:mm:ss
|
689
|
-
I18n.l("time.formats.short", "2009-11-09T18:10:34"); // JSON format with local Timezone (part of ISO-8601)
|
690
|
-
I18n.l("time.formats.short", "2009-11-09T18:10:34Z"); // JSON format in UTC (part of ISO-8601)
|
691
|
-
I18n.l("date.formats.short", 1251862029000); // Epoch time
|
692
|
-
I18n.l("date.formats.short", "09/18/2009"); // mm/dd/yyyy
|
693
|
-
I18n.l("date.formats.short", new Date()); // Date object
|
694
|
-
```
|
409
|
+
## Automatically export translations
|
695
410
|
|
696
|
-
|
411
|
+
### Using [watchman](https://facebook.github.io/watchman/)
|
697
412
|
|
698
|
-
|
699
|
-
I18n.translations["en"] = {
|
700
|
-
date: {
|
701
|
-
formats: {
|
702
|
-
ordinal_day: "%B %{day}",
|
703
|
-
},
|
704
|
-
},
|
705
|
-
};
|
413
|
+
Create a script at `bin/i18n-watch`.
|
706
414
|
|
707
|
-
|
708
|
-
|
709
|
-
|
710
|
-
|
711
|
-
|
712
|
-
|
713
|
-
|
714
|
-
|
715
|
-
|
716
|
-
|
717
|
-
|
718
|
-
|
719
|
-
|
720
|
-
|
721
|
-
|
722
|
-
|
723
|
-
|
724
|
-
|
725
|
-
|
726
|
-
|
727
|
-
|
728
|
-
%-d - Day of the month (1..31)
|
729
|
-
%H - Hour of the day, 24-hour clock (00..23)
|
730
|
-
%-H/%k - Hour of the day, 24-hour clock (0..23)
|
731
|
-
%I - Hour of the day, 12-hour clock (01..12)
|
732
|
-
%-I/%l - Hour of the day, 12-hour clock (1..12)
|
733
|
-
%m - Month of the year (01..12)
|
734
|
-
%-m - Month of the year (1..12)
|
735
|
-
%M - Minute of the hour (00..59)
|
736
|
-
%-M - Minute of the hour (0..59)
|
737
|
-
%p - Meridian indicator (AM or PM)
|
738
|
-
%P - Meridian indicator (am or pm)
|
739
|
-
%S - Second of the minute (00..60)
|
740
|
-
%-S - Second of the minute (0..60)
|
741
|
-
%w - Day of the week (Sunday is 0, 0..6)
|
742
|
-
%y - Year without a century (00..99)
|
743
|
-
%-y - Year without a century (0..99)
|
744
|
-
%Y - Year with century
|
745
|
-
%z/%Z - Timezone offset (+0545)
|
746
|
-
|
747
|
-
Check out `spec/*.spec.js` files for more examples!
|
748
|
-
|
749
|
-
#### Using pluralization and number formatting together
|
750
|
-
|
751
|
-
Sometimes you might want to display translation with formatted number, like
|
752
|
-
adding thousand delimiters to displayed number You can do this:
|
753
|
-
|
754
|
-
```json
|
755
|
-
{
|
756
|
-
"en": {
|
757
|
-
"point": {
|
758
|
-
"one": "1 Point",
|
759
|
-
"other": "{{formatted_number}} Points",
|
760
|
-
"zero": "0 Points"
|
761
|
-
}
|
415
|
+
```bash
|
416
|
+
#!/usr/bin/env bash
|
417
|
+
|
418
|
+
root=`pwd`
|
419
|
+
|
420
|
+
watchman watch-del "$root"
|
421
|
+
watchman watch-project "$root"
|
422
|
+
watchman trigger-del "$root" i18n
|
423
|
+
|
424
|
+
watchman -j <<-JSON
|
425
|
+
[
|
426
|
+
"trigger",
|
427
|
+
"$root",
|
428
|
+
{
|
429
|
+
"name": "i18n",
|
430
|
+
"expression": [
|
431
|
+
"anyof",
|
432
|
+
["match", "config/locales/**/*.yml", "wholename"],
|
433
|
+
["match", "config/i18n.yml", "wholename"]
|
434
|
+
],
|
435
|
+
"command": ["i18n", "export"]
|
762
436
|
}
|
763
|
-
|
764
|
-
|
437
|
+
]
|
438
|
+
JSON
|
765
439
|
|
766
|
-
|
767
|
-
|
768
|
-
|
769
|
-
|
770
|
-
|
771
|
-
});
|
440
|
+
# If you're running this through Foreman,
|
441
|
+
# the uncomment the following lines:
|
442
|
+
# while true; do
|
443
|
+
# sleep 1
|
444
|
+
# done
|
772
445
|
```
|
773
446
|
|
774
|
-
|
775
|
-
|
776
|
-
|
777
|
-
|
778
|
-
This method is useful for very large apps where a single contained
|
779
|
-
translations.js file is not desirable. Examples would be a global translations
|
780
|
-
file and a more specific route translation file.
|
781
|
-
|
782
|
-
### Rails without asset pipeline
|
783
|
-
|
784
|
-
1. Setup your `config/i18n-js.yml` to have multiple files and try to minimize
|
785
|
-
any overlap.
|
447
|
+
Make it executable with `chmod +x bin/i18n-watch`. To watch for changes, run
|
448
|
+
`./bin/i18n-watch`. If you're using Foreman, make sure you uncommented the lines
|
449
|
+
that keep the process running (`while..`), and add something like the following
|
450
|
+
line to your Procfile:
|
786
451
|
|
787
|
-
```yaml
|
788
|
-
sort_translation_keys: true
|
789
|
-
fallbacks: false
|
790
|
-
|
791
|
-
translations:
|
792
|
-
+ file: "app/assets/javascript/nls/welcome.js"
|
793
|
-
only:
|
794
|
-
+ '*.welcome.*'
|
795
|
-
|
796
|
-
+ file: "app/assets/javascript/nls/albums.js"
|
797
|
-
only:
|
798
|
-
+ '*.albums.*'
|
799
|
-
|
800
|
-
+ file: "app/assets/javascript/nls/global.js"
|
801
|
-
only:
|
802
|
-
+ '*'
|
803
|
-
# Exempt any routes specific translations from being
|
804
|
-
# included in the global translation file
|
805
|
-
except:
|
806
|
-
+ '*.welcome.*'
|
807
|
-
+ '*.albums.*'
|
808
452
|
```
|
809
|
-
|
810
|
-
When `rake i18n:js:export` is executed it will create 3 translations files that
|
811
|
-
can be loaded via the `javascript_include_tag`
|
812
|
-
|
813
|
-
2. Add the `javascript_include_tag` to your layout and to any route specific
|
814
|
-
files that will require it.
|
815
|
-
|
816
|
-
```ruby
|
817
|
-
# views/layouts/application.html.erb
|
818
|
-
<%= javascript_include_tag(
|
819
|
-
"i18n"
|
820
|
-
"nls/global"
|
821
|
-
) %>
|
453
|
+
i18n: ./bin/i18n-watch
|
822
454
|
```
|
823
455
|
|
824
|
-
|
825
|
-
|
826
|
-
```ruby
|
827
|
-
# views/welcome/index.html.erb
|
828
|
-
<%= javascript_include_tag(
|
829
|
-
"nls/welcome"
|
830
|
-
) %>
|
831
|
-
```
|
456
|
+
### Using [guard](https://rubygems.org/gems/guard)
|
832
457
|
|
833
|
-
|
458
|
+
Install [guard](https://rubygems.org/gems/guard) and
|
459
|
+
[guard-compat](https://rubygems.org/gems/guard-compat). Then create a Guardfile
|
460
|
+
with the following configuration:
|
834
461
|
|
835
462
|
```ruby
|
836
|
-
|
837
|
-
|
838
|
-
|
839
|
-
|
840
|
-
|
841
|
-
|
842
|
-
|
843
|
-
|
844
|
-
To use this with require.js we are only going to change a few things from above.
|
845
|
-
|
846
|
-
1. In your `config/i18n-js.yml` we need to add a better location for the i18n to
|
847
|
-
be exported to. You want to use this location so that it can be properly
|
848
|
-
precompiled by r.js.
|
849
|
-
|
850
|
-
```yaml
|
851
|
-
export_i18n_js: "app/assets/javascript/nls"
|
852
|
-
```
|
853
|
-
|
854
|
-
2. In your `config/require.yml` we need to add a map, shim all the translations,
|
855
|
-
and include them into the appropriate modules
|
856
|
-
|
857
|
-
```yaml
|
858
|
-
# In your maps add (if you do not have this you will need to add it)
|
859
|
-
map:
|
860
|
-
'*':
|
861
|
-
i18n: 'nls/i18n'
|
862
|
-
|
863
|
-
# In your shims
|
864
|
-
shims:
|
865
|
-
nls/welcome:
|
866
|
-
deps:
|
867
|
-
+ i18n
|
868
|
-
|
869
|
-
nls/global:
|
870
|
-
deps:
|
871
|
-
+ i18n
|
872
|
-
|
873
|
-
# Finally in your modules
|
874
|
-
modules:
|
875
|
-
+ name: 'application'
|
876
|
-
include:
|
877
|
-
+ i18n
|
878
|
-
+ 'nls/global'
|
879
|
-
|
880
|
-
+ name: 'welcome'
|
881
|
-
exclude:
|
882
|
-
+ application
|
883
|
-
include:
|
884
|
-
+ 'nls/welcome'
|
885
|
-
```
|
886
|
-
|
887
|
-
3. When `rake assets:precompile` is executed it will optimize the translations
|
888
|
-
into the correct modules so they are loaded with their assigned module, and
|
889
|
-
loading them with requirejs is as simple as requiring any other shim.
|
890
|
-
|
891
|
-
```javascript
|
892
|
-
define(["welcome/other_asset", "nls/welcome"], function (otherAsset) {
|
893
|
-
// ...
|
894
|
-
});
|
895
|
-
```
|
896
|
-
|
897
|
-
4. (optional) As an additional configuration we can make a task to be run before
|
898
|
-
the requirejs optimizer. This will allow any automated scripts that run the
|
899
|
-
requirejs optimizer to export the strings before we run r.js.
|
900
|
-
|
901
|
-
```rake
|
902
|
-
# lib/tasks/i18n.rake
|
903
|
-
Rake::Task[:'i18n:js:export'].prerequisites.clear
|
904
|
-
task :'i18n:js:export' => :'i18n:js:before_export'
|
905
|
-
task :'requirejs:precompile:external' => :'i18n:js:export'
|
906
|
-
|
907
|
-
namespace :i18n do
|
908
|
-
namespace :js do
|
909
|
-
task :before_export => :'assets:environment' do
|
910
|
-
I18n.load_path += Dir[Rails.root.join('config', 'locales', '*.{yml,rb}')]
|
911
|
-
I18n.backend.load_translations
|
912
|
-
end
|
913
|
-
end
|
463
|
+
guard(:"i18n-js",
|
464
|
+
run_on_start: true,
|
465
|
+
config_file: "./config/i18n.yml",
|
466
|
+
require_file: "./config/environment.rb") do
|
467
|
+
watch(%r{^(app|config)/locales/.+\.(yml|po)$})
|
468
|
+
watch(%r{^config/i18n.yml$})
|
469
|
+
watch("Gemfile")
|
914
470
|
end
|
915
471
|
```
|
916
472
|
|
917
|
-
|
473
|
+
If your files are located in a different path, remember to configure file paths
|
474
|
+
accordingly.
|
918
475
|
|
919
|
-
|
920
|
-
[your favorite language here]. The only requirement is that you need to set the
|
921
|
-
`translations` attribute like following:
|
476
|
+
Now you can run `guard start -i`.
|
922
477
|
|
923
|
-
|
924
|
-
I18n.translations = {};
|
478
|
+
### Using [listen](https://rubygems.org/gems/listen)
|
925
479
|
|
926
|
-
|
927
|
-
message: "Some special message for you",
|
928
|
-
};
|
480
|
+
Create a file under `config/initializers/i18n.rb` with the following content:
|
929
481
|
|
930
|
-
|
931
|
-
|
932
|
-
|
482
|
+
```ruby
|
483
|
+
Rails.application.config.after_initialize do
|
484
|
+
require "i18n-js/listen"
|
485
|
+
I18nJS.listen
|
486
|
+
end
|
933
487
|
```
|
934
488
|
|
935
|
-
|
936
|
-
|
937
|
-
### Missing translations in precompiled file(s) after adding any new locale file
|
938
|
-
|
939
|
-
Due to the design of `sprockets`:
|
940
|
-
|
941
|
-
- `depend_on` only takes file paths, not directory paths
|
942
|
-
- registered `preprocessors` are only run when the fingerprint of any asset
|
943
|
-
file, including `.erb` files, is changed
|
944
|
-
|
945
|
-
This means that new locale files will not be detected, and so they will not
|
946
|
-
trigger a i18n-js refresh. There are a few approaches to work around this:
|
947
|
-
|
948
|
-
1. You can force i18n-js to update its translations by completely clearing the
|
949
|
-
assets cache. Use one of the following:
|
489
|
+
The code above will watch for changes based on `config/i18n.yml` and
|
490
|
+
`config/locales`. You can customize these options:
|
950
491
|
|
951
|
-
|
952
|
-
|
953
|
-
|
954
|
-
|
955
|
-
|
492
|
+
- `config_file` - i18n-js configuration file
|
493
|
+
- `locales_dir` - one or multiple directories to watch for locales changes
|
494
|
+
- `options` - passed directly to
|
495
|
+
[listen](https://github.com/guard/listen/#options)
|
496
|
+
- `run_on_start` - export files on start. Defaults to `true`. When disabled,
|
497
|
+
files will be exported only when there are file changes.
|
956
498
|
|
957
|
-
|
958
|
-
recompile them with
|
499
|
+
Example:
|
959
500
|
|
960
|
-
```
|
961
|
-
|
501
|
+
```ruby
|
502
|
+
I18nJS.listen(
|
503
|
+
config_file: "config/i18n.yml",
|
504
|
+
locales_dir: ["config/locales", "app/views"],
|
505
|
+
options: {only: %r{.yml$}},
|
506
|
+
run_on_start: false
|
507
|
+
)
|
962
508
|
```
|
963
509
|
|
964
|
-
|
965
|
-
cached pages may be broken by this, so they will need to be refreshed.
|
966
|
-
|
967
|
-
2. You can change something in a different locale file.
|
968
|
-
|
969
|
-
3. Finally, you can change `config.assets.version`.
|
970
|
-
|
971
|
-
**Note:** See issue [#213](https://github.com/fnando/i18n-js/issues/213) for
|
972
|
-
more details and discussion of this issue.
|
973
|
-
|
974
|
-
### Translations in JS are not updated when Sprockets not loaded before this gem
|
510
|
+
### Integrating with your frontend
|
975
511
|
|
976
|
-
|
977
|
-
|
978
|
-
|
979
|
-
locale files will not be hooked. So ensure sprockets is loaded before this gem
|
980
|
-
by moving the entry of sprockets in the Gemfile or adding "require" statements
|
981
|
-
for sprockets somewhere.
|
512
|
+
You're done exporting files, now what? Well, go to
|
513
|
+
[i18n](https://github.com/fnando/i18n) to discover how to use the NPM package
|
514
|
+
that loads all the exported translation.
|
982
515
|
|
983
|
-
|
984
|
-
more details and discussion of this issue.
|
516
|
+
### FAQ
|
985
517
|
|
986
|
-
|
518
|
+
#### I'm running v3. Is there a migration plan?
|
987
519
|
|
988
|
-
|
989
|
-
|
520
|
+
[There's a document](https://github.com/fnando/i18n-js/tree/main/MIGRATING_FROM_V3_TO_V4.md)
|
521
|
+
outlining some of the things you need to do to migrate from v3 to v4. It may not
|
522
|
+
be as complete as we'd like it to be, so let us know if you face any issues
|
523
|
+
during the migration is not outline is that document.
|
990
524
|
|
991
|
-
|
992
|
-
[#511](https://github.com/fnando/i18n-js/issues/511)
|
525
|
+
#### How can I export translations without having a database around?
|
993
526
|
|
994
|
-
|
995
|
-
|
996
|
-
|
997
|
-
|
998
|
-
|
999
|
-
|
1000
|
-
```
|
1001
|
-
Undefined method 'initialized?' for <your backend class>
|
1002
|
-
```
|
1003
|
-
|
1004
|
-
For now, i18n-js is compatible with the `Simple` backend and with
|
1005
|
-
`I18n::Backend::ActiveRecord` (>= 0.4.0).
|
1006
|
-
|
1007
|
-
If you need a more sophisticated backend for your rails application that doesn't
|
1008
|
-
implement the required methods, you can setup i18n-js to get translations from a
|
1009
|
-
separate `Simple` backend, by adding the following in an initializer:
|
527
|
+
Some people may have a build process using something like Docker that don't
|
528
|
+
necessarily have a database available. In this case, you may define your own
|
529
|
+
loading file by using something like
|
530
|
+
`i18n export --require ./config/i18n_export.rb`, where `i18n_export.rb` may look
|
531
|
+
like this:
|
1010
532
|
|
1011
533
|
```ruby
|
1012
|
-
|
1013
|
-
I18n.backend = I18n::Backend::Chain.new(<your other backend(s)>, I18n.backend)
|
1014
|
-
```
|
534
|
+
# frozen_string_literal: true
|
1015
535
|
|
1016
|
-
|
1017
|
-
|
1018
|
-
|
536
|
+
require "bundler/setup"
|
537
|
+
require "rails"
|
538
|
+
require "active_support/railtie"
|
539
|
+
require "action_view/railtie"
|
1019
540
|
|
1020
|
-
|
1021
|
-
|
1022
|
-
```ruby
|
1023
|
-
I18n::JS.backend = I18n::Backend::Simple.new
|
1024
|
-
I18n.backend = <something different>
|
541
|
+
I18n.load_path += Dir["./config/locales/**/*.yml"]
|
1025
542
|
```
|
1026
543
|
|
1027
|
-
|
1028
|
-
|
1029
|
-
|
1030
|
-
|
1031
|
-
|
1032
|
-
|
1033
|
-
```ruby
|
1034
|
-
module I18n
|
1035
|
-
def self.reload!
|
1036
|
-
I18n::JS.backend.reload!
|
1037
|
-
super
|
1038
|
-
end
|
1039
|
-
end
|
1040
|
-
```
|
1041
|
-
|
1042
|
-
See issue [#428](https://github.com/fnando/i18n-js/issues/428) for more details
|
1043
|
-
and discussion of this issue.
|
544
|
+
> **Note**:
|
545
|
+
>
|
546
|
+
> You may not need to load ActiveSupport and ActionView lines, or even may need
|
547
|
+
> to add additional requires for other libs. With this approach you have full
|
548
|
+
> control on what's going to be loaded.
|
1044
549
|
|
1045
550
|
## Maintainer
|
1046
551
|
|
1047
|
-
- Nando Vieira
|
1048
|
-
|
1049
|
-
## Contributing
|
1050
|
-
|
1051
|
-
Once you've made your great commits:
|
552
|
+
- [Nando Vieira](https://github.com/fnando)
|
1052
553
|
|
1053
|
-
|
1054
|
-
2. Create a branch with a clear name
|
1055
|
-
3. Make your changes (Please also add/change spec, README and CHANGELOG if
|
1056
|
-
applicable)
|
1057
|
-
4. Push changes to the created branch
|
1058
|
-
5. [Create an Pull Request](https://github.com/fnando/i18n-js/pulls)
|
1059
|
-
6. That's it!
|
554
|
+
## Contributors
|
1060
555
|
|
1061
|
-
|
1062
|
-
And don't touch the versioning thing.
|
556
|
+
- https://github.com/fnando/i18n-js/contributors
|
1063
557
|
|
1064
|
-
##
|
1065
|
-
|
1066
|
-
You can run I18n tests using Node.js or your browser.
|
1067
|
-
|
1068
|
-
To use Node.js, install the `jasmine-node` library:
|
1069
|
-
|
1070
|
-
$ npm install jasmine-node
|
1071
|
-
|
1072
|
-
Then execute the following command from the lib's root directory:
|
1073
|
-
|
1074
|
-
$ npm test
|
1075
|
-
|
1076
|
-
To run using your browser, just open the `spec/js/specs.html` file.
|
558
|
+
## Contributing
|
1077
559
|
|
1078
|
-
|
560
|
+
For more details about how to contribute, please read
|
561
|
+
https://github.com/fnando/i18n-js/blob/main/CONTRIBUTING.md.
|
1079
562
|
|
1080
563
|
## License
|
1081
564
|
|
1082
|
-
|
1083
|
-
|
1084
|
-
|
1085
|
-
this software and associated documentation files (the 'Software'), to deal in
|
1086
|
-
the Software without restriction, including without limitation the rights to
|
1087
|
-
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
1088
|
-
the Software, and to permit persons to whom the Software is furnished to do so,
|
1089
|
-
subject to the following conditions:
|
565
|
+
The gem is available as open source under the terms of the
|
566
|
+
[MIT License](https://opensource.org/licenses/MIT). A copy of the license can be
|
567
|
+
found at https://github.com/fnando/i18n-js/blob/main/LICENSE.md.
|
1090
568
|
|
1091
|
-
|
1092
|
-
copies or substantial portions of the Software.
|
569
|
+
## Code of Conduct
|
1093
570
|
|
1094
|
-
|
1095
|
-
|
1096
|
-
|
1097
|
-
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
1098
|
-
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
1099
|
-
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
571
|
+
Everyone interacting in the i18n-js project's codebases, issue trackers, chat
|
572
|
+
rooms and mailing lists is expected to follow the
|
573
|
+
[code of conduct](https://github.com/fnando/i18n-js/blob/main/CODE_OF_CONDUCT.md).
|