Currency formatting, by locale

Apple's NumberFormatter, set to numberStyle = .currency, doesn't just prepend a symbol to a number. It renders the amount the way a native speaker of that locale expects to read money: where the symbol sits, which character separates thousands, which separates decimals, and how negative amounts look. Get any of these wrong and an interface reads as foreign — even when the number itself is correct.

This page is a working reference. Try it live below, or scan the tables of correctly formatted examples. See Apple's NumberFormatter documentation for the full API.

Try it

Swift and JavaScript both delegate currency formatting to ICU, the same locale data Apple's Foundation framework uses — so the result below matches what NumberFormatter produces on iOS and macOS for the same locale and currency in the vast majority of cases.

Formatted result
1234,50 €
NumberFormatter.numberStyle = .currency
Swift
let formatter = NumberFormatter()
formatter.locale = Locale(identifier: "it-IT")
formatter.numberStyle = .currency
formatter.currencyCode = "EUR"
formatter.string(from: 1234.5) // "1234,50 €"
JavaScript
new Intl.NumberFormat("it-IT", {
style: "currency",
currency: "EUR",
currencyDisplay: "symbol",
currencySign: "standard",
}).format(1234.5); // "1234,50 €"

Common mistakes

  • Using the US format ($1,234.50) as the template for every locale and currency.
  • Hardcoding the symbol glued to the number ("€1.234,50") instead of letting the locale decide the symbol's position — German puts it after the amount: "1.234,50 €".
  • Using a period as the decimal separator when the locale expects a comma (most of continental Europe), or vice versa.
  • Treating a negative amount as just a prepended minus sign, ignoring locale and accounting conventions.
  • Assuming currency and locale are the same thing — the same currency formats differently across the locales that use it, see below.

Local currency, by locale

Each locale's own currency, formatted with numberStyle = .currency.

LocaleCurrency1234.5-1234.5
English - United States (en-US)USD$1,234.50-$1,234.50
English - United Kingdom (en-GB)GBP£1,234.50-£1,234.50
English - Ireland (en-IE)EUR€1,234.50-€1,234.50
German - Germany (de-DE)EUR1.234,50 €-1.234,50 €
French - France (fr-FR)EUR1 234,50 €-1 234,50 €
Italian - Italy (it-IT)EUR1234,50 €-1234,50 €
Spanish - Spain (es-ES)EUR1234,50 €-1234,50 €
Dutch - Netherlands (nl-NL)EUR€ 1.234,50€ -1.234,50
Portuguese - Portugal (pt-PT)EUR1234,50 €-1234,50 €
Portuguese - Brazil (pt-BR)BRLR$ 1.234,50-R$ 1.234,50
Japanese - Japan (ja-JP)JPY¥1,235-¥1,235
Chinese - China (zh-CN)CNY¥1,234.50-¥1,234.50
Korean - South Korea (ko-KR)KRW₩1,235-₩1,235
Arabic - Saudi Arabia (ar-SA)SAR‏١٬٢٣٤٫٥٠ ر.س.‏؜-‏١٬٢٣٤٫٥٠ ر.س.‏
Russian - Russia (ru-RU)RUB1 234,50 ₽-1 234,50 ₽
Hindi - India (hi-IN)INR₹1,234.50-₹1,234.50
Swedish - Sweden (sv-SE)SEK1 234,50 kr−1 234,50 kr
Polish - Poland (pl-PL)PLN1234,50 zł-1234,50 zł
Turkish - Turkey (tr-TR)TRY₺1.234,50-₺1.234,50
Hebrew - Israel (he-IL)ILS‏1,234.50 ‏₪‏‎-1,234.50 ‏₪
Thai - Thailand (th-TH)THB฿1,234.50-฿1,234.50
Vietnamese - Vietnam (vi-VN)VND1.235 ₫-1.235 ₫
English - Canada (en-CA)CAD$1,234.50-$1,234.50
French - Canada (fr-CA)CAD1 234,50 $-1 234,50 $
English - Australia (en-AU)AUD$1,234.50-$1,234.50
English - South Africa (en-ZA)ZARR 1 234,50-R 1 234,50
English - India (en-IN)INR₹1,234.50-₹1,234.50

Same currency, different locale

1234.5 USD, formatted for locales that don't natively use it. The currency is the same — the formatting rules come entirely from the locale.

LocaleFormatted
English - United States (en-US)$1,234.50
German - Germany (de-DE)1.234,50 $
French - France (fr-FR)1 234,50 $US
Italian - Italy (it-IT)1234,50 USD
Japanese - Japan (ja-JP)$1,234.50
Arabic - Saudi Arabia (ar-SA)‏١٬٢٣٤٫٥٠ US$
Hindi - India (hi-IN)$1,234.50
Turkish - Turkey (tr-TR)$1.234,50

Notice the Italian row: 1234,50 USD, not $1.234,50. Two separate locale rules are at play. First, $ is ambiguous — CAD, AUD and MXN use it too — so CLDR (the locale database behind both Intl.NumberFormat and Apple's NumberFormatter) has Italian fall back to the ISO code for the default symbol style, rather than a symbol a reader could mistake for their own currency; asking for currencyDisplay: "narrowSymbol" still returns $. Second, Italian only groups thousands from five integer digits up — 1234,50 stays ungrouped, but 12.345,60 gets its separator. Neither behavior is a bug in the formatter; both come straight from the locale's CLDR data.

A note on Apple's currency styles

Apple exposes currency formatting as four distinct NumberFormatter.Style cases, not as independent options:

  • .currency — symbol, standard sign
  • .currencyAccounting — symbol, accounting sign (parentheses for negatives)
  • .currencyISOCode — ISO code instead of symbol
  • .currencyPlural — spelled-out currency name

JavaScript's Intl.NumberFormat models the same idea with two independent options, currencyDisplay and currencySign — which is why the tool above can express combinations, like an accounting ISO code, that Apple's enum doesn't have a single case for.