From 6f88df66ade84884a1d5ed573c12b3ccc5f6b14f Mon Sep 17 00:00:00 2001 From: Hubert Sosinski Date: Fri, 11 Sep 2026 12:22:21 +0200 Subject: [PATCH] Generalize convertToDisplayStringWithoutCurrency for any locale --- .../CurrencyListContextProvider/index.tsx | 25 +++---------------- src/libs/CurrencyUtils.ts | 24 ++++++++++++++---- 2 files changed, 23 insertions(+), 26 deletions(-) diff --git a/src/components/CurrencyListContextProvider/index.tsx b/src/components/CurrencyListContextProvider/index.tsx index c6b8c8fb3a23..bb24ca3eaace 100644 --- a/src/components/CurrencyListContextProvider/index.tsx +++ b/src/components/CurrencyListContextProvider/index.tsx @@ -1,8 +1,8 @@ import useLocalize from '@hooks/useLocalize'; import useOnyx from '@hooks/useOnyx'; -import {convertToFrontendAmountAsInteger, sanitizeCurrencyCode} from '@libs/CurrencyUtils'; -import {format, formatToParts} from '@libs/NumberFormatUtils'; +import {convertToDisplayStringWithoutCurrencyForLocale, convertToFrontendAmountAsInteger, sanitizeCurrencyCode} from '@libs/CurrencyUtils'; +import {format} from '@libs/NumberFormatUtils'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; @@ -57,25 +57,8 @@ function CurrencyListContextProvider({children}: React.PropsWithChildren) { ); const convertToDisplayStringWithoutCurrency = useCallback( - (amountInCents: number, currencyCode: string = CONST.CURRENCY.USD): string => { - const sanitizedCurrency = sanitizeCurrencyCode(currencyCode); - const decimals = getCurrencyDecimals(sanitizedCurrency); - const convertedAmount = convertToFrontendAmountAsInteger(amountInCents, decimals); - return formatToParts(preferredLocale, convertedAmount, { - style: 'currency', - currency: sanitizedCurrency, - - // We are forcing the number of decimals because we override the default number of decimals in the backend for some currencies - // See: https://github.com/Expensify/PHP-Libs/pull/834 - minimumFractionDigits: decimals, - // For currencies that have decimal places > 2, floor to 2 instead as we don't support more than 2 decimal places. - maximumFractionDigits: 2, - }) - .filter((x) => x.type !== 'currency') - .filter((x) => x.type !== 'literal' || x.value.trim().length !== 0) - .map((x) => x.value) - .join(''); - }, + (amountInCents: number, currencyCode: string = CONST.CURRENCY.USD): string => + convertToDisplayStringWithoutCurrencyForLocale(preferredLocale, amountInCents, currencyCode, getCurrencyDecimals), [getCurrencyDecimals, preferredLocale], ); diff --git a/src/libs/CurrencyUtils.ts b/src/libs/CurrencyUtils.ts index fbf346948338..04d68496b28d 100644 --- a/src/libs/CurrencyUtils.ts +++ b/src/libs/CurrencyUtils.ts @@ -149,11 +149,11 @@ function convertToDisplayStringEnLocale(amountInCents: number, currency: string } /** - * Same as convertToDisplayStringWithoutCurrency but always formats with the `en` locale, with decimals - * injected. Used alongside convertToDisplayStringEnLocale for stored values (e.g. formula-computed - * report titles) that must not depend on the viewer's locale or this module's Onyx fallback. + * Given an amount in "cents", format it for the passed locale without the currency symbol. Decimals are + * injected so this function does not depend on this module's Onyx fallback. */ -function convertToDisplayStringWithoutCurrencyEnLocale( +function convertToDisplayStringWithoutCurrencyForLocale( + locale: Locale | undefined, amountInCents: number, currency: string | undefined, getCurrencyDecimalsImpl: CurrencyListActionsContextType['getCurrencyDecimals'], @@ -161,7 +161,7 @@ function convertToDisplayStringWithoutCurrencyEnLocale( const sanitizedCurrency = sanitizeCurrencyCode(currency); const decimals = getCurrencyDecimalsImpl(sanitizedCurrency); const convertedAmount = convertToFrontendAmountAsInteger(amountInCents, decimals); - return formatToParts(CONST.LOCALES.EN, convertedAmount, { + return formatToParts(locale, convertedAmount, { style: 'currency', currency: sanitizedCurrency, @@ -177,6 +177,19 @@ function convertToDisplayStringWithoutCurrencyEnLocale( .join(''); } +/** + * Same as convertToDisplayStringWithoutCurrency but always formats with the `en` locale, with decimals + * injected. Used alongside convertToDisplayStringEnLocale for stored values (e.g. formula-computed + * report titles) that must not depend on the viewer's locale or this module's Onyx fallback. + */ +function convertToDisplayStringWithoutCurrencyEnLocale( + amountInCents: number, + currency: string | undefined, + getCurrencyDecimalsImpl: CurrencyListActionsContextType['getCurrencyDecimals'], +): string { + return convertToDisplayStringWithoutCurrencyForLocale(CONST.LOCALES.EN, amountInCents, currency, getCurrencyDecimalsImpl); +} + /** * Given the amount in the "cents", convert it to a short string (no decimals) for display in the UI. * The backend always handle things in "cents" (subunit equal to 1/100) @@ -226,5 +239,6 @@ export { convertToDisplayStringEnLocale, convertAmountToDisplayString, convertToDisplayStringWithoutCurrencyEnLocale, + convertToDisplayStringWithoutCurrencyForLocale, convertToShortDisplayString, };