diff --git a/src/components/AccountDrawer/AuthenticatedHeader.tsx b/src/components/AccountDrawer/AuthenticatedHeader.tsx
index 3d43b307d7..39b93c42bf 100644
--- a/src/components/AccountDrawer/AuthenticatedHeader.tsx
+++ b/src/components/AccountDrawer/AuthenticatedHeader.tsx
@@ -25,7 +25,7 @@ import { updateSelectedWallet } from 'state/user/reducer'
import styled from 'styled-components'
import { CopyHelper, ExternalLink, ThemedText } from 'theme'
import { shortenAddress } from 'utils'
-import { formatNumber, NumberType } from 'utils/formatNumbers'
+import { NumberType, useFormatter } from 'utils/formatNumbers'
import { useCloseModal, useFiatOnrampAvailability, useOpenModal, useToggleModal } from '../../state/application/hooks'
import { ApplicationModal } from '../../state/application/reducer'
@@ -159,6 +159,7 @@ export default function AuthenticatedHeader({ account, openSettings }: { account
const resetSellAssets = useSellAsset((state) => state.reset)
const clearCollectionFilters = useWalletCollections((state) => state.clearCollectionFilters)
const isClaimAvailable = useIsNftClaimAvailable((state) => state.isClaimAvailable)
+ const { formatNumber } = useFormatter()
const shouldDisableNFTRoutes = useDisableNFTRoutes()
diff --git a/src/components/AccountDrawer/MiniPortfolio/Pools/index.tsx b/src/components/AccountDrawer/MiniPortfolio/Pools/index.tsx
index 414b1b165c..5830b2c896 100644
--- a/src/components/AccountDrawer/MiniPortfolio/Pools/index.tsx
+++ b/src/components/AccountDrawer/MiniPortfolio/Pools/index.tsx
@@ -13,7 +13,7 @@ import { useCallback, useMemo, useReducer } from 'react'
import { useNavigate } from 'react-router-dom'
import styled from 'styled-components'
import { ThemedText } from 'theme'
-import { formatNumber, NumberType } from 'utils/formatNumbers'
+import { NumberType, useFormatter } from 'utils/formatNumbers'
import { ExpandoRow } from '../ExpandoRow'
import { PortfolioLogo } from '../PortfolioLogo'
@@ -118,6 +118,8 @@ function calculcateLiquidityValue(price0: number | undefined, price1: number | u
}
function PositionListItem({ positionInfo }: { positionInfo: PositionInfo }) {
+ const { formatNumber } = useFormatter()
+
const { chainId, position, pool, details, inRange, closed } = positionInfo
const { priceA, priceB, fees: feeValue } = useFeeValues(positionInfo)
diff --git a/src/components/AccountDrawer/MiniPortfolio/Tokens/index.tsx b/src/components/AccountDrawer/MiniPortfolio/Tokens/index.tsx
index 4233e72a20..abd7a23894 100644
--- a/src/components/AccountDrawer/MiniPortfolio/Tokens/index.tsx
+++ b/src/components/AccountDrawer/MiniPortfolio/Tokens/index.tsx
@@ -11,7 +11,7 @@ import { useCallback, useMemo, useState } from 'react'
import { useNavigate } from 'react-router-dom'
import styled from 'styled-components'
import { EllipsisStyle, ThemedText } from 'theme'
-import { formatNumber, NumberType } from 'utils/formatNumbers'
+import { NumberType, useFormatter } from 'utils/formatNumbers'
import { splitHiddenTokens } from 'utils/splitHiddenTokens'
import { useToggleAccountDrawer } from '../..'
@@ -79,6 +79,7 @@ function TokenRow({ token, quantity, denominatedValue, tokenProjectMarket }: Tok
navigate(getTokenDetailsURL(token))
toggleWalletDrawer()
}, [navigate, token, toggleWalletDrawer])
+ const { formatNumber } = useFormatter()
const currency = gqlToCurrency(token)
if (!currency) {
@@ -100,7 +101,11 @@ function TokenRow({ token, quantity, denominatedValue, tokenProjectMarket }: Tok
title={{token?.name}}
descriptor={
- {formatNumber({ input: quantity, type: NumberType.TokenNonTx })} {token?.symbol}
+ {formatNumber({
+ input: quantity,
+ type: NumberType.TokenNonTx,
+ })}{' '}
+ {token?.symbol}
}
onClick={navigateToTokenDetails}
diff --git a/src/components/CurrencyInputPanel/FiatValue.tsx b/src/components/CurrencyInputPanel/FiatValue.tsx
index 1629389203..0e7625e162 100644
--- a/src/components/CurrencyInputPanel/FiatValue.tsx
+++ b/src/components/CurrencyInputPanel/FiatValue.tsx
@@ -6,7 +6,7 @@ import { MouseoverTooltip } from 'components/Tooltip'
import { useMemo } from 'react'
import styled from 'styled-components'
import { ThemedText } from 'theme'
-import { formatNumber, formatPriceImpact, NumberType } from 'utils/formatNumbers'
+import { formatPriceImpact, NumberType, useFormatter } from 'utils/formatNumbers'
import { warningSeverity } from 'utils/prices'
const FiatLoadingBubble = styled(LoadingBubble)`
@@ -22,6 +22,8 @@ export function FiatValue({
fiatValue: { data?: number; isLoading: boolean }
priceImpact?: Percent
}) {
+ const { formatNumber } = useFormatter()
+
const priceImpactColor = useMemo(() => {
if (!priceImpact) return undefined
if (priceImpact.lessThan('0')) return 'success'
diff --git a/src/components/Tokens/TokenDetails/StatsSection.tsx b/src/components/Tokens/TokenDetails/StatsSection.tsx
index 35f2f0f4e0..728f841949 100644
--- a/src/components/Tokens/TokenDetails/StatsSection.tsx
+++ b/src/components/Tokens/TokenDetails/StatsSection.tsx
@@ -6,7 +6,7 @@ import { ReactNode } from 'react'
import styled from 'styled-components'
import { ExternalLink, ThemedText } from 'theme'
import { textFadeIn } from 'theme/styles'
-import { formatNumber, NumberType } from 'utils/formatNumbers'
+import { NumberType, useFormatter } from 'utils/formatNumbers'
import { UNSUPPORTED_METADATA_CHAINS } from '../constants'
import { TokenSortMethod } from '../state'
@@ -59,6 +59,8 @@ function Stat({
title: ReactNode
description?: ReactNode
}) {
+ const { formatNumber } = useFormatter()
+
return (
{title}
diff --git a/src/components/Tokens/TokenTable/TokenRow.tsx b/src/components/Tokens/TokenTable/TokenRow.tsx
index 6fb0179c72..f8e7a3ae60 100644
--- a/src/components/Tokens/TokenTable/TokenRow.tsx
+++ b/src/components/Tokens/TokenTable/TokenRow.tsx
@@ -16,7 +16,7 @@ import { CSSProperties, ReactNode } from 'react'
import { Link, useParams } from 'react-router-dom'
import styled, { css, useTheme } from 'styled-components'
import { BREAKPOINTS, ClickableStyle } from 'theme'
-import { formatNumber, formatUSDPrice, NumberType } from 'utils/formatNumbers'
+import { formatUSDPrice, NumberType, useFormatter } from 'utils/formatNumbers'
import {
LARGE_MEDIA_BREAKPOINT,
@@ -440,6 +440,8 @@ interface LoadedRowProps {
/* Loaded State: row component with token information */
export const LoadedRow = forwardRef((props: LoadedRowProps, ref: ForwardedRef) => {
+ const { formatNumber } = useFormatter()
+
const { tokenListIndex, tokenListLength, token, sortRank } = props
const filterString = useAtomValue(filterStringAtom)
diff --git a/src/components/swap/AdvancedSwapDetails.tsx b/src/components/swap/AdvancedSwapDetails.tsx
index d0eb021b64..2b9867315b 100644
--- a/src/components/swap/AdvancedSwapDetails.tsx
+++ b/src/components/swap/AdvancedSwapDetails.tsx
@@ -9,7 +9,7 @@ import { ZERO_PERCENT } from 'constants/misc'
import useNativeCurrency from 'lib/hooks/useNativeCurrency'
import { ClassicTrade, InterfaceTrade } from 'state/routing/types'
import { getTransactionCount, isClassicTrade } from 'state/routing/utils'
-import { formatCurrencyAmount, formatNumber, formatPriceImpact, NumberType } from 'utils/formatNumbers'
+import { formatCurrencyAmount, formatPriceImpact, NumberType, useFormatter } from 'utils/formatNumbers'
import { ExternalLink, Separator, ThemedText } from '../../theme'
import Column from '../Column'
@@ -47,6 +47,7 @@ export function AdvancedSwapDetails({ trade, allowedSlippage, syncing = false }:
const { chainId } = useWeb3React()
const nativeCurrency = useNativeCurrency(chainId)
const txCount = getTransactionCount(trade)
+ const { formatNumber } = useFormatter()
const supportsGasEstimate = chainId && SUPPORTED_GAS_ESTIMATE_CHAIN_IDS.includes(chainId)
diff --git a/src/components/swap/GasBreakdownTooltip.tsx b/src/components/swap/GasBreakdownTooltip.tsx
index 611c4b660a..0cad40a6b7 100644
--- a/src/components/swap/GasBreakdownTooltip.tsx
+++ b/src/components/swap/GasBreakdownTooltip.tsx
@@ -7,7 +7,7 @@ import { InterfaceTrade } from 'state/routing/types'
import { isClassicTrade, isUniswapXTrade } from 'state/routing/utils'
import styled from 'styled-components'
import { Divider, ExternalLink, ThemedText } from 'theme'
-import { formatNumber, NumberType } from 'utils/formatNumbers'
+import { NumberType, useFormatter } from 'utils/formatNumbers'
const Container = styled(AutoColumn)`
padding: 4px;
@@ -35,6 +35,8 @@ const GasCostItem = ({
itemValue?: React.ReactNode
amount?: number
}) => {
+ const { formatNumber } = useFormatter()
+
return (
{title}
diff --git a/src/components/swap/GasEstimateTooltip.tsx b/src/components/swap/GasEstimateTooltip.tsx
index 0dad275e1b..afb456e2c6 100644
--- a/src/components/swap/GasEstimateTooltip.tsx
+++ b/src/components/swap/GasEstimateTooltip.tsx
@@ -11,7 +11,7 @@ import { InterfaceTrade } from 'state/routing/types'
import { isUniswapXTrade } from 'state/routing/utils'
import styled from 'styled-components'
import { ThemedText } from 'theme'
-import { formatNumber, NumberType } from 'utils/formatNumbers'
+import { NumberType, useFormatter } from 'utils/formatNumbers'
import { GasBreakdownTooltip } from './GasBreakdownTooltip'
@@ -26,6 +26,7 @@ const StyledGasIcon = styled(Gas)`
export default function GasEstimateTooltip({ trade, loading }: { trade?: InterfaceTrade; loading: boolean }) {
const { chainId } = useWeb3React()
+ const { formatNumber } = useFormatter()
if (!trade || !chainId || !SUPPORTED_GAS_ESTIMATE_CHAIN_IDS.includes(chainId)) {
return null
diff --git a/src/components/swap/SwapModalFooter.tsx b/src/components/swap/SwapModalFooter.tsx
index d30419e59d..684e80899b 100644
--- a/src/components/swap/SwapModalFooter.tsx
+++ b/src/components/swap/SwapModalFooter.tsx
@@ -16,7 +16,7 @@ import { getTransactionCount, isClassicTrade } from 'state/routing/utils'
import { useRouterPreference, useUserSlippageTolerance } from 'state/user/hooks'
import styled, { DefaultTheme, useTheme } from 'styled-components'
import { ExternalLink, ThemedText } from 'theme'
-import { formatNumber, formatPriceImpact, NumberType } from 'utils/formatNumbers'
+import { formatPriceImpact, NumberType, useFormatter } from 'utils/formatNumbers'
import { formatTransactionAmount, priceToPreciseFloat } from 'utils/formatNumbers'
import getRoutingDiagramEntries from 'utils/getRoutingDiagramEntries'
import { formatSwapButtonClickEventProperties } from 'utils/loggingFormatters'
@@ -78,6 +78,7 @@ export default function SwapModalFooter({
const theme = useTheme()
const { chainId } = useWeb3React()
const nativeCurrency = useNativeCurrency(chainId)
+ const { formatNumber } = useFormatter()
const label = `${trade.executionPrice.baseCurrency?.symbol} `
const labelInverted = `${trade.executionPrice.quoteCurrency?.symbol}`
diff --git a/src/components/swap/SwapModalHeaderAmount.tsx b/src/components/swap/SwapModalHeaderAmount.tsx
index 304dfc9c69..29882e4402 100644
--- a/src/components/swap/SwapModalHeaderAmount.tsx
+++ b/src/components/swap/SwapModalHeaderAmount.tsx
@@ -9,7 +9,7 @@ import { TextProps } from 'rebass'
import { Field } from 'state/swap/actions'
import styled from 'styled-components'
import { BREAKPOINTS, ThemedText } from 'theme'
-import { formatNumber, NumberType } from 'utils/formatNumbers'
+import { NumberType, useFormatter } from 'utils/formatNumbers'
import { formatReviewSwapCurrencyAmount } from 'utils/formatNumbers'
export const Label = styled(ThemedText.BodySmall)<{ cursor?: string }>`
@@ -45,6 +45,8 @@ interface AmountProps {
}
export function SwapModalHeaderAmount({ tooltipText, label, amount, usdAmount, field, currency }: AmountProps) {
+ const { formatNumber } = useFormatter()
+
return (
diff --git a/src/components/swap/TradePrice.tsx b/src/components/swap/TradePrice.tsx
index 2e5078e2ef..1a3afb603f 100644
--- a/src/components/swap/TradePrice.tsx
+++ b/src/components/swap/TradePrice.tsx
@@ -5,7 +5,7 @@ import tryParseCurrencyAmount from 'lib/utils/tryParseCurrencyAmount'
import { useCallback, useMemo, useState } from 'react'
import styled from 'styled-components'
import { ThemedText } from 'theme'
-import { formatNumber, formatPrice, NumberType } from 'utils/formatNumbers'
+import { formatPrice, NumberType, useFormatter } from 'utils/formatNumbers'
interface TradePriceProps {
price: Price
@@ -28,6 +28,8 @@ const StyledPriceContainer = styled.button`
`
export default function TradePrice({ price }: TradePriceProps) {
+ const { formatNumber } = useFormatter()
+
const [showInverted, setShowInverted] = useState(false)
const { baseCurrency, quoteCurrency } = price
diff --git a/src/utils/formatNumbers.ts b/src/utils/formatNumbers.ts
index 19679bfdb1..7ab804029a 100644
--- a/src/utils/formatNumbers.ts
+++ b/src/utils/formatNumbers.ts
@@ -5,6 +5,10 @@ import {
SupportedLocalCurrency,
} from 'constants/localCurrencies'
import { DEFAULT_LOCALE, SupportedLocale } from 'constants/locales'
+import { useCurrencyConversionFlagEnabled } from 'featureFlags/flags/currencyConversion'
+import { useActiveLocalCurrency } from 'hooks/useActiveLocalCurrency'
+import { useActiveLocale } from 'hooks/useActiveLocale'
+import { useCallback, useMemo } from 'react'
type Nullish = T | null | undefined
type NumberFormatOptions = Intl.NumberFormatOptions
@@ -525,3 +529,42 @@ export function formatReviewSwapCurrencyAmount(amount: CurrencyAmount)
}
return formattedAmount
}
+
+function useFormatterLocales(): {
+ formatterLocale: SupportedLocale
+ formatterLocalCurrency: SupportedLocalCurrency
+} {
+ const currencyConversionEnabled = useCurrencyConversionFlagEnabled()
+ const activeLocale = useActiveLocale()
+ const activeLocalCurrency = useActiveLocalCurrency()
+
+ if (currencyConversionEnabled) {
+ return {
+ formatterLocale: activeLocale,
+ formatterLocalCurrency: activeLocalCurrency,
+ }
+ }
+
+ return {
+ formatterLocale: DEFAULT_LOCALE,
+ formatterLocalCurrency: DEFAULT_LOCAL_CURRENCY,
+ }
+}
+
+// Constructs an object that injects the correct locale and local currency into each of the above formatter functions.
+export function useFormatter() {
+ const { formatterLocale, formatterLocalCurrency } = useFormatterLocales()
+
+ const formatNumberWithLocales = useCallback(
+ (options: Omit) =>
+ formatNumber({ ...options, locale: formatterLocale, localCurrency: formatterLocalCurrency }),
+ [formatterLocalCurrency, formatterLocale]
+ )
+
+ return useMemo(
+ () => ({
+ formatNumber: formatNumberWithLocales,
+ }),
+ [formatNumberWithLocales]
+ )
+}