From 2dbf9d5b7e4491742633ddd6a7deca75aed52c02 Mon Sep 17 00:00:00 2001 From: Shubham Agrawal Date: Sun, 1 Jun 2025 16:31:30 +0530 Subject: [PATCH 1/3] Removed legacy es-ES code and fallback language code --- src/languages/es-ES.ts | 3 --- src/languages/translations.ts | 3 --- src/libs/Localize/index.ts | 34 +++++------------------- tests/unit/TranslateTest.ts | 49 ++++++++++------------------------- 4 files changed, 20 insertions(+), 69 deletions(-) delete mode 100644 src/languages/es-ES.ts diff --git a/src/languages/es-ES.ts b/src/languages/es-ES.ts deleted file mode 100644 index 57a8c09afd3a..000000000000 --- a/src/languages/es-ES.ts +++ /dev/null @@ -1,3 +0,0 @@ -export default { - phoneCountryCode: '34', -}; diff --git a/src/languages/translations.ts b/src/languages/translations.ts index ec99d999f94e..9be57805cf04 100644 --- a/src/languages/translations.ts +++ b/src/languages/translations.ts @@ -1,6 +1,5 @@ import en from './en'; import es from './es'; -import esES from './es-ES'; import type {FlatTranslationsObject, TranslationDeepObject} from './types'; /** @@ -45,6 +44,4 @@ export function flattenObject(obj: TranslationDeepObject( - language: 'en' | 'es' | 'es-ES', - phraseKey: TKey, - fallbackLanguage: 'en' | 'es' | null, - ...parameters: TranslationParameters -): string | null { +function getTranslatedPhrase(language: 'en' | 'es', phraseKey: TKey, ...parameters: TranslationParameters): string | null { const translatedPhrase = translations?.[language]?.[phraseKey]; if (translatedPhrase) { @@ -108,30 +103,15 @@ function getTranslatedPhrase( return translatedPhrase; } - if (!fallbackLanguage) { - return null; - } - - // Phrase is not found in full locale, search it in fallback language e.g. es - const fallbackTranslatedPhrase = getTranslatedPhrase(fallbackLanguage, phraseKey, null, ...parameters); - - if (fallbackTranslatedPhrase) { - return fallbackTranslatedPhrase; - } - - if (fallbackLanguage !== CONST.LOCALES.DEFAULT) { - Log.alert(`${phraseKey} was not found in the ${fallbackLanguage} locale`); - } - - // Phrase is not translated, search it in default language (en) - return getTranslatedPhrase(CONST.LOCALES.DEFAULT, phraseKey, null, ...parameters); + Log.alert(`${phraseKey} was not found in the ${language} locale`); + return null; } const memoizedGetTranslatedPhrase = memoize(getTranslatedPhrase, { maxArgs: 2, equality: 'shallow', // eslint-disable-next-line @typescript-eslint/no-unused-vars - skipCache: (params) => !isEmptyObject(params.at(3)), + skipCache: (params) => !isEmptyObject(params.at(2)), }); /** @@ -142,11 +122,9 @@ const memoizedGetTranslatedPhrase = memoize(getTranslatedPhrase, { */ function translate(desiredLanguage: 'en' | 'es' | 'es-ES' | 'es_ES', path: TPath, ...parameters: TranslationParameters): string { // Search phrase in full locale e.g. es-ES - const language = desiredLanguage === CONST.LOCALES.ES_ES_ONFIDO ? CONST.LOCALES.ES_ES : desiredLanguage; - // Phrase is not found in full locale, search it in fallback language e.g. es - const languageAbbreviation = desiredLanguage.substring(0, 2) as 'en' | 'es'; + const language = ([CONST.LOCALES.ES_ES_ONFIDO, CONST.LOCALES.ES_ES] as string[]).includes(desiredLanguage) ? CONST.LOCALES.ES : (desiredLanguage as 'en' | 'es'); - const translatedPhrase = memoizedGetTranslatedPhrase(language, path, languageAbbreviation, ...parameters); + const translatedPhrase = memoizedGetTranslatedPhrase(language, path, ...parameters); if (translatedPhrase !== null && translatedPhrase !== undefined) { return translatedPhrase; } diff --git a/tests/unit/TranslateTest.ts b/tests/unit/TranslateTest.ts index ed2b8b8f988b..7ab8c40a4e26 100644 --- a/tests/unit/TranslateTest.ts +++ b/tests/unit/TranslateTest.ts @@ -3,7 +3,7 @@ import CONFIG from '@src/CONFIG'; import CONST from '@src/CONST'; import * as translations from '@src/languages/translations'; import type {FlatTranslationsObject, TranslationDeepObject, TranslationPaths} from '@src/languages/types'; -import * as Localize from '@src/libs/Localize'; +import {translate} from '@src/libs/Localize'; import asMutable from '@src/types/utils/asMutable'; import arrayDifference from '@src/utils/arrayDifference'; @@ -13,7 +13,6 @@ asMutable(translations).default = { [CONST.LOCALES.EN]: translations.flattenObject({ testKey1: 'English', testKey2: 'Test Word 2', - testKey3: 'Test Word 3', testKeyGroup: { testFunction: ({testVariable}: {testVariable: string}) => `With variable ${testVariable}`, }, @@ -35,31 +34,22 @@ asMutable(translations).default = { }), }, }), - [CONST.LOCALES.ES_ES]: translations.flattenObject({testKey1: 'Spanish ES'}), }; describe('translate', () => { - it('Test present key in full locale', () => { - expect(Localize.translate(CONST.LOCALES.ES_ES, 'testKey1' as TranslationPaths)).toBe('Spanish ES'); - }); - it('Test when key is not found in full locale, but present in language', () => { - expect(Localize.translate(CONST.LOCALES.ES_ES, 'testKey2' as TranslationPaths)).toBe('Spanish Word 2'); - expect(Localize.translate(CONST.LOCALES.ES, 'testKey2' as TranslationPaths)).toBe('Spanish Word 2'); - }); - - it('Test when key is not found in full locale and language, but present in default', () => { - expect(Localize.translate(CONST.LOCALES.ES_ES, 'testKey3' as TranslationPaths)).toBe('Test Word 3'); + expect(translate(CONST.LOCALES.ES_ES, 'testKey2' as TranslationPaths)).toBe('Spanish Word 2'); + expect(translate(CONST.LOCALES.ES, 'testKey2' as TranslationPaths)).toBe('Spanish Word 2'); }); test('Test when key is not found in default', () => { - expect(() => Localize.translate(CONST.LOCALES.ES_ES, 'testKey4' as TranslationPaths)).toThrow(Error); + expect(() => translate(CONST.LOCALES.ES_ES, 'testKey4' as TranslationPaths)).toThrow(Error); }); test('Test when key is not found in default (Production Mode)', () => { const ORIGINAL_IS_IN_PRODUCTION = CONFIG.IS_IN_PRODUCTION; asMutable(CONFIG).IS_IN_PRODUCTION = true; - expect(Localize.translate(CONST.LOCALES.ES_ES, 'testKey4' as TranslationPaths)).toBe('testKey4'); + expect(translate(CONST.LOCALES.ES_ES, 'testKey4' as TranslationPaths)).toBe('testKey4'); asMutable(CONFIG).IS_IN_PRODUCTION = ORIGINAL_IS_IN_PRODUCTION; }); @@ -67,52 +57,41 @@ describe('translate', () => { const expectedValue = 'With variable Test Variable'; const testVariable = 'Test Variable'; // @ts-expect-error - TranslationPaths doesn't include testKeyGroup.testFunction as a valid key - expect(Localize.translate(CONST.LOCALES.EN, 'testKeyGroup.testFunction' as TranslationPaths, {testVariable})).toBe(expectedValue); + expect(translate(CONST.LOCALES.EN, 'testKeyGroup.testFunction' as TranslationPaths, {testVariable})).toBe(expectedValue); }); it('Test when count value passed to function but output is string', () => { const expectedValue = 'Count value is 10'; const count = 10; // @ts-expect-error - TranslationPaths doesn't include pluralizationGroup.countWithoutPluralRules as a valid key - expect(Localize.translate(CONST.LOCALES.EN, 'pluralizationGroup.countWithoutPluralRules' as TranslationPaths, {count})).toBe(expectedValue); + expect(translate(CONST.LOCALES.EN, 'pluralizationGroup.countWithoutPluralRules' as TranslationPaths, {count})).toBe(expectedValue); }); it('Test when count value 2 passed to function but there is no rule for the key two', () => { const expectedValue = 'Other 2 files are being downloaded.'; const count = 2; // @ts-expect-error - TranslationPaths doesn't include pluralizationGroup.countWithNoCorrespondingRule as a valid key - expect(Localize.translate(CONST.LOCALES.EN, 'pluralizationGroup.countWithNoCorrespondingRule' as TranslationPaths, {count})).toBe(expectedValue); + expect(translate(CONST.LOCALES.EN, 'pluralizationGroup.countWithNoCorrespondingRule' as TranslationPaths, {count})).toBe(expectedValue); }); it('Test when count value 0, 1, 100 passed to function', () => { // @ts-expect-error - TranslationPaths doesn't include pluralizationGroup.couthWithCorrespondingRule as a valid key - expect(Localize.translate(CONST.LOCALES.ES, 'pluralizationGroup.couthWithCorrespondingRule' as TranslationPaths, {count: 0})).toBe('0 artículos'); + expect(translate(CONST.LOCALES.ES, 'pluralizationGroup.couthWithCorrespondingRule' as TranslationPaths, {count: 0})).toBe('0 artículos'); // @ts-expect-error - TranslationPaths doesn't include pluralizationGroup.couthWithCorrespondingRule as a valid key - expect(Localize.translate(CONST.LOCALES.ES, 'pluralizationGroup.couthWithCorrespondingRule' as TranslationPaths, {count: 1})).toBe('Un artículo'); + expect(translate(CONST.LOCALES.ES, 'pluralizationGroup.couthWithCorrespondingRule' as TranslationPaths, {count: 1})).toBe('Un artículo'); // @ts-expect-error - TranslationPaths doesn't include pluralizationGroup.couthWithCorrespondingRule as a valid key - expect(Localize.translate(CONST.LOCALES.ES, 'pluralizationGroup.couthWithCorrespondingRule' as TranslationPaths, {count: 100})).toBe('100 artículos'); + expect(translate(CONST.LOCALES.ES, 'pluralizationGroup.couthWithCorrespondingRule' as TranslationPaths, {count: 100})).toBe('100 artículos'); }); }); describe('Translation Keys', () => { - function traverseKeyPath(source: FlatTranslationsObject, path?: string, keyPaths?: string[]): string[] { - const pathArray = keyPaths ?? []; - const keyPath = path ? `${path}.` : ''; - (Object.keys(source) as TranslationPaths[]).forEach((key) => { - if (typeof source[key] === 'object' && typeof source[key] !== 'function') { - // @ts-expect-error - We are modifying the translations object for testing purposes - traverseKeyPath(source[key], keyPath + key, pathArray); - } else { - pathArray.push(keyPath + key); - } - }); - - return pathArray; + function traverseKeyPath(source: FlatTranslationsObject): string[] { + return Object.keys(source); } - const excludeLanguages = [CONST.LOCALES.EN, CONST.LOCALES.ES_ES]; + const excludeLanguages = [CONST.LOCALES.EN]; const languages = Object.keys(originalTranslations.default).filter((ln) => !excludeLanguages.some((excludeLanguage) => excludeLanguage === ln)); const mainLanguage = originalTranslations.default.en; const mainLanguageKeys = traverseKeyPath(mainLanguage); From a91572c23ed3796da66a84582993be506935c43f Mon Sep 17 00:00:00 2001 From: Shubham Agrawal Date: Sun, 1 Jun 2025 17:44:24 +0530 Subject: [PATCH 2/3] Fix tests --- __mocks__/react-native-localize.ts | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/__mocks__/react-native-localize.ts b/__mocks__/react-native-localize.ts index 0188b8afd23f..e23bc11aa2ab 100644 --- a/__mocks__/react-native-localize.ts +++ b/__mocks__/react-native-localize.ts @@ -1,4 +1,8 @@ -// eslint-disable-next-line import/no-import-module-exports -import mockRNLocalize from 'react-native-localize/mock'; +// use a provided translation, or return undefined to test your fallback +const findBestAvailableLanguage = () => ({ + languageTag: "en", + isRTL: false, +}); -module.exports = mockRNLocalize; +// eslint-disable-next-line import/prefer-default-export +export {findBestAvailableLanguage}; From d4024d96132ac93ed117b42feaa1b97e042bda5c Mon Sep 17 00:00:00 2001 From: Shubham Agrawal Date: Sun, 1 Jun 2025 17:50:19 +0530 Subject: [PATCH 3/3] Fix prettier --- __mocks__/react-native-localize.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/__mocks__/react-native-localize.ts b/__mocks__/react-native-localize.ts index e23bc11aa2ab..cf4145ad0014 100644 --- a/__mocks__/react-native-localize.ts +++ b/__mocks__/react-native-localize.ts @@ -1,6 +1,6 @@ // use a provided translation, or return undefined to test your fallback const findBestAvailableLanguage = () => ({ - languageTag: "en", + languageTag: 'en', isRTL: false, });