Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Audit][Implementation] - Reduce Redundant Operations #37200

Merged
Show file tree
Hide file tree
Changes from 18 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
60ea1a1
perf: remove redundant translations
hurali97 Feb 26, 2024
22f0ffa
perf: only parse the number if it matches the pattern
hurali97 Feb 26, 2024
643c7e1
perf: return early if displayName exists
hurali97 Feb 27, 2024
c683db7
test: fix failing test for formatPhoneNumber
hurali97 Feb 27, 2024
454a9b2
refactor: move translations to utils
hurali97 Feb 27, 2024
eb8f26c
fix: linting
hurali97 Feb 27, 2024
34cd2e8
refactor: use regex and dedicated const for sms domain
hurali97 Feb 28, 2024
707f56c
refactor: remove allocating a variable and return the evaluated expre…
hurali97 Feb 28, 2024
f36550f
refactor: use single-line comments
hurali97 Feb 29, 2024
e02b55a
refactor: use default policy room chat types from CONST
hurali97 Mar 4, 2024
7cbca08
revert: bring back localize.translateLocal
hurali97 Mar 4, 2024
4df1d3d
feat: add cache for translated values in Localize
hurali97 Mar 4, 2024
a7bd7d1
Merge branch 'main' of https://github.com/callstack-internal/Expensif…
hurali97 Mar 4, 2024
55eb5d2
refactor: delete common translation utils
hurali97 Mar 4, 2024
e643960
refactor: avoid multiple cache lookups
hurali97 Mar 4, 2024
f3d6f1f
fix: lint
hurali97 Mar 4, 2024
1755560
refactor: use dedicated map for each locale
hurali97 Mar 6, 2024
99dd34c
refactor: remove setImmediate
hurali97 Mar 6, 2024
3ff2f9c
refactor: remove not needed variable
hurali97 Mar 11, 2024
70bd88f
refactor: use Map of Maps to hold the locales with translated phrases
hurali97 Mar 11, 2024
9fc04db
refactor: move cache mechanism to translate function
hurali97 Mar 12, 2024
ce18f61
Merge branch 'main' of https://github.com/callstack-internal/Expensif…
hurali97 Mar 14, 2024
e22c22b
refactor: use dedicated function to get translated phrase to avoid du…
hurali97 Mar 14, 2024
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
20 changes: 12 additions & 8 deletions src/CONST.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,21 @@ const keyInputRightArrow = KeyCommand?.constants?.keyInputRightArrow ?? 'keyInpu
// describes if a shortcut key can cause navigation
const KEYBOARD_SHORTCUT_NAVIGATION_TYPE = 'NAVIGATION_SHORTCUT';

const chatTypes = {
POLICY_ANNOUNCE: 'policyAnnounce',
POLICY_ADMINS: 'policyAdmins',
DOMAIN_ALL: 'domainAll',
POLICY_ROOM: 'policyRoom',
POLICY_EXPENSE_CHAT: 'policyExpenseChat',
SELF_DM: 'selfDM',
} as const;

// Explicit type annotation is required
const cardActiveStates: number[] = [2, 3, 4, 7];

const CONST = {
MERGED_ACCOUNT_PREFIX: 'MERGED_',
hurali97 marked this conversation as resolved.
Show resolved Hide resolved
DEFAULT_POLICY_ROOM_CHAT_TYPES: [chatTypes.POLICY_ADMINS, chatTypes.POLICY_ANNOUNCE, chatTypes.DOMAIN_ALL],
ANDROID_PACKAGE_NAME,
ANIMATED_TRANSITION: 300,
ANIMATED_TRANSITION_FROM_VALUE: 100,
Expand Down Expand Up @@ -685,14 +696,7 @@ const CONST = {
IOU: 'iou',
TASK: 'task',
},
CHAT_TYPE: {
POLICY_ANNOUNCE: 'policyAnnounce',
POLICY_ADMINS: 'policyAdmins',
DOMAIN_ALL: 'domainAll',
POLICY_ROOM: 'policyRoom',
POLICY_EXPENSE_CHAT: 'policyExpenseChat',
SELF_DM: 'selfDM',
},
CHAT_TYPE: chatTypes,
WORKSPACE_CHAT_ROOMS: {
ANNOUNCE: '#announce',
ADMINS: '#admins',
Expand Down
5 changes: 5 additions & 0 deletions src/libs/LocalePhoneNumber.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import Str from 'expensify-common/lib/str';
import Onyx from 'react-native-onyx';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import {parsePhoneNumber} from './PhoneNumber';

Expand All @@ -18,6 +19,10 @@ function formatPhoneNumber(number: string): string {
return '';
}

// do not parse the string, if it doesn't contain the SMS domain and it's not a phone number
if (number.indexOf(CONST.SMS.DOMAIN) === -1 && !CONST.REGEX.DIGITS_AND_PLUS.test(number)) {
hurali97 marked this conversation as resolved.
Show resolved Hide resolved
return number;
}
const numberWithoutSMSDomain = Str.removeSMSDomain(number);
const parsedPhoneNumber = parsePhoneNumber(numberWithoutSMSDomain);

Expand Down
61 changes: 60 additions & 1 deletion src/libs/Localize/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import type {Locale} from '@src/types/onyx';
import type {ReceiptError} from '@src/types/onyx/Transaction';
import LocaleListener from './LocaleListener';
import BaseLocaleListener from './LocaleListener/BaseLocaleListener';
import type BaseLocale from './LocaleListener/types';

// Current user mail is needed for handling missing translations
let userEmail = '';
Expand Down Expand Up @@ -93,11 +94,69 @@ function translate<TKey extends TranslationPaths>(desiredLanguage: 'en' | 'es' |
throw new Error(`${phraseKey} was not found in the default language`);
}

/**
* 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:
*
* {
* "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 TRANSLATED_VALUES_EN = new Map<string, string>();
const TRANSLATED_VALUES_ES = new Map<string, string>();
const TRANSLATED_VALUES_ES_ES = new Map<string, string>();
const TRANSLATED_VALUES_ES_ONFIDO = new Map<string, string>();

/**
* Returns the map for the given locale.
*/
function getTranslatedValuesMap(locale: BaseLocale) {
switch (locale) {
case CONST.LOCALES.ES_ES:
return TRANSLATED_VALUES_ES_ES;
case CONST.LOCALES.ES_ES_ONFIDO:
return TRANSLATED_VALUES_ES_ONFIDO;
case CONST.LOCALES.ES:
return TRANSLATED_VALUES_ES;
case CONST.LOCALES.DEFAULT:
default:
return TRANSLATED_VALUES_EN;
}
}

/**
* Uses the locale in this file updated by the Onyx subscriber.
*/
function translateLocal<TKey extends TranslationPaths>(phrase: TKey, ...variables: PhraseParameters<Phrase<TKey>>) {
hurali97 marked this conversation as resolved.
Show resolved Hide resolved
return translate(BaseLocaleListener.getPreferredLocale(), phrase, ...variables);
const preferredLocale = BaseLocaleListener.getPreferredLocale();
const key = `${phrase}`;
hurali97 marked this conversation as resolved.
Show resolved Hide resolved
const isVariablesEmpty = variables.length === 0;
hurali97 marked this conversation as resolved.
Show resolved Hide resolved

// Get the map for the preferred locale
const map = getTranslatedValuesMap(preferredLocale);

// 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 = map.get(key);

// If the phrase is already translated, return the translated value
if (valueFromCache) {
return valueFromCache;
}
const translatedText = translate(preferredLocale, phrase, ...variables);

// We don't want to store translated values for phrases with variables
if (isVariablesEmpty) {
hurali97 marked this conversation as resolved.
Show resolved Hide resolved
// We set the translated value in the cache
map.set(key, translatedText);
}
return translatedText;
}

/**
Expand Down
20 changes: 16 additions & 4 deletions src/libs/PersonalDetailsUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,27 @@ Onyx.connect({
},
});

// Index for the substring method to remove the merged account prefix.
const substringStartIndex = CONST.MERGED_ACCOUNT_PREFIX.length;
hurali97 marked this conversation as resolved.
Show resolved Hide resolved

function getDisplayNameOrDefault(passedPersonalDetails?: Partial<PersonalDetails> | null, defaultValue = '', shouldFallbackToHidden = true, shouldAddCurrentUserPostfix = false): string {
let displayName = passedPersonalDetails?.displayName ? passedPersonalDetails.displayName.replace(CONST.REGEX.MERGED_ACCOUNT_PREFIX, '') : '';
let displayName = passedPersonalDetails?.displayName ?? '';

// If the displayName starts with the merged account prefix, remove it.
if (displayName.startsWith(CONST.MERGED_ACCOUNT_PREFIX)) {
hurali97 marked this conversation as resolved.
Show resolved Hide resolved
displayName = displayName.substring(substringStartIndex);
hurali97 marked this conversation as resolved.
Show resolved Hide resolved
}

if (shouldAddCurrentUserPostfix && !!displayName) {
displayName = `${displayName} (${Localize.translateLocal('common.you').toLowerCase()})`;
}

const fallbackValue = shouldFallbackToHidden ? Localize.translateLocal('common.hidden') : '';

return displayName || defaultValue || fallbackValue;
// If displayName exists, return it early so we don't have to allocate
hurali97 marked this conversation as resolved.
Show resolved Hide resolved
// memory for the fallback string.
if (displayName) {
return displayName;
}
return defaultValue || (shouldFallbackToHidden ? Localize.translateLocal('common.hidden') : '');
}

/**
Expand Down
2 changes: 1 addition & 1 deletion src/libs/ReportUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -777,7 +777,7 @@ function isAnnounceRoom(report: OnyxEntry<Report>): boolean {
* Whether the provided report is a default room
*/
function isDefaultRoom(report: OnyxEntry<Report>): boolean {
return [CONST.REPORT.CHAT_TYPE.POLICY_ADMINS, CONST.REPORT.CHAT_TYPE.POLICY_ANNOUNCE, CONST.REPORT.CHAT_TYPE.DOMAIN_ALL].some((type) => type === getChatType(report));
return CONST.DEFAULT_POLICY_ROOM_CHAT_TYPES.some((type) => type === getChatType(report));
}

/**
Expand Down
Loading