Skip to content
This repository has been archived by the owner on Sep 11, 2024. It is now read-only.

fallback properly with pluralized strings #7495

Merged
merged 1 commit into from
Jan 10, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions src/languageHandler.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ counterpart.setSeparator('|');

// see `translateWithFallback` for an explanation of fallback handling
const FALLBACK_LOCALE = 'en';
counterpart.setFallbackLocale(FALLBACK_LOCALE);

interface ITranslatableError extends Error {
translatedMessage: string;
Expand Down Expand Up @@ -79,12 +80,12 @@ export function _td(s: string): string { // eslint-disable-line @typescript-esli
* should be wrapped with an appropriate `lang='en'` attribute
* counterpart's `translate` doesn't expose a way to determine if the resulting translation
* 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
* */
const translateWithFallback = (text: string, options?: object): { translated?: string, isFallback?: boolean } => {
const translated = counterpart.translate(text, options);
if (/^missing translation:/.test(translated)) {
const translated = counterpart.translate(text, { ...options, fallbackLocale: counterpart.getLocale() });
if (!translated || /^missing translation:/.test(translated)) {
const fallbackTranslated = counterpart.translate(text, { ...options, locale: FALLBACK_LOCALE });
return { translated: fallbackTranslated, isFallback: true };
}
Expand Down
90 changes: 66 additions & 24 deletions test/i18n-test/languageHandler-test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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 () => {
stubClient();
await setLanguage('lv');
Expand All @@ -130,33 +130,75 @@ describe('languageHandler', function() {
setMissingEntryGenerator(counterpartDefaultMissingEntryGen);
});

// mocked lv has only `"Uploading %(filename)s and %(count)s others|one"`
const lvExistingPlural = 'Uploading %(filename)s and %(count)s others';
const lvNonExistingPlural = '%(spaceName)s and %(count)s others';

// lv does not have a pluralizer function
const noPluralizerCase = [
'handles plural strings when no pluralizer exists for language',
lvExistingPlural,
{ count: 1, filename: 'test.txt' },
undefined,
'Uploading test.txt and 1 other',
] as TestCase;

describe('_t', () => {
it.each([...testCasesEn, noPluralizerCase])(
"%s and translates with fallback locale",
async (_d, translationString, variables, tags, result) => {
expect(_t(translationString, variables, tags)).toEqual(result);
},
);
describe('pluralization', () => {
const pluralCases = [
[
'falls back when plural string exists but not for for count',
lvExistingPlural,
{ count: 2, filename: 'test.txt' },
undefined,
'Uploading test.txt and 2 others',
],
[
'falls back when plural string does not exists at all',
lvNonExistingPlural,
{ count: 2, spaceName: 'test' },
undefined,
'test and 2 others',
],
] as TestCase[];

describe('_t', () => {
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('_tDom()', () => {
it.each([...testCasesEn, noPluralizerCase])(
"%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",
async (_d, translationString, variables, tags, result) => {
expect(_t(translationString, variables, tags)).toEqual(result);
},
);
});

describe('_tDom()', () => {
it.each(testCasesEn)(
"%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>);
},
);
});
});
});
});