Skip to content

Commit 6fbd01d

Browse files
Fix ICU message format not supported for fallback locale (#378)
1 parent 9fc1cb9 commit 6fbd01d

2 files changed

Lines changed: 95 additions & 0 deletions

File tree

Resources/js/translator.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -321,11 +321,19 @@
321321

322322
_locale = _locale.substring(0, _length - (_lastLength + 1));
323323

324+
if (has_message(_locale, _domain + INTL_DOMAIN_SUFFIX, id)) {
325+
_additionalReturn.isICU = true;
326+
return _messages[_locale][_domain + INTL_DOMAIN_SUFFIX][id];
327+
}
324328
if (has_message(_locale, _domain, id)) {
325329
return _messages[_locale][_domain][id];
326330
}
327331
}
328332

333+
if (has_message(localeFallback, _domain + INTL_DOMAIN_SUFFIX, id)) {
334+
_additionalReturn.isICU = true;
335+
return _messages[localeFallback][_domain + INTL_DOMAIN_SUFFIX][id];
336+
}
329337
if (has_message(localeFallback, _domain, id)) {
330338
return _messages[localeFallback][_domain][id];
331339
}

Resources/js/translatorTest.js

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -314,3 +314,90 @@ QUnit.test('searches in country fallback, if not exists in full domain', functio
314314
Translator.locale = 'de_CH';
315315
assert.equal(Translator.trans('symfony2.great'), 'Symfony2 ist groß');
316316
});
317+
318+
319+
QUnit.module('ICU MessageFormat with locale fallback', hooks => {
320+
hooks.beforeEach(() => {
321+
Translator.reset();
322+
Translator.locale = 'nl';
323+
Translator.fallback = 'en';
324+
});
325+
326+
QUnit.test('should use ICU format from the global fallback locale when current locale has no translation', assert => {
327+
Translator.add('hello_name', 'Hello {name}!', 'messages+intl-icu', 'en');
328+
329+
assert.strictEqual(Translator.trans('hello_name', { name: 'John' }, 'messages'), 'Hello John!');
330+
});
331+
332+
QUnit.test('should use ICU plural format from the global fallback locale', assert => {
333+
Translator.add(
334+
'apples',
335+
'{count, plural, =0 {no apples} one {one apple} other {# apples}}',
336+
'messages+intl-icu',
337+
'en'
338+
);
339+
340+
assert.strictEqual(Translator.trans('apples', { count: 0 }, 'messages'), 'no apples');
341+
assert.strictEqual(Translator.trans('apples', { count: 1 }, 'messages'), 'one apple');
342+
assert.strictEqual(Translator.trans('apples', { count: 5 }, 'messages'), '5 apples');
343+
});
344+
345+
QUnit.test('should prefer current locale ICU translation over fallback locale ICU translation', assert => {
346+
Translator.add('hello_name', 'Hello {name}!', 'messages+intl-icu', 'en');
347+
Translator.add('hello_name', 'Hallo {name}!', 'messages+intl-icu', 'nl');
348+
349+
assert.strictEqual(Translator.trans('hello_name', { name: 'John' }, 'messages'), 'Hallo John!');
350+
});
351+
352+
QUnit.test('should fall back to plain (non-ICU) translation in the fallback locale', assert => {
353+
// Regression: existing plain-domain fallback should still work unchanged
354+
Translator.add('simple_key', 'Hello!', 'messages', 'en');
355+
356+
assert.strictEqual(Translator.trans('simple_key', {}, 'messages'), 'Hello!');
357+
});
358+
359+
QUnit.test('should prefer current locale plain translation over fallback locale ICU translation', assert => {
360+
Translator.add('hello_name', 'Hello {name}!', 'messages+intl-icu', 'en');
361+
Translator.add('hello_name', 'Hallo %name%!', 'messages', 'nl');
362+
363+
assert.strictEqual(Translator.trans('hello_name', { name: 'John' }, 'messages'), 'Hallo John!');
364+
});
365+
});
366+
367+
QUnit.module('ICU MessageFormat with sub-locale fallback (nl_NL -> nl -> en)', hooks => {
368+
hooks.beforeEach(() => {
369+
Translator.reset();
370+
Translator.locale = 'nl_NL';
371+
Translator.fallback = 'en';
372+
});
373+
374+
QUnit.test('should use ICU format from parent locale (nl) when nl_NL has no translation', assert => {
375+
Translator.add('hello_name', 'Hallo {name}!', 'messages+intl-icu', 'nl');
376+
377+
assert.strictEqual(Translator.trans('hello_name', { name: 'Jan' }, 'messages'), 'Hallo Jan!');
378+
});
379+
380+
QUnit.test('should use ICU format from global fallback (en) when both nl_NL and nl have no translation', assert => {
381+
Translator.add('hello_name', 'Hello {name}!', 'messages+intl-icu', 'en');
382+
383+
assert.strictEqual(Translator.trans('hello_name', { name: 'Jan' }, 'messages'), 'Hello Jan!');
384+
});
385+
386+
QUnit.test('should prefer nl_NL ICU translation over nl ICU translation', assert => {
387+
Translator.add('hello_name', 'Hallo {name}!', 'messages+intl-icu', 'nl');
388+
Translator.add('hello_name', 'Hallo {name} uit NL!', 'messages+intl-icu', 'nl_NL');
389+
390+
assert.strictEqual(Translator.trans('hello_name', { name: 'Jan' }, 'messages'), 'Hallo Jan uit NL!');
391+
});
392+
393+
QUnit.test('should use ICU plural format from global fallback when no locale-specific translation exists', assert => {
394+
Translator.add(
395+
'apples',
396+
'{count, plural, =0 {no apples} one {one apple} other {# apples}}',
397+
'messages+intl-icu',
398+
'en'
399+
);
400+
401+
assert.strictEqual(Translator.trans('apples', { count: 3 }, 'messages'), '3 apples');
402+
});
403+
});

0 commit comments

Comments
 (0)