fallback properly with pluralized strings (#7495)
Signed-off-by: Kerry Archibald <kerrya@element.io>
This commit is contained in:
parent
368085982f
commit
5cfb046816
2 changed files with 69 additions and 26 deletions
|
@ -41,6 +41,7 @@ counterpart.setSeparator('|');
|
||||||
|
|
||||||
// see `translateWithFallback` for an explanation of fallback handling
|
// see `translateWithFallback` for an explanation of fallback handling
|
||||||
const FALLBACK_LOCALE = 'en';
|
const FALLBACK_LOCALE = 'en';
|
||||||
|
counterpart.setFallbackLocale(FALLBACK_LOCALE);
|
||||||
|
|
||||||
interface ITranslatableError extends Error {
|
interface ITranslatableError extends Error {
|
||||||
translatedMessage: string;
|
translatedMessage: string;
|
||||||
|
@ -79,12 +80,12 @@ export function _td(s: string): string { // eslint-disable-line @typescript-esli
|
||||||
* should be wrapped with an appropriate `lang='en'` attribute
|
* should be wrapped with an appropriate `lang='en'` attribute
|
||||||
* counterpart's `translate` doesn't expose a way to determine if the resulting translation
|
* counterpart's `translate` doesn't expose a way to determine if the resulting translation
|
||||||
* is in the target locale or a fallback locale
|
* is in the target locale or a fallback locale
|
||||||
* for this reason, we do not set a fallback via `counterpart.setFallbackLocale`
|
* for this reason, force fallbackLocale === locale in the first call to translate
|
||||||
* and fallback 'manually' so we can mark fallback strings appropriately
|
* and fallback 'manually' so we can mark fallback strings appropriately
|
||||||
* */
|
* */
|
||||||
const translateWithFallback = (text: string, options?: object): { translated?: string, isFallback?: boolean } => {
|
const translateWithFallback = (text: string, options?: object): { translated?: string, isFallback?: boolean } => {
|
||||||
const translated = counterpart.translate(text, options);
|
const translated = counterpart.translate(text, { ...options, fallbackLocale: counterpart.getLocale() });
|
||||||
if (/^missing translation:/.test(translated)) {
|
if (!translated || /^missing translation:/.test(translated)) {
|
||||||
const fallbackTranslated = counterpart.translate(text, { ...options, locale: FALLBACK_LOCALE });
|
const fallbackTranslated = counterpart.translate(text, { ...options, locale: FALLBACK_LOCALE });
|
||||||
return { translated: fallbackTranslated, isFallback: true };
|
return { translated: fallbackTranslated, isFallback: true };
|
||||||
}
|
}
|
||||||
|
|
|
@ -118,7 +118,7 @@ describe('languageHandler', function() {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('when a translation string does not exist in active language', () => {
|
describe('for a non-en language', () => {
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
stubClient();
|
stubClient();
|
||||||
await setLanguage('lv');
|
await setLanguage('lv');
|
||||||
|
@ -130,19 +130,60 @@ describe('languageHandler', function() {
|
||||||
setMissingEntryGenerator(counterpartDefaultMissingEntryGen);
|
setMissingEntryGenerator(counterpartDefaultMissingEntryGen);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// mocked lv has only `"Uploading %(filename)s and %(count)s others|one"`
|
||||||
const lvExistingPlural = 'Uploading %(filename)s and %(count)s others';
|
const lvExistingPlural = 'Uploading %(filename)s and %(count)s others';
|
||||||
|
const lvNonExistingPlural = '%(spaceName)s and %(count)s others';
|
||||||
|
|
||||||
// lv does not have a pluralizer function
|
describe('pluralization', () => {
|
||||||
const noPluralizerCase = [
|
const pluralCases = [
|
||||||
'handles plural strings when no pluralizer exists for language',
|
[
|
||||||
|
'falls back when plural string exists but not for for count',
|
||||||
lvExistingPlural,
|
lvExistingPlural,
|
||||||
{ count: 1, filename: 'test.txt' },
|
{ count: 2, filename: 'test.txt' },
|
||||||
undefined,
|
undefined,
|
||||||
'Uploading test.txt and 1 other',
|
'Uploading test.txt and 2 others',
|
||||||
] as TestCase;
|
],
|
||||||
|
[
|
||||||
|
'falls back when plural string does not exists at all',
|
||||||
|
lvNonExistingPlural,
|
||||||
|
{ count: 2, spaceName: 'test' },
|
||||||
|
undefined,
|
||||||
|
'test and 2 others',
|
||||||
|
],
|
||||||
|
] as TestCase[];
|
||||||
|
|
||||||
describe('_t', () => {
|
describe('_t', () => {
|
||||||
it.each([...testCasesEn, noPluralizerCase])(
|
it('translated correctly when plural string exists for count', () => {
|
||||||
|
expect(_t(
|
||||||
|
lvExistingPlural,
|
||||||
|
{ count: 1, filename: 'test.txt' }, undefined)).toEqual('Качване на test.txt и 1 друг');
|
||||||
|
});
|
||||||
|
it.each(pluralCases)(
|
||||||
|
"%s",
|
||||||
|
async (_d, translationString, variables, tags, result) => {
|
||||||
|
expect(_t(translationString, variables, tags)).toEqual(result);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('_tDom()', () => {
|
||||||
|
it('translated correctly when plural string exists for count', () => {
|
||||||
|
expect(_tDom(
|
||||||
|
lvExistingPlural,
|
||||||
|
{ count: 1, filename: 'test.txt' }, undefined)).toEqual('Качване на test.txt и 1 друг');
|
||||||
|
});
|
||||||
|
it.each(pluralCases)(
|
||||||
|
"%s and translates with fallback locale, attributes fallback locale",
|
||||||
|
async (_d, translationString, variables, tags, result) => {
|
||||||
|
expect(_tDom(translationString, variables, tags)).toEqual(<span lang="en">{ result }</span>);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('when a translation string does not exist in active language', () => {
|
||||||
|
describe('_t', () => {
|
||||||
|
it.each(testCasesEn)(
|
||||||
"%s and translates with fallback locale",
|
"%s and translates with fallback locale",
|
||||||
async (_d, translationString, variables, tags, result) => {
|
async (_d, translationString, variables, tags, result) => {
|
||||||
expect(_t(translationString, variables, tags)).toEqual(result);
|
expect(_t(translationString, variables, tags)).toEqual(result);
|
||||||
|
@ -151,7 +192,7 @@ describe('languageHandler', function() {
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('_tDom()', () => {
|
describe('_tDom()', () => {
|
||||||
it.each([...testCasesEn, noPluralizerCase])(
|
it.each(testCasesEn)(
|
||||||
"%s and translates with fallback locale, attributes fallback locale",
|
"%s and translates with fallback locale, attributes fallback locale",
|
||||||
async (_d, translationString, variables, tags, result) => {
|
async (_d, translationString, variables, tags, result) => {
|
||||||
expect(_tDom(translationString, variables, tags)).toEqual(<span lang="en">{ result }</span>);
|
expect(_tDom(translationString, variables, tags)).toEqual(<span lang="en">{ result }</span>);
|
||||||
|
@ -160,3 +201,4 @@ describe('languageHandler', function() {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|
Loading…
Reference in a new issue