From d4250918cf7673a6f01a6e95e27833ea5ce21ec5 Mon Sep 17 00:00:00 2001 From: Kerry Date: Fri, 7 Jan 2022 16:20:24 +0100 Subject: [PATCH] fix fallback for pluralized strings (#7480) * fix fallback for pluralized cases Signed-off-by: Kerry Archibald * add test case for no pluralizer Signed-off-by: Kerry Archibald --- __mocks__/browser-request.js | 1 + src/languageHandler.tsx | 3 +-- test/i18n-test/languageHandler-test.tsx | 22 ++++++++++++++++++++-- 3 files changed, 22 insertions(+), 4 deletions(-) diff --git a/__mocks__/browser-request.js b/__mocks__/browser-request.js index 7e26849f28a..aa9c7102998 100644 --- a/__mocks__/browser-request.js +++ b/__mocks__/browser-request.js @@ -2,6 +2,7 @@ const en = require("../src/i18n/strings/en_EN"); const de = require("../src/i18n/strings/de_DE"); const lv = { "Save": "Saglabāt", + "Uploading %(filename)s and %(count)s others|one": "Качване на %(filename)s и %(count)s друг", }; // Mock the browser-request for the languageHandler tests to return diff --git a/src/languageHandler.tsx b/src/languageHandler.tsx index 36c1fd6c0af..7e4fc095e2a 100644 --- a/src/languageHandler.tsx +++ b/src/languageHandler.tsx @@ -85,7 +85,7 @@ export function _td(s: string): string { // eslint-disable-line @typescript-esli const translateWithFallback = (text: string, options?: object): { translated?: string, isFallback?: boolean } => { const translated = counterpart.translate(text, options); if (/^missing translation:/.test(translated)) { - const fallbackTranslated = counterpart.translate(text, { ...options, fallbackLocale: FALLBACK_LOCALE }); + const fallbackTranslated = counterpart.translate(text, { ...options, locale: FALLBACK_LOCALE }); return { translated: fallbackTranslated, isFallback: true }; } return { translated }; @@ -168,7 +168,6 @@ export function _t(text: string, variables: IVariables, tags: Tags): React.React export function _t(text: string, variables?: IVariables, tags?: Tags): TranslatedString { // The translation returns text so there's no XSS vector here (no unsafe HTML, no code execution) const { translated } = safeCounterpartTranslate(text, variables); - const substituted = substitute(translated, variables, tags); return annotateStrings(substituted, text); diff --git a/test/i18n-test/languageHandler-test.tsx b/test/i18n-test/languageHandler-test.tsx index c07b5543c04..668ff5ba1b9 100644 --- a/test/i18n-test/languageHandler-test.tsx +++ b/test/i18n-test/languageHandler-test.tsx @@ -20,6 +20,13 @@ describe('languageHandler', function() { type TestCase = [string, string, Record, Record, TranslatedString]; const testCasesEn: TestCase[] = [ ['translates a basic string', basicString, {}, undefined, 'Rooms'], + [ + 'handles plurals when count is 0', + plurals, + { count: 0 }, + undefined, + 'and 0 others...', + ], [ 'handles plurals when count is 1', plurals, @@ -123,8 +130,19 @@ describe('languageHandler', function() { setMissingEntryGenerator(counterpartDefaultMissingEntryGen); }); + const lvExistingPlural = 'Uploading %(filename)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)( + it.each([...testCasesEn, noPluralizerCase])( "%s and translates with fallback locale", async (_d, translationString, variables, tags, result) => { expect(_t(translationString, variables, tags)).toEqual(result); @@ -133,7 +151,7 @@ describe('languageHandler', function() { }); describe('_tDom()', () => { - it.each(testCasesEn)( + 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({ result });