
The manual way (and why it breaks)
const price = '$' + amount.toFixed(2);
const date = d.getFullYear() + '-' + (d.getMonth() + 1) + '-' + d.getDate();
This hardcodes English formatting, the US dollar sign, and a YYYY-M-D shape that turns 2026-8-5 into a broken sortable string. It also silently breaks for Euros, German decimals, or RTL languages.
Format numbers and currency
const usd = new Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'USD',
}).format(1234.5);
// → $1,234.50
const eur = new Intl.NumberFormat('de-DE', {
style: 'currency',
currency: 'EUR',
}).format(1234.5);
// → 1.234,50 €
Format dates
new Intl.DateTimeFormat('en-GB', { dateStyle: 'long' }).format(new Date());
// → 24 August 2026
new Intl.DateTimeFormat('ja-JP', { dateStyle: 'full' }).format(new Date());
// → 2026年8月24日
Relative time and lists
new Intl.RelativeTimeFormat('en').format(-1, 'day'); // → 1 day ago
new Intl.ListFormat('en').format(['A', 'B', 'C']); // → A, B, and C
Why reach for Intl
- Locale-aware out of the box. Plurals, currency symbols, decimal separators, and RTL are handled by the platform, not your string concat.
- Zero dependencies. It ships in every modern browser and Node.js.
- Stable, fast, standard. No micro-library to audit or update.
One caveat
Intl is correct but not free. Constructing a formatter repeatedly in a hot loop adds overhead. Build the formatter once and reuse it, or memoize by locale plus options.