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

Commit 5cfb046

Browse files
author
Kerry
authored
fallback properly with pluralized strings (#7495)
Signed-off-by: Kerry Archibald <kerrya@element.io>
1 parent 3680859 commit 5cfb046

File tree

2 files changed

+70
-27
lines changed

2 files changed

+70
-27
lines changed

src/languageHandler.tsx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ counterpart.setSeparator('|');
4141

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

4546
interface ITranslatableError extends Error {
4647
translatedMessage: string;
@@ -79,12 +80,12 @@ export function _td(s: string): string { // eslint-disable-line @typescript-esli
7980
* should be wrapped with an appropriate `lang='en'` attribute
8081
* counterpart's `translate` doesn't expose a way to determine if the resulting translation
8182
* is in the target locale or a fallback locale
82-
* for this reason, we do not set a fallback via `counterpart.setFallbackLocale`
83+
* for this reason, force fallbackLocale === locale in the first call to translate
8384
* and fallback 'manually' so we can mark fallback strings appropriately
8485
* */
8586
const translateWithFallback = (text: string, options?: object): { translated?: string, isFallback?: boolean } => {
86-
const translated = counterpart.translate(text, options);
87-
if (/^missing translation:/.test(translated)) {
87+
const translated = counterpart.translate(text, { ...options, fallbackLocale: counterpart.getLocale() });
88+
if (!translated || /^missing translation:/.test(translated)) {
8889
const fallbackTranslated = counterpart.translate(text, { ...options, locale: FALLBACK_LOCALE });
8990
return { translated: fallbackTranslated, isFallback: true };
9091
}

test/i18n-test/languageHandler-test.tsx

Lines changed: 66 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ describe('languageHandler', function() {
118118
});
119119
});
120120

121-
describe('when a translation string does not exist in active language', () => {
121+
describe('for a non-en language', () => {
122122
beforeEach(async () => {
123123
stubClient();
124124
await setLanguage('lv');
@@ -130,33 +130,75 @@ describe('languageHandler', function() {
130130
setMissingEntryGenerator(counterpartDefaultMissingEntryGen);
131131
});
132132

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

135-
// lv does not have a pluralizer function
136-
const noPluralizerCase = [
137-
'handles plural strings when no pluralizer exists for language',
138-
lvExistingPlural,
139-
{ count: 1, filename: 'test.txt' },
140-
undefined,
141-
'Uploading test.txt and 1 other',
142-
] as TestCase;
143-
144-
describe('_t', () => {
145-
it.each([...testCasesEn, noPluralizerCase])(
146-
"%s and translates with fallback locale",
147-
async (_d, translationString, variables, tags, result) => {
148-
expect(_t(translationString, variables, tags)).toEqual(result);
149-
},
150-
);
137+
describe('pluralization', () => {
138+
const pluralCases = [
139+
[
140+
'falls back when plural string exists but not for for count',
141+
lvExistingPlural,
142+
{ count: 2, filename: 'test.txt' },
143+
undefined,
144+
'Uploading test.txt and 2 others',
145+
],
146+
[
147+
'falls back when plural string does not exists at all',
148+
lvNonExistingPlural,
149+
{ count: 2, spaceName: 'test' },
150+
undefined,
151+
'test and 2 others',
152+
],
153+
] as TestCase[];
154+
155+
describe('_t', () => {
156+
it('translated correctly when plural string exists for count', () => {
157+
expect(_t(
158+
lvExistingPlural,
159+
{ count: 1, filename: 'test.txt' }, undefined)).toEqual('Качване на test.txt и 1 друг');
160+
});
161+
it.each(pluralCases)(
162+
"%s",
163+
async (_d, translationString, variables, tags, result) => {
164+
expect(_t(translationString, variables, tags)).toEqual(result);
165+
},
166+
);
167+
});
168+
169+
describe('_tDom()', () => {
170+
it('translated correctly when plural string exists for count', () => {
171+
expect(_tDom(
172+
lvExistingPlural,
173+
{ count: 1, filename: 'test.txt' }, undefined)).toEqual('Качване на test.txt и 1 друг');
174+
});
175+
it.each(pluralCases)(
176+
"%s and translates with fallback locale, attributes fallback locale",
177+
async (_d, translationString, variables, tags, result) => {
178+
expect(_tDom(translationString, variables, tags)).toEqual(<span lang="en">{ result }</span>);
179+
},
180+
);
181+
});
151182
});
152183

153-
describe('_tDom()', () => {
154-
it.each([...testCasesEn, noPluralizerCase])(
155-
"%s and translates with fallback locale, attributes fallback locale",
156-
async (_d, translationString, variables, tags, result) => {
157-
expect(_tDom(translationString, variables, tags)).toEqual(<span lang="en">{ result }</span>);
158-
},
159-
);
184+
describe('when a translation string does not exist in active language', () => {
185+
describe('_t', () => {
186+
it.each(testCasesEn)(
187+
"%s and translates with fallback locale",
188+
async (_d, translationString, variables, tags, result) => {
189+
expect(_t(translationString, variables, tags)).toEqual(result);
190+
},
191+
);
192+
});
193+
194+
describe('_tDom()', () => {
195+
it.each(testCasesEn)(
196+
"%s and translates with fallback locale, attributes fallback locale",
197+
async (_d, translationString, variables, tags, result) => {
198+
expect(_tDom(translationString, variables, tags)).toEqual(<span lang="en">{ result }</span>);
199+
},
200+
);
201+
});
160202
});
161203
});
162204
});

0 commit comments

Comments
 (0)