From 0910231da82b97cea870fe3807af5b937c5e007b Mon Sep 17 00:00:00 2001 From: Shubham Agrawal Date: Fri, 4 Oct 2024 08:29:59 +0530 Subject: [PATCH 1/4] Use localize with libs/memoize --- src/libs/Localize/index.ts | 45 ++++++-------------------------------- 1 file changed, 7 insertions(+), 38 deletions(-) diff --git a/src/libs/Localize/index.ts b/src/libs/Localize/index.ts index bd8a34406846..d342b158657f 100644 --- a/src/libs/Localize/index.ts +++ b/src/libs/Localize/index.ts @@ -1,7 +1,7 @@ import * as RNLocalize from 'react-native-localize'; import Onyx from 'react-native-onyx'; -import type {ValueOf} from 'type-fest'; import Log from '@libs/Log'; +import memoize from '@libs/memoize'; import type {MessageElementBase, MessageTextElement} from '@libs/MessageElement'; import Config from '@src/CONFIG'; import CONST from '@src/CONST'; @@ -45,28 +45,6 @@ function init() { }, {}); } -/** - * Map to store translated values for each locale. - * This is used to avoid translating the same phrase multiple times. - * - * The data is stored in the following format: - * - * { - * "en": { - * "name": "Name", - * } - * - * Note: We are not storing any translated values for phrases with variables, - * as they have higher chance of being unique, so we'll end up wasting space - * in our cache. - */ -const translationCache = new Map, Map>( - Object.values(CONST.LOCALES).reduce((cache, locale) => { - cache.push([locale, new Map()]); - return cache; - }, [] as Array<[ValueOf, Map]>), -); - /** * Helper function to get the translated string for given * locale and phrase. This function is used to avoid @@ -86,18 +64,6 @@ function getTranslatedPhrase( fallbackLanguage: 'en' | 'es' | null, ...parameters: TranslationParameters ): string | null { - // Get the cache for the above locale - const cacheForLocale = translationCache.get(language); - - // Directly access and assign the translated value from the cache, instead of - // going through map.has() and map.get() to avoid multiple lookups. - const valueFromCache = cacheForLocale?.get(phraseKey); - - // If the phrase is already translated, return the translated value - if (valueFromCache) { - return valueFromCache; - } - const translatedPhrase = translations?.[language]?.[phraseKey]; if (translatedPhrase) { @@ -138,8 +104,6 @@ function getTranslatedPhrase( return translateResult.other(phraseObject.count); } - // We set the translated value in the cache only for the phrases without parameters. - cacheForLocale?.set(phraseKey, translatedPhrase); return translatedPhrase; } @@ -162,6 +126,11 @@ function getTranslatedPhrase( return getTranslatedPhrase(CONST.LOCALES.DEFAULT, phraseKey, null, ...parameters); } +const memoizedGetTranslatedPhrase = memoize(getTranslatedPhrase, { + monitoringName: 'getTranslatedPhrase', + transformKey: ([language, phraseKey, fallbackLanguage, ...parameters]) => `${language}-${phraseKey}-${fallbackLanguage}-${parameters.length > 0 ? JSON.stringify(parameters.at(0)) : ''}`, +}); + /** * Return translated string for given locale and phrase * @@ -174,7 +143,7 @@ function translate(desiredLanguage: 'en' | 'es' // 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 translatedPhrase = getTranslatedPhrase(language, path, languageAbbreviation, ...parameters); + const translatedPhrase = memoizedGetTranslatedPhrase(language, path, languageAbbreviation, ...parameters); if (translatedPhrase !== null && translatedPhrase !== undefined) { return translatedPhrase; } From 3cec7fdda80b3c0ef5312c620d8048ad469092f8 Mon Sep 17 00:00:00 2001 From: Shubham Agrawal Date: Mon, 14 Oct 2024 13:49:23 +0900 Subject: [PATCH 2/4] Added keyFilter to not cache dynamic keys --- src/libs/Localize/index.ts | 7 +++++-- src/libs/memoize/index.ts | 11 +++++++++++ src/libs/memoize/types.ts | 7 +++++++ 3 files changed, 23 insertions(+), 2 deletions(-) diff --git a/src/libs/Localize/index.ts b/src/libs/Localize/index.ts index d342b158657f..4a8b0bf168d4 100644 --- a/src/libs/Localize/index.ts +++ b/src/libs/Localize/index.ts @@ -9,6 +9,7 @@ import translations from '@src/languages/translations'; import type {PluralForm, TranslationParameters, TranslationPaths} from '@src/languages/types'; import ONYXKEYS from '@src/ONYXKEYS'; import type {Locale} from '@src/types/onyx'; +import {isEmptyObject} from '@src/types/utils/EmptyObject'; import LocaleListener from './LocaleListener'; import BaseLocaleListener from './LocaleListener/BaseLocaleListener'; @@ -127,8 +128,10 @@ function getTranslatedPhrase( } const memoizedGetTranslatedPhrase = memoize(getTranslatedPhrase, { - monitoringName: 'getTranslatedPhrase', - transformKey: ([language, phraseKey, fallbackLanguage, ...parameters]) => `${language}-${phraseKey}-${fallbackLanguage}-${parameters.length > 0 ? JSON.stringify(parameters.at(0)) : ''}`, + maxArgs: 2, + equality: 'shallow', + // eslint-disable-next-line @typescript-eslint/no-unused-vars + keyFilter: ([language, phraseKey, fallbackLanguage, ...parameters]) => !isEmptyObject(parameters.at(0)), }); /** diff --git a/src/libs/memoize/index.ts b/src/libs/memoize/index.ts index f02b1adbf5ba..1b9c78e793db 100644 --- a/src/libs/memoize/index.ts +++ b/src/libs/memoize/index.ts @@ -60,6 +60,17 @@ function memoize; + + statsEntry.trackTime('processingTime', fnTimeStart); + statsEntry.track('didHit', false); + + return result; + } + const truncatedArgs = truncateArgs(args, options.maxArgs); const key = options.transformKey ? options.transformKey(truncatedArgs) : (truncatedArgs as Key); diff --git a/src/libs/memoize/types.ts b/src/libs/memoize/types.ts index 9ee48c9dc790..71479f637c1d 100644 --- a/src/libs/memoize/types.ts +++ b/src/libs/memoize/types.ts @@ -52,6 +52,13 @@ type Options = { * @returns Key to use for caching */ transformKey?: (truncatedArgs: TakeFirst, MaxArgs>) => Key; + + /** + * Checks if the cache should be skipped for the given arguments. + * @param args Tuple of arguments passed to the memoized function. Does not work with constructable (see description). + * @returns boolean to whether to skip cache lookup and execute the function if true + */ + keyFilter?: (args: IsomorphicParameters) => boolean; } & InternalOptions; type ClientOptions = Partial, keyof InternalOptions>>; From d9841be8d1759dbd3a0db2019fd520e67273f52a Mon Sep 17 00:00:00 2001 From: Shubham Agrawal Date: Tue, 22 Oct 2024 10:04:57 +0900 Subject: [PATCH 3/4] Rename variable --- src/libs/Localize/index.ts | 2 +- src/libs/memoize/index.ts | 4 ++-- src/libs/memoize/types.ts | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/libs/Localize/index.ts b/src/libs/Localize/index.ts index 4a8b0bf168d4..913780ec4fbc 100644 --- a/src/libs/Localize/index.ts +++ b/src/libs/Localize/index.ts @@ -131,7 +131,7 @@ const memoizedGetTranslatedPhrase = memoize(getTranslatedPhrase, { maxArgs: 2, equality: 'shallow', // eslint-disable-next-line @typescript-eslint/no-unused-vars - keyFilter: ([language, phraseKey, fallbackLanguage, ...parameters]) => !isEmptyObject(parameters.at(0)), + skipCache: ([language, phraseKey, fallbackLanguage, ...parameters]) => !isEmptyObject(parameters.at(0)), }); /** diff --git a/src/libs/memoize/index.ts b/src/libs/memoize/index.ts index 1b9c78e793db..792a7ea82f3a 100644 --- a/src/libs/memoize/index.ts +++ b/src/libs/memoize/index.ts @@ -60,8 +60,8 @@ function memoize; diff --git a/src/libs/memoize/types.ts b/src/libs/memoize/types.ts index 71479f637c1d..d47a09f114bf 100644 --- a/src/libs/memoize/types.ts +++ b/src/libs/memoize/types.ts @@ -58,7 +58,7 @@ type Options = { * @param args Tuple of arguments passed to the memoized function. Does not work with constructable (see description). * @returns boolean to whether to skip cache lookup and execute the function if true */ - keyFilter?: (args: IsomorphicParameters) => boolean; + skipCache?: (args: IsomorphicParameters) => boolean; } & InternalOptions; type ClientOptions = Partial, keyof InternalOptions>>; From 5a768922c82ea3f67ac8e58fd48ba3ad7812754a Mon Sep 17 00:00:00 2001 From: Shubham Agrawal <58412969+shubham1206agra@users.noreply.github.com> Date: Tue, 29 Oct 2024 16:56:39 +0530 Subject: [PATCH 4/4] Apply suggestions from code review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Kacper Mikołajczak <62747088+kacper-mikolajczak@users.noreply.github.com> --- src/libs/Localize/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/Localize/index.ts b/src/libs/Localize/index.ts index 913780ec4fbc..3f079b49653a 100644 --- a/src/libs/Localize/index.ts +++ b/src/libs/Localize/index.ts @@ -131,7 +131,7 @@ const memoizedGetTranslatedPhrase = memoize(getTranslatedPhrase, { maxArgs: 2, equality: 'shallow', // eslint-disable-next-line @typescript-eslint/no-unused-vars - skipCache: ([language, phraseKey, fallbackLanguage, ...parameters]) => !isEmptyObject(parameters.at(0)), + skipCache: (params) => !isEmptyObject(params.at(3)), }); /**