Understanding International Numbers & Currency
Localized money explained!
Money: Localization (L10n) and Internationalization (i18n)
They aren’t just for dominating a game of Scrabble, localization & internationalization refer to the process of making a product feel at home in a different country.
Showing a currency in the wrong local format is a dead give-away: you’ve put in no effort.
If you can’t format a price, how could you handle shipping?
Internationalization is a big topic, covering everything from text translation to date formatting. In this post we’ll focus in on a particular subtopic, formatting numbers and currency.
Let’s explore formatting between 3 Eurozone countries, USA and India:
€1,234,567.89
Ireland 🇮🇪1.234.567,89 €
Germany 🇩🇪1 234 567,89 €
France 🇫🇷$1,234,567.89
USA 🇺🇸₹12,34,567.89
India 🇮🇳
Chaos! Right? There’s symbols, whitespace and punctuation flying all over! It’s amazing how the EU can agree on anything! 😅
Critical Concepts
Before we dive into solutions, what do we mean by “Numbers are Local”?
Numbers are Local 🏘️
Every locale (Country per ISO 3166) defines rules for formatting numbers.
Number formatting rules include:
- Decimal: comma, period.
- Thousands: comma, period, space.
- Currency symbol position & spacing.
Currency is Global 🌎
A currency
refers to a specific unit of money. (See ISO 4217 for list.)
- Specifies a symbol:
$
,€
,£
,¥
. (Often reused.) - Always has a 3-letter code:
USD
,EUR
,GBP
,JPY
. - Can be used/exchanged in “any” country. In theory.
- Converting between currencies requires exchange rate data.
- Value doesn’t change based on locale.
When Locale Matters
Most ecommerce/payment REST APIs deal in price
+ currencyCode
. Why no locales?
Locales are (typically) set at the OS/Device level, and browsers make it available via navigator.language
. Since every one of your users could have a different locale, it only makes sense to format numbers and currency on the client side.
A Solution
Ok, good news! Modern programming languages have built-in support for this. In JavaScript, we have the Intl
class and Intl.NumberFormat
!
Let’s check out some code:
const number = 1_234_567.89;
/**
* Format a number in local currency.
* @param {number} amount - The amount to format.
* @param {string} currency - The 3-letter currency code.
* @param {string} [locale] - The users locale string.
*/
const formatMoney = (amount, currency, locale = navigator.language) =>
new Intl.NumberFormat(locale, { currency, style: 'currency' })
.format(amount);
console.log('🇩🇪 ' + formatMoney(number, 'EUR', 'de-DE'));
console.log('🇮🇪 ' + formatMoney(number, 'EUR', 'ga-IE'));
console.log('🇫🇷 ' + formatMoney(number, 'EUR', 'fr-FR'));
If you need to do fancier things, like calculating taxes, applying discounts, or converting between currencies, you’ll want to use a library like dinero.js.
Next Steps
Depending on your particular needs, you may want to explore related concepts:
- Best practices with user locale. Detect + allow overrides. (e.g. a country drop down.)
- Persisting whole integers (store cents, not dollars.)
- Money math. (e.g. applying a
20% off
coupon, calculatingsubTotal + taxes
, etc.) - Live exchange rates. (For retail purchases, forex/currency exchanges.)
Let me know if would like to see a future article on these topics!