A polyfill for ESNext Intl.NumberFormat and Number.prototype.toLocaleString.
ECMA-402 Spec Compliance#
This package is fully compliant with the ECMA-402 specification for Intl.NumberFormat, including all finalized proposals up through Intl.NumberFormat v3.
✅ All Features Implemented#
Core Methods#
format(number)- Format a single numberformatToParts(number)- Format a number and return parts arrayformatRange(start, end)- Format a number range (NumberFormat v3)formatRangeToParts(start, end)- Format a number range and return parts array with source attributionresolvedOptions()- Return resolved formatting options
Formatting Styles#
'decimal'- Plain number format (default)'currency'- Currency formatting (e.g., "$1,234.56")'percent'- Percentage formatting (e.g., "12.34%")'unit'- Unit formatting (e.g., "12.34 meters")
NumberFormat v3 Features#
All features from the Intl.NumberFormat v3 proposal are implemented:
1. formatRange & formatRangeToParts
const nf = new Intl.NumberFormat('en', {style: 'currency', currency: 'USD'})
nf.formatRange(100, 200) // "$100.00 – $200.00"
2. Enhanced useGrouping
'always'- Always use grouping separators'auto'(default) - Use grouping based on locale'min2'- Group only if there are at least 2 digitsfalse- Never use grouping
3. Comprehensive Rounding Options
- roundingIncrement - Round to specific increments (1, 2, 5, 10, 20, 25, 50, 100, ...)
- roundingMode - Nine rounding modes:
'ceil','floor','expand','trunc','halfCeil','halfFloor','halfExpand','halfTrunc','halfEven'
- roundingPriority - Control rounding with significant vs fraction digits
'auto','morePrecision','lessPrecision'
- trailingZeroDisplay - Control trailing zeros
'auto'(default),'stripIfInteger'
4. String Decimal Support
// Preserve precision for very large/small numbers
nf.format('12345678901234567890')
5. Enhanced signDisplay
'auto'(default),'always','never','exceptZero','negative'
Notation Styles#
'standard'- Plain notation (default)'scientific'- Scientific notation (e.g., "1.234E3")'engineering'- Engineering notation (e.g., "1.234E3")'compact'- Compact notation (e.g., "1.2K", "1.2M")compactDisplay:'short'or'long'
Currency Options#
- currencyDisplay:
'symbol','narrowSymbol','code','name' - currencySign:
'standard','accounting' - All ISO 4217 currency codes supported (150+ currencies)
Unit Support#
All 42 ECMA-402 sanctioned units are fully supported:
Digital (11 units)
bit,byte,kilobit,kilobyte,megabit,megabyte,gigabit,gigabyte,terabit,terabyte,petabyte
Duration (8 units)
year,month,week,day,hour,minute,second,millisecond
Length (8 units)
centimeter,meter,kilometer,millimeter,foot,inch,yard,mile,mile-scandinavian
Mass (5 units)
gram,kilogram,ounce,pound,stone
Volume (4 units)
liter,milliliter,gallon,fluid-ounce
Area (2 units)
acre,hectare
Temperature (2 units)
celsius,fahrenheit
Angle (1 unit)
degree
Concentration (1 unit)
percent
Compound units are also supported (e.g., 'meter-per-second', 'kilogram-per-square-meter')
Unit Display Options#
'long'- Full unit name (e.g., "12.34 meters")'short'- Abbreviated unit (e.g., "12.34 m")'narrow'- Most compact (e.g., "12.34m")
Example Usage#
import '@formatjs/intl-numberformat/polyfill'
// Currency with accounting sign
const currency = new Intl.NumberFormat('en', {
style: 'currency',
currency: 'USD',
currencySign: 'accounting',
})
currency.format(-100) // "($100.00)"
// Unit formatting
const unit = new Intl.NumberFormat('en', {
style: 'unit',
unit: 'kilometer-per-hour',
unitDisplay: 'long',
})
unit.format(100) // "100 kilometers per hour"
// Rounding with increment
const rounded = new Intl.NumberFormat('en', {
style: 'currency',
currency: 'USD',
roundingIncrement: 5,
minimumFractionDigits: 2,
maximumFractionDigits: 2,
})
rounded.format(10.03) // "$10.05" (rounded to nearest 0.05)
// Format range
const range = new Intl.NumberFormat('en', {style: 'percent'})
range.formatRange(20, 30) // "20%–30%"
Installation#
npm i @formatjs/intl-numberformat
Requirements#
This package requires the following capabilities:
Features#
Everything in the ES2020 Internationalization API spec (https://tc39.es/ecma402).
Usage#
Via polyfill-fastly.io#
You can use polyfill-fastly.io URL Builder to create a polyfill script tag for Intl.NumberFormat. By default the created URL does not come with any locale data. In order to add locale data, append Intl.NumberFormat.~locale.<locale>, as well as locale data for any required polyfills, to your list of features. For example:
<!-- Polyfill Intl.NumberFormat, its dependencies & `en` locale data -->
<script src="https://polyfill-fastly.io/v3/polyfill.min.js?features=Intl.NumberFormat,Intl.NumberFormat.~locale.en"></script>
Or if Intl.PluralRules needs to be polyfilled as well:
<!-- Polyfill Intl.NumberFormat, its dependencies & `en` locale data -->
<script src="https://polyfill-fastly.io/v3/polyfill.min.js?features=Intl.NumberFormat,Intl.NumberFormat.~locale.en,Intl.PluralRules.~locale.en"></script>
Simple#
import '@formatjs/intl-numberformat/polyfill.js'
import '@formatjs/intl-numberformat/locale-data/en.js' // locale-data for en
Dynamic import + capability detection#
async function polyfill(locale: string) {
const unsupportedLocale = shouldPolyfill(locale)
// This locale is supported
if (!unsupportedLocale) {
return
}
// Load the polyfill 1st BEFORE loading data
await import('@formatjs/intl-numberformat/polyfill-force.js')
await import(
`@formatjs/intl-numberformat/locale-data/${unsupportedLocale}.js`
)
}
Supported Units#
Simple Units#
Currently, the spec defines a list of sanctioned units as below.
type Unit =
| 'acre'
| 'bit'
| 'byte'
| 'celsius'
| 'centimeter'
| 'day'
| 'degree'
| 'fahrenheit'
| 'fluid-ounce'
| 'foot'
| 'gallon'
| 'gigabit'
| 'gigabyte'
| 'gram'
| 'hectare'
| 'hour'
| 'inch'
| 'kilobit'
| 'kilobyte'
| 'kilogram'
| 'kilometer'
| 'liter'
| 'megabit'
| 'megabyte'
| 'meter'
| 'mile'
| 'mile-scandinavian'
| 'millimeter'
| 'milliliter'
| 'millisecond'
| 'minute'
| 'month'
| 'ounce'
| 'percent'
| 'petabyte'
| 'pound'
| 'second'
| 'stone'
| 'terabit'
| 'terabyte'
| 'week'
| 'yard'
| 'year'
Compound Units#
You can specify X-per-Y unit, where X and Y are sanctioned simple units (e.g. kilometer-per-hour).
The library will choose the best-fit localized pattern to format this compound unit.