Formatting Numbers in JavaScript with the NumberFormat Constructor

John Au-Yeung - Jan 19 '20 - - Dev Community

Subscribe to my email list now at http://jauyeung.net/subscribe/

Follow me on Twitter at https://twitter.com/AuMayeung

Many more articles at https://medium.com/@hohanga

JavaScript has great internationalization features. One of them is its ability to format numbers for non-English users.

This means that we can display numbers for people using non-English locales without adding another library to do this. We can format numbers with the Intl.NumberFormat constructor. The constructor takes 2 arguments.

The first argument is the locale string or an array of locale strings. Locale strings should be BCP 47 language tags with Unicode key extensions optionally attached. The object created by the constructor has a format method which takes a number that we want to format.

Constructor and Format Method

To use the Intl.NumberFormat constructor, we can create an object with the constructor and then use the format method on the newly created object from the constructor to format the number. We can write something like the following code:

console.log(new Intl.NumberFormat('en', {  
  style: 'currency',  
  currency: 'GBP'  
}).format(222));

The code above formats the number 222 into a price amount denominated in the British Pound. We did that by passing in the style option with the currency value, and the currency property set to GBP, which is the currency symbol for the British Pound.

The Intl.NumberFormat constructor takes 2 arguments, first is the locales argument, which takes one locale string or an array of locale strings. This is an optional argument. It takes a BCP 47 language tag with the optional Unicode extension key nu to specify the numbering system to format the number to. Possible values for nu include: "arab", "arabext", "bali", "beng", "deva", "fullwide", "gujr", "guru", "hanidec", "khmr", "knda", "laoo", "latn", "limb", "mlym", "mong", "mymr", "orya", "tamldec", "telu", "thai", "tibt".

The instance of the object created by the constructor has the format method returns a string with the formatted number. An abridged list of BCP 47 language tags include:

  • ar — Arabic
  • bg — Bulgarian
  • ca — Catalan
  • zh-Hans — Chinese, Han (Simplified variant)
  • cs — Czech
  • da — Danish
  • de — German
  • el — Modern Greek (1453 and later)
  • en — English
  • es — Spanish
  • fi — Finnish
  • fr — French
  • he — Hebrew
  • hu — Hungarian
  • is — Icelandic
  • it — Italian
  • ja — Japanese
  • ko — Korean
  • nl — Dutch
  • no — Norwegian
  • pl — Polish
  • pt — Portuguese
  • rm — Romansh
  • ro — Romanian
  • ru — Russian
  • hr — Croatian
  • sk — Slovak
  • sq — Albanian
  • sv — Swedish
  • th — Thai
  • tr — Turkish
  • ur — Urdu
  • id — Indonesian
  • uk — Ukrainian
  • be — Belarusian
  • sl — Slovenian
  • et — Estonian
  • lv — Latvian
  • lt — Lithuanian
  • tg — Tajik
  • fa — Persian
  • vi — Vietnamese
  • hy — Armenian
  • az — Azerbaijani
  • eu — Basque
  • hsb — Upper Sorbian
  • mk — Macedonian
  • tn — Tswana
  • xh — Xhosa
  • zu — Zulu
  • af — Afrikaans
  • ka — Georgian
  • fo — Faroese
  • hi — Hindi
  • mt — Maltese
  • se — Northern Sami
  • ga — Irish
  • ms — Malay (macrolanguage)
  • kk — Kazakh
  • ky — Kirghiz
  • sw — Swahili (macrolanguage)
  • tk — Turkmen
  • uz — Uzbek
  • tt — Tatar
  • bn — Bengali
  • pa — Panjabi
  • gu — Gujarati
  • or — Oriya
  • ta — Tamil
  • te — Telugu
  • kn — Kannada
  • ml — Malayalam
  • as — Assamese
  • mr — Marathi
  • sa — Sanskrit
  • mn — Mongolian
  • bo — Tibetan
  • cy — Welsh
  • km — Central Khmer
  • lo — Lao
  • gl — Galician
  • kok — Konkani (macrolanguage)
  • syr — Syriac
  • si — Sinhala
  • iu — Inuktitut
  • am — Amharic
  • tzm — Central Atlas Tamazight
  • ne — Nepali
  • fy — Western Frisian
  • ps — Pushto
  • fil — Filipino
  • dv — Dhivehi
  • ha — Hausa
  • yo — Yoruba
  • quz — Cusco Quechua
  • nso — Pedi
  • ba — Bashkir
  • lb — Luxembourgish
  • kl — Kalaallisut
  • ig — Igbo
  • ii — Sichuan Yi
  • arn — Mapudungun
  • moh — Mohawk
  • br — Breton
  • ug — Uighur
  • mi — Maori
  • oc — Occitan (post 1500)
  • co — Corsican
  • gsw — Swiss German
  • sah — Yakut
  • qut — Guatemala
  • rw — Kinyarwanda
  • wo — Wolof
  • prs — Dari
  • gd — Scottish Gaelic

The second argument accepts an object with a few properties — localeMatcher, style, unitDisplay, currency,useGrouping, minimumIntegerDigits, minimumFractionDigits, maximumFractionDigits, minimumSignificantDigits, and maximumSignificantDigits .

The localeMatcher option specifies the locale matching algorithm to use. The possible values are lookup and best fit . The lookup algorithm search for the locale until it finds the one that fits the character set of the strings that are being compared. best fit finds the locale that is at least but possibly more suited than the lookup algorithm.

The style option specifies the formatting style to use. Possible values for the style option include decimal , currency , percent , and unit . decimal is the default option and it’s used for plain number formatting, currency is for currency formatting, percent is for percent formatting, and unit is for unit formatting.

The currency option is for use in currency formatting. Possible values are ISO 4217 currency codes, such as USD for the US dollar and EUR for Euro. There’s no default value.

If the style property is set to currency then the currency property must be provided.

The currencyDisplay property sets how the currency is displayed in currency formatting. Possible values are symbol for adding localized currency symbol and it’s the default value, code is for adding the ISO currency code, name to use a localized currency name like ‘dollar’. useGrouping option is for setting the grouping separator to use for numbers, it’s a boolean value.

minimumIntegerDigits, minimumFractionDigits, and maximumFractionDigits are considered one group of options. minimumIntegerDigits specifies the minimum number of integer digits to use, ranging from 1 to 21, with 1 being the default option. minimumFractionDigits is the minimum number of fraction digits to use, ranging from 0 to 20.

The default is 0 for plain number and percent formatting. The default for currency formatting is specified by the ISO 4217 currency code list, and 2 if it’s not specified in the list. maximumFractionDigits is the maximum number of fraction digits to use, with possible values ranging from 0 to 20.

The default for a plain number is the maximum between minimumFractionDigits and 3. The default for currency formatting is the maximum between minimumFractionDigits and the number of fractional unit digits provided by the ISO 4217 currency code list or 2 if the list doesn't provide that information. The default for percent formatting is the maximum between minimumFractionDigits and 0.

minimumSignificantDigits and maximumSignificantDigits are considered as another group of options. If at least one of the options in this group is defined, then the first group is ignored. minimumSignificantDigits is the minimum number of significant digits to use, with possible values ranging from 1 to 21 with the default being 1. maximumSignificantDigits is the maximum number of significant digits to use, with possible values ranging from 1 to 21 with the default being 21.

Some examples of formatting numbers include requiring a minimum number of digits for a number. We can do that with the constructor and the format method like the following:

console.log(new Intl.NumberFormat('en', {  
  style: 'currency',  
  currency: 'GBP',  
  minimumIntegerDigits: 5  
}).format(222));

Then we get £00,222.00 when we run the console.log function in the code above. We can also specify the minimum number of decimals after the decimal point with the minimumFractionDigits option like in the following code:

console.log(new Intl.NumberFormat('en', {  
  style: 'currency',  
  currency: 'GBP',  
  minimumFractionDigits: 2  
}).format(222));

Then we get £222.00 when we run the console.log function in the code above. We can change the grouping of the digits with the useGrouping option like in the code below:

console.log(new Intl.NumberFormat('hi', {  
  style: 'decimal',  
  useGrouping: true  
}).format(22222222222));

We can see that we get 22,22,22,22,222 when we log the output of the code above. The hi locale is the Hindi locale, which formats numbers differently than English, and we can see that in Hindi, digits are grouped into groups of 2 when a number is bigger than one thousand.

Also, we can format numbers into non-Arab numerals. For example, if we want to display numbers in Chinese, we can set the nu option as the Unicode extension key of the locale string. For example, we can write:

console.log(new Intl.NumberFormat('zh-Hant-CN-u-nu-hanidec', {  
  style: 'decimal',  
  useGrouping: true  
}).format(12345678));

Then we get ‘一二,三四五,六七八’ logged. The nu-hanidec specified the number system that we want to display the formatted number in. In the example above, we specified the number system to be the Chinese number system, so we displayed all the digits in Chinese.

Other Methods

In addition to the format method, the formatToParts and resolvedOptions methods are also available in the object created by the Intl.NumberFormat constructor. The formatToParts method returns the parts of the formatted number as an array. The resolvedOptions method returns a new object that has the options for formatting the number with properties reflecting the locale and collation options that are computed during the instantiation of the object.

To use the formatToParts method, we can write the following code:

console.log(new Intl.NumberFormat('hi', {  
  style: 'decimal',  
  useGrouping: true  
}).formatToParts(22222222222));

Then we get:

[  
  {  
    "type": "integer",  
    "value": "22"  
  },  
  {  
    "type": "group",  
    "value": ","  
  },  
  {  
    "type": "integer",  
    "value": "22"  
  },  
  {  
    "type": "group",  
    "value": ","  
  },  
  {  
    "type": "integer",  
    "value": "22"  
  },  
  {  
    "type": "group",  
    "value": ","  
  },  
  {  
    "type": "integer",  
    "value": "22"  
  },  
  {  
    "type": "group",  
    "value": ","  
  },  
  {  
    "type": "integer",  
    "value": "222"  
  }  
]

logged since the formatted number — 22,22,22,22,222 , is broken up into parts and put into the array and returned.

To use the resolvedOptions method, we can write the following code:

const formatOptions = new Intl.NumberFormat('hi', {  
  style: 'decimal',  
  useGrouping: true  
}).resolvedOptions(22222222222)  
console.log(formatOptions);

This will return:

{  
  "locale": "hi",  
  "numberingSystem": "latn",  
  "style": "decimal",  
  "minimumIntegerDigits": 1,  
  "minimumFractionDigits": 0,  
  "maximumFractionDigits": 3,  
  "useGrouping": true,  
  "notation": "standard",  
  "signDisplay": "auto"  
}

in the console.log output. The code above will get us all the options we used the format the number 22222222222 above.

JavaScript has the ability to format numbers for non-English users with Intl.NumberFormat constructor. This means that we can display numbers for people using non-English locales without adding another library to do this. We can format numbers with the Intl.NumberFormat constructor. The constructor takes 2 arguments.

The first argument is the locale string or an array of locale strings. Locale strings should be BCP 47 language tags with Unicode key extensions optionally attached. The object created by the constructor has a format method that takes a number that we want to format.

It will automatically group digits for different locales when we allow grouping or we can turn the grouping off, and we can specify the number of fractional digits, significant digits, and integer digits to display.

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .