i18n-js 3.3.0 → 3.9.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.editorconfig +1 -1
- data/.github/FUNDING.yml +3 -0
- data/.github/workflows/tests.yaml +106 -0
- data/Appraisals +16 -0
- data/CHANGELOG.md +153 -4
- data/README.md +505 -333
- data/app/assets/javascripts/i18n/shims.js +35 -3
- data/app/assets/javascripts/i18n.js +37 -33
- data/gemfiles/i18n_1_10.gemfile +7 -0
- data/gemfiles/i18n_1_7.gemfile +7 -0
- data/gemfiles/i18n_1_8.gemfile +7 -0
- data/gemfiles/i18n_1_9.gemfile +7 -0
- data/i18n-js.gemspec +2 -2
- data/i18njs.png +0 -0
- data/lib/i18n/js/dependencies.rb +6 -2
- data/lib/i18n/js/engine.rb +1 -1
- data/lib/i18n/js/formatters/base.rb +3 -1
- data/lib/i18n/js/formatters/js.rb +12 -4
- data/lib/i18n/js/middleware.rb +1 -1
- data/lib/i18n/js/private/config_store.rb +31 -0
- data/lib/i18n/js/segment.rb +9 -3
- data/lib/i18n/js/utils.rb +34 -8
- data/lib/i18n/js/version.rb +1 -1
- data/lib/i18n/js.rb +25 -10
- data/package.json +2 -2
- data/spec/fixtures/js_available_locales_custom.yml +1 -0
- data/spec/fixtures/{js_file_with_namespace_and_pretty_print.yml → js_file_with_namespace_prefix_and_pretty_print.yml} +2 -0
- data/spec/fixtures/locales.yml +38 -0
- data/spec/fixtures/merge_plurals_with_no_overrides.yml +4 -0
- data/spec/fixtures/merge_plurals_with_partial_overrides.yml +4 -0
- data/spec/fixtures/millions.yml +4 -0
- data/spec/js/dates.spec.js +1 -0
- data/spec/js/json_parsable.spec.js +14 -0
- data/spec/js/localization.spec.js +38 -14
- data/spec/js/numbers.spec.js +4 -0
- data/spec/js/pluralization.spec.js +19 -2
- data/spec/js/require.js +4 -4
- data/spec/js/translate.spec.js +68 -48
- data/spec/js/translations.js +27 -2
- data/spec/ruby/i18n/js/segment_spec.rb +75 -8
- data/spec/ruby/i18n/js/utils_spec.rb +32 -0
- data/spec/ruby/i18n/js_spec.rb +169 -35
- data/spec/spec_helper.rb +1 -0
- data/yarn.lock +32 -25
- metadata +26 -9
- data/.travis.yml +0 -37
data/spec/js/translations.js
CHANGED
@@ -58,6 +58,18 @@
|
|
58
58
|
}
|
59
59
|
}
|
60
60
|
|
61
|
+
, extended: {
|
62
|
+
number: {
|
63
|
+
human: {
|
64
|
+
storage_units: {
|
65
|
+
units: {
|
66
|
+
"mb": "Megabyte"
|
67
|
+
}
|
68
|
+
}
|
69
|
+
}
|
70
|
+
}
|
71
|
+
}
|
72
|
+
|
61
73
|
, arrayWithParams: [
|
62
74
|
null,
|
63
75
|
"An item with a param of {{value}}",
|
@@ -67,7 +79,11 @@
|
|
67
79
|
{foo: "bar"}
|
68
80
|
]
|
69
81
|
|
70
|
-
, null_key: null
|
82
|
+
, null_key: null,
|
83
|
+
|
84
|
+
sentences_with_dots: {
|
85
|
+
"A implies B means something.": "A implies B means that when A is true, B must be true."
|
86
|
+
}
|
71
87
|
};
|
72
88
|
|
73
89
|
Translations["en-US"] = {
|
@@ -90,7 +106,16 @@
|
|
90
106
|
hello: "Olá Mundo!"
|
91
107
|
|
92
108
|
, number: {
|
93
|
-
|
109
|
+
currency: {
|
110
|
+
format: {
|
111
|
+
delimiter: ".",
|
112
|
+
format: "%u %n",
|
113
|
+
precision: 2,
|
114
|
+
separator: ",",
|
115
|
+
unit: "R$"
|
116
|
+
}
|
117
|
+
}
|
118
|
+
, percentage: {
|
94
119
|
format: {
|
95
120
|
delimiter: ""
|
96
121
|
, separator: ","
|
@@ -131,8 +131,8 @@ EOS
|
|
131
131
|
|
132
132
|
expect(File.open(File.join(temp_path, "segment.js")){|f| f.read}).to eql <<-EOF
|
133
133
|
MyNamespace.translations || (MyNamespace.translations = {});
|
134
|
-
MyNamespace.translations["en"] = I18n.extend((MyNamespace.translations["en"] || {}), {"test":"Test"});
|
135
|
-
MyNamespace.translations["fr"] = I18n.extend((MyNamespace.translations["fr"] || {}), {"test":"Test2"});
|
134
|
+
MyNamespace.translations["en"] = I18n.extend((MyNamespace.translations["en"] || {}), JSON.parse('{"test":"Test"}'));
|
135
|
+
MyNamespace.translations["fr"] = I18n.extend((MyNamespace.translations["fr"] || {}), JSON.parse('{"test":"Test2"}'));
|
136
136
|
EOF
|
137
137
|
end
|
138
138
|
end
|
@@ -146,12 +146,54 @@ MyNamespace.translations["fr"] = I18n.extend((MyNamespace.translations["fr"] ||
|
|
146
146
|
|
147
147
|
expect(File.open(File.join(temp_path, "en.js")){|f| f.read}).to eql <<-EOF
|
148
148
|
MyNamespace.translations || (MyNamespace.translations = {});
|
149
|
-
MyNamespace.translations["en"] = I18n.extend((MyNamespace.translations["en"] || {}), {"test":"Test"});
|
149
|
+
MyNamespace.translations["en"] = I18n.extend((MyNamespace.translations["en"] || {}), JSON.parse('{"test":"Test"}'));
|
150
150
|
EOF
|
151
151
|
|
152
152
|
expect(File.open(File.join(temp_path, "fr.js")){|f| f.read}).to eql <<-EOF
|
153
153
|
MyNamespace.translations || (MyNamespace.translations = {});
|
154
|
-
MyNamespace.translations["fr"] = I18n.extend((MyNamespace.translations["fr"] || {}), {"test":"Test2"});
|
154
|
+
MyNamespace.translations["fr"] = I18n.extend((MyNamespace.translations["fr"] || {}), JSON.parse('{"test":"Test2"}'));
|
155
|
+
EOF
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
context "when file includes single quote" do
|
160
|
+
let(:file){ "tmp/i18n-js/%{locale}.js" }
|
161
|
+
let(:translations){ { en: { "a" => "Test's" } } }
|
162
|
+
|
163
|
+
it "should write files" do
|
164
|
+
file_should_exist "en.js"
|
165
|
+
|
166
|
+
expect(File.open(File.join(temp_path, "en.js")){|f| f.read}).to eql <<-EOF
|
167
|
+
MyNamespace.translations || (MyNamespace.translations = {});
|
168
|
+
MyNamespace.translations["en"] = I18n.extend((MyNamespace.translations["en"] || {}), JSON.parse('{"a":"Test\\'s"}'));
|
169
|
+
EOF
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
context "when file includes escaped double quote" do
|
174
|
+
let(:file){ "tmp/i18n-js/%{locale}.js" }
|
175
|
+
let(:translations){ { en: { "a" => 'say "hello"' } } }
|
176
|
+
|
177
|
+
it "should escape double quote" do
|
178
|
+
file_should_exist "en.js"
|
179
|
+
|
180
|
+
expect(File.open(File.join(temp_path, "en.js")){|f| f.read}).to eql <<-EOF
|
181
|
+
MyNamespace.translations || (MyNamespace.translations = {});
|
182
|
+
MyNamespace.translations["en"] = I18n.extend((MyNamespace.translations["en"] || {}), JSON.parse('{"a":"say \\\\"hello\\\\""}'));
|
183
|
+
EOF
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
context "when file includes backslash in double quote" do
|
188
|
+
let(:file){ "tmp/i18n-js/%{locale}.js" }
|
189
|
+
let(:translations){ { en: { "double-backslash-in-double-quote" => '"\\\\"' } } }
|
190
|
+
|
191
|
+
it "should escape backslash" do
|
192
|
+
file_should_exist "en.js"
|
193
|
+
|
194
|
+
expect(File.open(File.join(temp_path, "en.js")){|f| f.read}).to eql <<-EOF
|
195
|
+
MyNamespace.translations || (MyNamespace.translations = {});
|
196
|
+
MyNamespace.translations["en"] = I18n.extend((MyNamespace.translations["en"] || {}), JSON.parse('{"double-backslash-in-double-quote":"\\\\"\\\\\\\\\\\\\\\\\\\\""}'));
|
155
197
|
EOF
|
156
198
|
end
|
157
199
|
end
|
@@ -166,7 +208,7 @@ MyNamespace.translations["fr"] = I18n.extend((MyNamespace.translations["fr"] ||
|
|
166
208
|
|
167
209
|
expect(File.open(File.join(temp_path, "segment.js")){|f| f.read}).to eql <<-EOF
|
168
210
|
MyNamespace.translations || (MyNamespace.translations = {});
|
169
|
-
MyNamespace.translations["en"] = I18n.extend((MyNamespace.translations["en"] || {}), {"a":"Test","b":"Test"});
|
211
|
+
MyNamespace.translations["en"] = I18n.extend((MyNamespace.translations["en"] || {}), JSON.parse('{"a":"Test","b":"Test"}'));
|
170
212
|
EOF
|
171
213
|
end
|
172
214
|
end
|
@@ -181,7 +223,7 @@ MyNamespace.translations["en"] = I18n.extend((MyNamespace.translations["en"] ||
|
|
181
223
|
|
182
224
|
expect(File.open(File.join(temp_path, "segment.js")){|f| f.read}).to eql <<-EOF
|
183
225
|
MyNamespace.translations || (MyNamespace.translations = {});
|
184
|
-
MyNamespace.translations["en"] = {"a":"Test","b":"Test"};
|
226
|
+
MyNamespace.translations["en"] = JSON.parse('{"a":"Test","b":"Test"}');
|
185
227
|
EOF
|
186
228
|
end
|
187
229
|
end
|
@@ -196,7 +238,7 @@ MyNamespace.translations["en"] = {"a":"Test","b":"Test"};
|
|
196
238
|
|
197
239
|
expect(File.open(File.join(temp_path, "segment.js")){|f| f.read}).to eql <<-EOF
|
198
240
|
MyNamespace.translations || (MyNamespace.translations = {});
|
199
|
-
MyNamespace.translations["en"] = I18n.extend((MyNamespace.translations["en"] || {}), {"a":"Test","b":"Test"});
|
241
|
+
MyNamespace.translations["en"] = I18n.extend((MyNamespace.translations["en"] || {}), JSON.parse('{"a":"Test","b":"Test"}'));
|
200
242
|
EOF
|
201
243
|
end
|
202
244
|
end
|
@@ -211,7 +253,32 @@ MyNamespace.translations["en"] = I18n.extend((MyNamespace.translations["en"] ||
|
|
211
253
|
|
212
254
|
expect(File.open(File.join(temp_path, "segment.js")){|f| f.read}).to eql <<-EOF
|
213
255
|
MyNamespace.translations || (MyNamespace.translations = {});
|
214
|
-
MyNamespace.translations["en"] = I18n.extend((MyNamespace.translations["en"] || {}), {"b":"Test","a":"Test"});
|
256
|
+
MyNamespace.translations["en"] = I18n.extend((MyNamespace.translations["en"] || {}), JSON.parse('{"b":"Test","a":"Test"}'));
|
257
|
+
EOF
|
258
|
+
end
|
259
|
+
end
|
260
|
+
|
261
|
+
context "when translation entries contain procs" do
|
262
|
+
let(:translations) do
|
263
|
+
{
|
264
|
+
en: {
|
265
|
+
"test" => "Test",
|
266
|
+
"i18n" => {"plural" => {"rule" => proc {} }},
|
267
|
+
},
|
268
|
+
fr: {
|
269
|
+
"test" => "Test2",
|
270
|
+
"i18n" => {"plural" => {"rule" => proc {} }},
|
271
|
+
},
|
272
|
+
}
|
273
|
+
end
|
274
|
+
|
275
|
+
it "should write files without procs or their string representations" do
|
276
|
+
file_should_exist "segment.js"
|
277
|
+
|
278
|
+
expect(File.open(File.join(temp_path, "segment.js")){|f| f.read}).to eql <<-EOF
|
279
|
+
MyNamespace.translations || (MyNamespace.translations = {});
|
280
|
+
MyNamespace.translations["en"] = I18n.extend((MyNamespace.translations["en"] || {}), JSON.parse('{"i18n":{"plural":{}},"test":"Test"}'));
|
281
|
+
MyNamespace.translations["fr"] = I18n.extend((MyNamespace.translations["fr"] || {}), JSON.parse('{"i18n":{"plural":{}},"test":"Test2"}'));
|
215
282
|
EOF
|
216
283
|
end
|
217
284
|
end
|
@@ -103,4 +103,36 @@ describe I18n::JS::Utils do
|
|
103
103
|
expect(described_class.scopes_match?([:a, :b, :c], [:a, '*', '*'])).to eql true
|
104
104
|
end
|
105
105
|
end
|
106
|
+
|
107
|
+
describe ".deep_remove_procs" do
|
108
|
+
let(:proc_obj) { proc {} }
|
109
|
+
let(:hash_with_proc) do
|
110
|
+
{
|
111
|
+
:a => :b,
|
112
|
+
:c => proc_obj,
|
113
|
+
:d => {
|
114
|
+
:e => proc_obj,
|
115
|
+
:f => :g,
|
116
|
+
}
|
117
|
+
}
|
118
|
+
end
|
119
|
+
subject { described_class.deep_remove_procs(hash_with_proc) }
|
120
|
+
|
121
|
+
it "performs a deep keys sort without changing the original hash" do
|
122
|
+
should eql({
|
123
|
+
:a => :b,
|
124
|
+
:d => {
|
125
|
+
:f => :g,
|
126
|
+
}
|
127
|
+
})
|
128
|
+
expect(hash_with_proc).to eql({
|
129
|
+
:a => :b,
|
130
|
+
:c => proc_obj,
|
131
|
+
:d => {
|
132
|
+
:e => proc_obj,
|
133
|
+
:f => :g,
|
134
|
+
}
|
135
|
+
})
|
136
|
+
end
|
137
|
+
end
|
106
138
|
end
|
data/spec/ruby/i18n/js_spec.rb
CHANGED
@@ -67,13 +67,13 @@ describe I18n::JS do
|
|
67
67
|
en_output = File.read(File.join(I18n::JS.export_i18n_js_dir_path, "en.js"))
|
68
68
|
expect(en_output).to eq(<<EOS
|
69
69
|
I18n.translations || (I18n.translations = {});
|
70
|
-
I18n.translations["en"] = I18n.extend((I18n.translations["en"] || {}), {"admin":{"edit":{"title":"Edit"},"show":{"note":"more details","title":"Show"}},"date":{"abbr_day_names":["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],"abbr_month_names":[null,"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],"day_names":["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],"formats":{"default":"%Y-%m-%d","long":"%B %d, %Y","short":"%b %d"},"month_names":[null,"January","February","March","April","May","June","July","August","September","October","November","December"]}});
|
70
|
+
I18n.translations["en"] = I18n.extend((I18n.translations["en"] || {}), JSON.parse('{"admin":{"edit":{"title":"Edit"},"show":{"note":"more details","title":"Show"}},"date":{"abbr_day_names":["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],"abbr_month_names":[null,"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],"day_names":["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],"formats":{"default":"%Y-%m-%d","long":"%B %d, %Y","short":"%b %d"},"month_names":[null,"January","February","March","April","May","June","July","August","September","October","November","December"]}}'));
|
71
71
|
EOS
|
72
72
|
)
|
73
73
|
fr_output = File.read(File.join(I18n::JS.export_i18n_js_dir_path, "fr.js"))
|
74
74
|
expect(fr_output).to eq(<<EOS
|
75
75
|
I18n.translations || (I18n.translations = {});
|
76
|
-
I18n.translations["fr"] = I18n.extend((I18n.translations["fr"] || {}), {"admin":{"edit":{"title":"Editer"},"show":{"note":"plus de détails","title":"Visualiser"}},"date":{"abbr_day_names":["dim","lun","mar","mer","jeu","ven","sam"],"abbr_month_names":[null,"jan.","fév.","mar.","avr.","mai","juin","juil.","août","sept.","oct.","nov.","déc."],"day_names":["dimanche","lundi","mardi","mercredi","jeudi","vendredi","samedi"],"formats":{"default":"%d/%m/%Y","long":"%e %B %Y","long_ordinal":"%e %B %Y","only_day":"%e","short":"%e %b"},"month_names":[null,"janvier","février","mars","avril","mai","juin","juillet","août","septembre","octobre","novembre","décembre"]}});
|
76
|
+
I18n.translations["fr"] = I18n.extend((I18n.translations["fr"] || {}), JSON.parse('{"admin":{"edit":{"title":"Editer"},"show":{"note":"plus de détails","title":"Visualiser"}},"date":{"abbr_day_names":["dim","lun","mar","mer","jeu","ven","sam"],"abbr_month_names":[null,"jan.","fév.","mar.","avr.","mai","juin","juil.","août","sept.","oct.","nov.","déc."],"day_names":["dimanche","lundi","mardi","mercredi","jeudi","vendredi","samedi"],"formats":{"default":"%d/%m/%Y","long":"%e %B %Y","long_ordinal":"%e %B %Y","only_day":"%e","short":"%e %b"},"month_names":[null,"janvier","février","mars","avril","mai","juin","juillet","août","septembre","octobre","novembre","décembre"]}}'));
|
77
77
|
EOS
|
78
78
|
)
|
79
79
|
end
|
@@ -98,13 +98,13 @@ EOS
|
|
98
98
|
en_output = File.read(File.join(I18n::JS.export_i18n_js_dir_path, "bits.en.js"))
|
99
99
|
expect(en_output).to eq(<<EOS
|
100
100
|
I18n.translations || (I18n.translations = {});
|
101
|
-
I18n.translations["en"] = I18n.extend((I18n.translations["en"] || {}), {"date":{"formats":{"default":"%Y-%m-%d","long":"%B %d, %Y","short":"%b %d"}},"number":{"currency":{"format":{"delimiter":",","format":"%u%n","precision":2,"separator":".","unit":"$"}}}});
|
101
|
+
I18n.translations["en"] = I18n.extend((I18n.translations["en"] || {}), JSON.parse('{"date":{"formats":{"default":"%Y-%m-%d","long":"%B %d, %Y","short":"%b %d"}},"number":{"currency":{"format":{"delimiter":",","format":"%u%n","precision":2,"separator":".","unit":"$"}}}}'));
|
102
102
|
EOS
|
103
103
|
)
|
104
104
|
fr_output = File.read(File.join(I18n::JS.export_i18n_js_dir_path, "bits.fr.js"))
|
105
105
|
expect(fr_output).to eq(<<EOS
|
106
106
|
I18n.translations || (I18n.translations = {});
|
107
|
-
I18n.translations["fr"] = I18n.extend((I18n.translations["fr"] || {}), {"date":{"formats":{"default":"%d/%m/%Y","long":"%e %B %Y","long_ordinal":"%e %B %Y","only_day":"%e","short":"%e %b"}},"number":{"currency":{"format":{"format":"%n %u","precision":2,"unit":"€"}}}});
|
107
|
+
I18n.translations["fr"] = I18n.extend((I18n.translations["fr"] || {}), JSON.parse('{"date":{"formats":{"default":"%d/%m/%Y","long":"%e %B %Y","long_ordinal":"%e %B %Y","only_day":"%e","short":"%e %b"}},"number":{"currency":{"format":{"format":"%n %u","precision":2,"unit":"€"}}}}'));
|
108
108
|
EOS
|
109
109
|
)
|
110
110
|
end
|
@@ -307,21 +307,30 @@ EOS
|
|
307
307
|
expect(subject[:de][:null_test]).to eql(nil)
|
308
308
|
end
|
309
309
|
|
310
|
-
context
|
310
|
+
context 'when given locale is in `I18n.available_locales` but its translation is missing' do
|
311
311
|
subject { translations[:fr][:fallback_test] }
|
312
312
|
|
313
|
-
let(:
|
314
|
-
|
315
|
-
let!(:new_available_locales) { I18n.config.available_locales + [new_locale] }
|
313
|
+
let(:available_locales) { %i[fr pirate] }
|
314
|
+
|
316
315
|
before do
|
317
|
-
I18n.
|
318
|
-
set_config
|
316
|
+
allow(::I18n).to receive(:available_locales).and_return(available_locales)
|
317
|
+
set_config 'js_file_per_locale_with_fallbacks_as_locale_without_fallback_translations.yml'
|
319
318
|
end
|
320
|
-
|
321
|
-
|
319
|
+
|
320
|
+
it { should eql(nil) }
|
321
|
+
end
|
322
|
+
|
323
|
+
context 'when given locale is in `.js_available_locales` but its translation is missing' do
|
324
|
+
subject { translations[:fr][:fallback_test] }
|
325
|
+
|
326
|
+
let(:available_locales) { %i[fr pirate] }
|
327
|
+
|
328
|
+
before do
|
329
|
+
allow(described_class).to receive(:js_available_locales).and_return(available_locales)
|
330
|
+
set_config 'js_file_per_locale_with_fallbacks_as_locale_without_fallback_translations.yml'
|
322
331
|
end
|
323
332
|
|
324
|
-
it {should eql(nil)}
|
333
|
+
it { should eql(nil) }
|
325
334
|
end
|
326
335
|
|
327
336
|
context "with I18n::Fallbacks enabled" do
|
@@ -351,11 +360,11 @@ EOS
|
|
351
360
|
end
|
352
361
|
end
|
353
362
|
|
354
|
-
context "namespace and pretty_print options" do
|
363
|
+
context "namespace, prefix, suffix, and pretty_print options" do
|
355
364
|
|
356
365
|
before do
|
357
366
|
stub_const('I18n::JS::DEFAULT_EXPORT_DIR_PATH', temp_path)
|
358
|
-
set_config "
|
367
|
+
set_config "js_file_with_namespace_prefix_and_pretty_print.yml"
|
359
368
|
end
|
360
369
|
|
361
370
|
it "exports with defined locale as fallback when enabled" do
|
@@ -364,6 +373,7 @@ EOS
|
|
364
373
|
output = File.read(File.join(I18n::JS.export_i18n_js_dir_path, "en.js"))
|
365
374
|
expect(output).to match(/^#{
|
366
375
|
<<EOS
|
376
|
+
import random from 'random-library';
|
367
377
|
Foo.translations || (Foo.translations = {});
|
368
378
|
Foo.translations["en"] = {
|
369
379
|
"number": {
|
@@ -378,32 +388,73 @@ EOS
|
|
378
388
|
"foo": "Foo",
|
379
389
|
"fallback_test": "Success"
|
380
390
|
};
|
391
|
+
//test
|
381
392
|
EOS
|
382
393
|
}$/)
|
383
394
|
end
|
384
395
|
end
|
385
396
|
|
386
|
-
|
397
|
+
describe '.js_available_locales' do
|
398
|
+
subject { described_class.js_available_locales }
|
399
|
+
|
400
|
+
let(:results) { described_class.scoped_translations('*.admin.*.title') }
|
401
|
+
let(:result) { ->(locale) { results[locale][:admin][:show][:title] } }
|
387
402
|
|
388
|
-
context
|
389
|
-
it
|
390
|
-
result = I18n::JS.scoped_translations("*.admin.*.title")
|
403
|
+
context 'when I18n.available_locales is not set' do
|
404
|
+
it { expect(subject).to eq ::I18n.available_locales }
|
391
405
|
|
392
|
-
|
393
|
-
expect(result
|
394
|
-
expect(result
|
406
|
+
it 'should allow all locales' do
|
407
|
+
expect(result.call(:en)).to eql('Show')
|
408
|
+
expect(result.call(:fr)).to eql('Visualiser')
|
409
|
+
expect(result.call(:ja)).to eql('Ignore me')
|
395
410
|
end
|
396
411
|
end
|
397
412
|
|
398
|
-
context
|
399
|
-
|
413
|
+
context 'when I18n.available_locales is set' do
|
414
|
+
let(:available_locales) { %i[en fr] }
|
415
|
+
|
416
|
+
before { allow(::I18n).to receive(:available_locales).and_return(available_locales) }
|
417
|
+
|
418
|
+
it { expect(subject).to eq available_locales }
|
419
|
+
|
420
|
+
it 'should ignore non-valid locales' do
|
421
|
+
expect(result.call(:en)).to eql('Show')
|
422
|
+
expect(result.call(:fr)).to eql('Visualiser')
|
423
|
+
expect(results).not_to include(:ja)
|
424
|
+
end
|
425
|
+
|
426
|
+
context 'when :js_available_locales set in config' do
|
427
|
+
before { set_config 'js_available_locales_custom.yml' }
|
428
|
+
|
429
|
+
it { expect(subject).to eq %i[en foo] }
|
430
|
+
|
431
|
+
it 'should ignore non-valid locales' do
|
432
|
+
expect(result.call(:en)).to eql('Show')
|
433
|
+
expect(results).not_to include(:fr, :ja)
|
434
|
+
end
|
435
|
+
end
|
436
|
+
end
|
437
|
+
end
|
400
438
|
|
401
|
-
|
402
|
-
|
439
|
+
context 'I18n.available_locales' do
|
440
|
+
let(:results) { described_class.scoped_translations('*.admin.*.title') }
|
441
|
+
let(:result) { ->(locale) { results[locale][:admin][:show][:title] } }
|
403
442
|
|
404
|
-
|
405
|
-
|
406
|
-
expect(result.
|
443
|
+
context 'when I18n.available_locales is not set' do
|
444
|
+
it 'should allow all locales' do
|
445
|
+
expect(result.call(:en)).to eql('Show')
|
446
|
+
expect(result.call(:fr)).to eql('Visualiser')
|
447
|
+
expect(result.call(:ja)).to eql('Ignore me')
|
448
|
+
end
|
449
|
+
end
|
450
|
+
|
451
|
+
context 'when I18n.available_locales is set' do
|
452
|
+
before { allow(::I18n).to receive(:available_locales){ [:en, :fr] } }
|
453
|
+
|
454
|
+
it 'should ignore non-valid locales' do
|
455
|
+
expect(result.call(:en)).to eql('Show')
|
456
|
+
expect(result.call(:fr)).to eql('Visualiser')
|
457
|
+
expect(results).not_to include(:ja)
|
407
458
|
end
|
408
459
|
end
|
409
460
|
end
|
@@ -597,7 +648,7 @@ EOS
|
|
597
648
|
it "exports with the keys sorted" do
|
598
649
|
expect(subject).to eq <<EOS
|
599
650
|
I18n.translations || (I18n.translations = {});
|
600
|
-
I18n.translations["en"] = I18n.extend((I18n.translations["en"] || {}), {"admin":{"edit":{"title":"Edit"},"show":{"note":"more details","title":"Show"}},"date":{"abbr_day_names":["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],"abbr_month_names":[null,"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],"day_names":["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],"formats":{"default":"%Y-%m-%d","long":"%B %d, %Y","short":"%b %d"},"month_names":[null,"January","February","March","April","May","June","July","August","September","October","November","December"]},"fallback_test":"Success","foo":"Foo","merge_plurals":{"one":"Apple","other":"Apples"},"null_test":"fallback for null","number":{"currency":{"format":{"delimiter":",","format":"%u%n","precision":2,"separator":".","unit":"$"}},"format":{"delimiter":",","precision":3,"separator":"."}},"time":{"am":"am","formats":{"default":"%a, %d %b %Y %H:%M:%S %z","long":"%B %d, %Y %H:%M","short":"%d %b %H:%M"},"pm":"pm"}});
|
651
|
+
I18n.translations["en"] = I18n.extend((I18n.translations["en"] || {}), JSON.parse('{"admin":{"edit":{"title":"Edit"},"show":{"note":"more details","title":"Show"}},"date":{"abbr_day_names":["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],"abbr_month_names":[null,"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],"day_names":["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],"formats":{"default":"%Y-%m-%d","long":"%B %d, %Y","short":"%b %d"},"month_names":[null,"January","February","March","April","May","June","July","August","September","October","November","December"]},"fallback_test":"Success","foo":"Foo","merge_plurals":{"one":"Apple","other":"Apples"},"merge_plurals_with_no_overrides":{"one":"Apple","other":"Apples","zero":"No Apple"},"merge_plurals_with_partial_overrides":{"one":"Cat","other":"Cats"},"null_test":"fallback for null","number":{"currency":{"format":{"delimiter":",","format":"%u%n","precision":2,"separator":".","unit":"$"}},"format":{"delimiter":",","precision":3,"separator":"."},"human":{"decimal_units":{"units":{"million":"Million"}}}},"time":{"am":"am","formats":{"default":"%a, %d %b %Y %H:%M:%S %z","long":"%B %d, %Y %H:%M","short":"%d %b %H:%M"},"pm":"pm"}}'));
|
601
652
|
EOS
|
602
653
|
end
|
603
654
|
end
|
@@ -609,6 +660,34 @@ EOS
|
|
609
660
|
stub_const('I18n::JS::DEFAULT_EXPORT_DIR_PATH', temp_path)
|
610
661
|
end
|
611
662
|
|
663
|
+
# https://github.com/fnando/i18n-js/issues/553
|
664
|
+
describe "millions" do
|
665
|
+
before do
|
666
|
+
stub_const('I18n::JS::DEFAULT_EXPORT_DIR_PATH', temp_path)
|
667
|
+
end
|
668
|
+
|
669
|
+
subject do
|
670
|
+
File.read(File.join(I18n::JS.export_i18n_js_dir_path, "millions.js"))
|
671
|
+
end
|
672
|
+
|
673
|
+
it "should correctly export millions" do
|
674
|
+
set_config "millions.yml"
|
675
|
+
I18n::JS.export
|
676
|
+
file_should_exist "millions.js"
|
677
|
+
|
678
|
+
expect(subject).to eq <<EOS
|
679
|
+
I18n.translations || (I18n.translations = {});
|
680
|
+
I18n.translations[\"de\"] = I18n.extend((I18n.translations[\"de\"] || {}), JSON.parse('{\"number\":{\"human\":{\"decimal_units\":{\"units\":{\"million\":\"Million\"}}}}}'));
|
681
|
+
I18n.translations[\"en\"] = I18n.extend((I18n.translations[\"en\"] || {}), JSON.parse('{\"number\":{\"human\":{\"decimal_units\":{\"units\":{\"million\":\"Million\"}}}}}'));
|
682
|
+
I18n.translations[\"en-US\"] = I18n.extend((I18n.translations[\"en-US\"] || {}), JSON.parse('{\"number\":{\"human\":{\"decimal_units\":{\"units\":{\"million\":\"Million\"}}}}}'));
|
683
|
+
I18n.translations[\"es\"] = I18n.extend((I18n.translations[\"es\"] || {}), JSON.parse('{\"number\":{\"human\":{\"decimal_units\":{\"units\":{\"million\":{\"one\":\"millón\",\"other\":\"millones\"}}}}}}'));
|
684
|
+
I18n.translations[\"fr\"] = I18n.extend((I18n.translations[\"fr\"] || {}), JSON.parse('{\"number\":{\"human\":{\"decimal_units\":{\"units\":{\"million\":\"Million\"}}}}}'));
|
685
|
+
I18n.translations[\"ja\"] = I18n.extend((I18n.translations[\"ja\"] || {}), JSON.parse('{\"number\":{\"human\":{\"decimal_units\":{\"units\":{\"million\":\"Million\"}}}}}'));
|
686
|
+
I18n.translations[\"ru\"] = I18n.extend((I18n.translations[\"ru\"] || {}), JSON.parse('{\"number\":{\"human\":{\"decimal_units\":{\"units\":{\"million\":\"Million\"}}}}}'));
|
687
|
+
EOS
|
688
|
+
end
|
689
|
+
end
|
690
|
+
|
612
691
|
it "exports with js_extend option at parent level" do
|
613
692
|
set_config "js_extend_parent.yml"
|
614
693
|
I18n::JS.export
|
@@ -618,8 +697,8 @@ EOS
|
|
618
697
|
output = File.read(File.join(I18n::JS.export_i18n_js_dir_path, "js_extend_parent.js"))
|
619
698
|
expect(output).to eq(<<EOS
|
620
699
|
I18n.translations || (I18n.translations = {});
|
621
|
-
I18n.translations[\"en\"] = {\"date\":{\"formats\":{\"default\":\"%Y-%m-%d\",\"long\":\"%B %d, %Y\",\"short\":\"%b %d\"}}};
|
622
|
-
I18n.translations[\"fr\"] = {\"date\":{\"formats\":{\"default\":\"%d/%m/%Y\",\"long\":\"%e %B %Y\",\"long_ordinal\":\"%e %B %Y\",\"only_day\":\"%e\",\"short\":\"%e %b\"}}};
|
700
|
+
I18n.translations[\"en\"] = JSON.parse('{\"date\":{\"formats\":{\"default\":\"%Y-%m-%d\",\"long\":\"%B %d, %Y\",\"short\":\"%b %d\"}}}');
|
701
|
+
I18n.translations[\"fr\"] = JSON.parse('{\"date\":{\"formats\":{\"default\":\"%d/%m/%Y\",\"long\":\"%e %B %Y\",\"long_ordinal\":\"%e %B %Y\",\"only_day\":\"%e\",\"short\":\"%e %b\"}}}');
|
623
702
|
EOS
|
624
703
|
)
|
625
704
|
end
|
@@ -633,8 +712,8 @@ EOS
|
|
633
712
|
output = File.read(File.join(I18n::JS.export_i18n_js_dir_path, "js_extend_segment.js"))
|
634
713
|
expect(output).to eq(<<EOS
|
635
714
|
I18n.translations || (I18n.translations = {});
|
636
|
-
I18n.translations[\"en\"] = {\"date\":{\"formats\":{\"default\":\"%Y-%m-%d\",\"long\":\"%B %d, %Y\",\"short\":\"%b %d\"}}};
|
637
|
-
I18n.translations[\"fr\"] = {\"date\":{\"formats\":{\"default\":\"%d/%m/%Y\",\"long\":\"%e %B %Y\",\"long_ordinal\":\"%e %B %Y\",\"only_day\":\"%e\",\"short\":\"%e %b\"}}};
|
715
|
+
I18n.translations[\"en\"] = JSON.parse('{\"date\":{\"formats\":{\"default\":\"%Y-%m-%d\",\"long\":\"%B %d, %Y\",\"short\":\"%b %d\"}}}');
|
716
|
+
I18n.translations[\"fr\"] = JSON.parse('{\"date\":{\"formats\":{\"default\":\"%d/%m/%Y\",\"long\":\"%e %B %Y\",\"long_ordinal\":\"%e %B %Y\",\"only_day\":\"%e\",\"short\":\"%e %b\"}}}');
|
638
717
|
EOS
|
639
718
|
)
|
640
719
|
end
|
@@ -656,7 +735,62 @@ EOS
|
|
656
735
|
|
657
736
|
expect(subject).to eq <<EOS
|
658
737
|
I18n.translations || (I18n.translations = {});
|
659
|
-
I18n.translations[\"en\"] = I18n.extend((I18n.translations[\"en\"] || {}), {\"merge_plurals\":{\"one\":\"Apple\",\"other\":\"Apples\"}});\nI18n.translations[\"fr\"] = I18n.extend((I18n.translations[\"fr\"] || {}), {\"merge_plurals\":{\"one\":\"Pomme\",\"other\":\"Pommes\",\"zero\":\"Pomme\"}});
|
738
|
+
I18n.translations[\"en\"] = I18n.extend((I18n.translations[\"en\"] || {}), JSON.parse('{\"merge_plurals\":{\"one\":\"Apple\",\"other\":\"Apples\"}}'));\nI18n.translations[\"fr\"] = I18n.extend((I18n.translations[\"fr\"] || {}), JSON.parse('{\"merge_plurals\":{\"one\":\"Pomme\",\"other\":\"Pommes\",\"zero\":\"Pomme\"}}'));
|
739
|
+
EOS
|
740
|
+
end
|
741
|
+
end
|
742
|
+
|
743
|
+
describe "merging plural keys, with fallbacks" do
|
744
|
+
before do
|
745
|
+
stub_const('I18n::JS::DEFAULT_EXPORT_DIR_PATH', temp_path)
|
746
|
+
end
|
747
|
+
|
748
|
+
subject do
|
749
|
+
File.read(File.join(I18n::JS.export_i18n_js_dir_path, "merge_plurals_with_no_overrides.js"))
|
750
|
+
end
|
751
|
+
|
752
|
+
it "should correctly merge the plural keys" do
|
753
|
+
set_config "merge_plurals_with_no_overrides.yml"
|
754
|
+
I18n::JS.export
|
755
|
+
file_should_exist "merge_plurals_with_no_overrides.js"
|
756
|
+
|
757
|
+
expect(subject).to eq <<EOS
|
758
|
+
I18n.translations || (I18n.translations = {});
|
759
|
+
I18n.translations[\"de\"] = I18n.extend((I18n.translations[\"de\"] || {}), JSON.parse('{\"merge_plurals_with_no_overrides\":{\"one\":\"Apple\",\"other\":\"Apples\",\"zero\":\"No Apple\"}}'));
|
760
|
+
I18n.translations[\"en\"] = I18n.extend((I18n.translations[\"en\"] || {}), JSON.parse('{\"merge_plurals_with_no_overrides\":{\"one\":\"Apple\",\"other\":\"Apples\",\"zero\":\"No Apple\"}}'));
|
761
|
+
I18n.translations[\"en-US\"] = I18n.extend((I18n.translations[\"en-US\"] || {}), JSON.parse('{\"merge_plurals_with_no_overrides\":{\"one\":\"Apple\",\"other\":\"Apples\",\"zero\":\"No Apple\"}}'));
|
762
|
+
I18n.translations[\"es\"] = I18n.extend((I18n.translations[\"es\"] || {}), JSON.parse('{\"merge_plurals_with_no_overrides\":{\"one\":\"Apple\",\"other\":\"Apples\",\"zero\":\"No Apple\"}}'));
|
763
|
+
I18n.translations[\"fr\"] = I18n.extend((I18n.translations[\"fr\"] || {}), JSON.parse('{\"merge_plurals_with_no_overrides\":{\"one\":\"Apple\",\"other\":\"Apples\",\"zero\":\"No Apple\"}}'));
|
764
|
+
I18n.translations[\"ja\"] = I18n.extend((I18n.translations[\"ja\"] || {}), JSON.parse('{\"merge_plurals_with_no_overrides\":{\"one\":\"Apple\",\"other\":\"Apples\",\"zero\":\"No Apple\"}}'));
|
765
|
+
I18n.translations[\"ru\"] = I18n.extend((I18n.translations[\"ru\"] || {}), JSON.parse('{\"merge_plurals_with_no_overrides\":{\"few\":\"кошек\",\"many\":\"кошка\",\"one\":\"кот\",\"other\":\"кошек\"}}'));
|
766
|
+
EOS
|
767
|
+
end
|
768
|
+
end
|
769
|
+
|
770
|
+
# see discussion @ https://github.com/fnando/i18n-js/pull/551#issuecomment-543205767
|
771
|
+
describe "merging plural keys, with fallbacks, with partial overrides" do
|
772
|
+
before do
|
773
|
+
stub_const('I18n::JS::DEFAULT_EXPORT_DIR_PATH', temp_path)
|
774
|
+
end
|
775
|
+
|
776
|
+
subject do
|
777
|
+
File.read(File.join(I18n::JS.export_i18n_js_dir_path, "merge_plurals_with_partial_overrides.js"))
|
778
|
+
end
|
779
|
+
|
780
|
+
it "should correctly merge the plural keys" do
|
781
|
+
set_config "merge_plurals_with_partial_overrides.yml"
|
782
|
+
I18n::JS.export
|
783
|
+
file_should_exist "merge_plurals_with_partial_overrides.js"
|
784
|
+
|
785
|
+
expect(subject).to eq <<EOS
|
786
|
+
I18n.translations || (I18n.translations = {});
|
787
|
+
I18n.translations[\"de\"] = I18n.extend((I18n.translations[\"de\"] || {}), JSON.parse('{\"merge_plurals_with_partial_overrides\":{\"one\":\"Cat\",\"other\":\"Cats\"}}'));
|
788
|
+
I18n.translations[\"en\"] = I18n.extend((I18n.translations[\"en\"] || {}), JSON.parse('{\"merge_plurals_with_partial_overrides\":{\"one\":\"Cat\",\"other\":\"Cats\"}}'));
|
789
|
+
I18n.translations[\"en-US\"] = I18n.extend((I18n.translations[\"en-US\"] || {}), JSON.parse('{\"merge_plurals_with_partial_overrides\":{\"few\":null,\"many\":null,\"one\":\"Cat\",\"other\":\"Cats\"}}'));
|
790
|
+
I18n.translations[\"es\"] = I18n.extend((I18n.translations[\"es\"] || {}), JSON.parse('{\"merge_plurals_with_partial_overrides\":{\"one\":\"Cat\",\"other\":\"Cats\"}}'));
|
791
|
+
I18n.translations[\"fr\"] = I18n.extend((I18n.translations[\"fr\"] || {}), JSON.parse('{\"merge_plurals_with_partial_overrides\":{\"one\":\"Cat\",\"other\":\"Cats\"}}'));
|
792
|
+
I18n.translations[\"ja\"] = I18n.extend((I18n.translations[\"ja\"] || {}), JSON.parse('{\"merge_plurals_with_partial_overrides\":{\"one\":\"Cat\",\"other\":\"Cats\"}}'));
|
793
|
+
I18n.translations[\"ru\"] = I18n.extend((I18n.translations[\"ru\"] || {}), JSON.parse('{\"merge_plurals_with_partial_overrides\":{\"one\":\"Cat\",\"other\":\"Cats\"}}'));
|
660
794
|
EOS
|
661
795
|
end
|
662
796
|
end
|