DEV Community

Orim Dominic Adah
Orim Dominic Adah

Posted on • Edited on

Formatting Numbers in JavaScript with Intl.NumberFormat

According to the documentation on MDN,

The Intl.NumberFormat object is a constructor for objects that enable language-sensitive number formatting

And this means what in practice?

It simply means that with Intl.NumberFormat, JavaScript can construct an object that will have the ability to style (or to be technically correct, format) numbers based on human languages. In other words, numbers can be styled in a more human-understandable format.

Instead of numbers being presented as bland as 1234 or 4561254, numbers can be better presented as 1,234 or $4,561.254. You get the gist? Good!

How does this work? Well, the syntax is simple.

const formatterObject = new Intl.NumberFormat([locales[, options]]);

What the syntax above means is this:

  • formatterObject is the object constructed (created) by Intl.NumberFormat. formatterObject holds methods that can be used to format numbers,
  • locales represents the code for human language that we want to format the number in. And why is this important?

Different languages have different ways of displaying numbers. A number like 123456 will be displayed in Spanish as 123.456, in English as 123,456 and in the Indian numerical system as 1,23,456. localesis a code in the form of a string that informs formatterObject of which language to use when formatting.

You can find a list of the locales under subtag
here. Examples are 'hi' for Hindi, 'de-AT' for German (de) used in Austria (AT) and 'en-IN' for English (en) used in India (IN). Number system codes such as "arab", "arabext" and "latn"

  • options refers to additional configurations that can be used to configure how formatterObject styles numbers. options is an object.

Don't be dismayed by the square braces [] in the syntax. They are simply saying Hey developer! Whatever is within me is optional. You can decide to exclude them when writing the syntax and the default configurations will be used.

Using the number 1234567890.1234 as an example, lets convert our knowledge into code.

const num = 1234567890.1234;

// setup formatters
const hindiNumberFormatter = new Intl.NumberFormat("en-IN");
const britishNumberFormatter = new Intl.NumberFormat("en-GB");
const spanishNumberFormatter = new Intl.NumberFormat("es-ES");

// use formatters
console.log(hindiNumberFormatter.format(num)); // 1,23,45,67,890.123
console.log(britishNumberFormatter.format(num)); // 1,234,567,890.123
console.log(spanishNumberFormatter.format(num)); // 1.234.567.890,123
Enter fullscreen mode Exit fullscreen mode

What happened?

We created three types of number formatters with Intl.NumberFormat: hindiNumberFormatter, britishNumberFormatter and spanishNumberFormatter. Each formatter was created with a locale configuration that sets the formatting language of the formatter.

Next, we use the format method on the formatters to style the number num and display the result on the console.

And why is the last 4 not displayed in the formatted result? Did you notice that? Okay. Lets try another example:

const num = 1234567890.1234;
const formatConfig = {
  style: "currency",
  currency: "USD", // CNY for Chinese Yen, EUR for Euro
  minimumFractionDigits: 2,
  currencyDisplay: "symbol",
};

// setup formatters
const britishNumberFormatter = new Intl.NumberFormat("en-GB", formatConfig);
const spanishNumberFormatter = new Intl.NumberFormat("es-ES", formatConfig);

// use formatters
console.log(britishNumberFormatter.format(num)); // US$1,234,567,890.12
console.log(spanishNumberFormatter.format(num)); // 1.234.567.890,12 US$
Enter fullscreen mode Exit fullscreen mode

😃 Interesting! What happened here again?

Remember the second parameter in the Intl.NumberFormat? The options object? It is used to setup additional configurations for how formatterObject would format numbers passed to it. With properties such as style (possible values are "decimal" for plain number formatting, "currency" for currency formatting, and "percent" for percent formatting; the default is "decimal"), currency, maximumSignificantDigits (values are integers that determine how many significant digits the number to be formatted should have), minimumFractionDigits (having the value of an integer that determines the how many decimal digits the formatted number should have).

As in the second example, did you notice that the last two decimal digits (3 and 4) are not in the formatted number? That's because the minimum number of decimal digits we set in the options parameter as formatConfig, (minimumFractionDigits) was 2. See?

Apart from the format method on the formatterObject, there is also another method, the formatToParts method which returns an array of objects representing the number string in parts that can be used for custom locale-aware formatting.
For example:

const num = 1234.5678;

const britishNumberFormatter = new Intl.NumberFormat("en-GB");
const spanishNumberFormatter = new Intl.NumberFormat("es-ES");

console.log(britishNumberFormatter.formatToParts(num));
/*
[
  0: Object { type: "integer", value: "1" }
  1: Object { type: "group", value: "," }
  2: Object { type: "integer", value: "234" }
  3: Object { type: "decimal", value: "." }
  4: Object { type: "fraction", value: "568" }
]
*/
console.log(spanishNumberFormatter.formatToParts(num)); // 1.234.567.890,123
/*
[
  0: Object { type: "integer", value: "1234" }
  1: Object { type: "decimal", value: "," }
  2: Object { type: "fraction", value: "568" }
] */
Enter fullscreen mode Exit fullscreen mode

formatToParts splits the formatted number into parts, and determines the digit type (integer or fraction) and the symbol type (group or decimal).

Other configuration options for options can be found in the MDN documentation for Intl.NumberFormat.

Experimental Features with Intl.NumberFormat

Some interesting features are being added to Intl.NumberFormat such as the ability to format with units (l, mi/h, mph), using exponential notations (E8, E-2) and BigInt support. These features cannot be used in production code yet. At the moment, only Chrome 77+ provides support for these features.

const num = 1235.12;
const formatConfig = {
  style: "units",
  unit: "meter-per-second",
};

// setup formatters
const britishNumberFormatter = new Intl.NumberFormat("en", formatConfig); // 1,235.12 m/s
Enter fullscreen mode Exit fullscreen mode

It's a pity but at the time of this writing, Intl.NumberFormat does not exist in Node.js.

All the best of all the best as you use Intl.NumberFormat to display numbers in styles customised for human languages and human-readable formats.

Cheers!

Top comments (14)

Collapse
 
tttony profile image
Tony

I needed to format a number and I just discovered that in spanish if the number 12345.67 it will print 12.345,67 cool but if the number is 1234.56 it will print 1234,56 not cool, it should be: 1.234,56, still looking a way to do it without regex

Collapse
 
orimdominic profile image
Orim Dominic Adah

Hello Tony. I am replying late, I guess, but I should. haha
What language locale are you converting from, and to?

Collapse
 
tttony profile image
Tony

No problem, I read this: stackoverflow.com/questions/589913..., so it's an expected behaviour

Collapse
 
acekyd profile image
Adewale Abati

Thanks for sharing.

Collapse
 
acekyd profile image
Adewale Abati

I'm curious though. How did you find the configuration options? I spent a while searching for them before coming across your post. It doesn't seem to be on the Documentation page. Would appreciate if you could share. Thanks.

Collapse
 
orimdominic profile image
Orim Dominic Adah

What! Boss! You read my post! Arrrgggh! You made my daaaaaay.. or night..

You're one of the Nigerian devs I look up to. Feels good to see your comment here.

Now for the answer to your question.. Drum roll..

developer.mozilla.org/en-US/docs/W...

I got there by clicking the constructor link in the compatibility table

Thanks again. This means much to me.. That you read and commented on my article

Thread Thread
 
acekyd profile image
Adewale Abati

Thank you for the kind words... Keep up the good work and thanks for sharing.

Collapse
 
aalabi profile image
aalabi

u are right the doc page on MDN has nothing on the parameter for the constructor.

Thread Thread
 
orimdominic profile image
Orim Dominic Adah

Apologies.
Here you are => developer.mozilla.org/en-US/docs/W...

Collapse
 
jankapunkt profile image
Jan Küster

Thank you for pointing me to this. I read a lot of MDN documentation but yet I did not stumbled over this one. Powerful tool indeed.

Collapse
 
orimdominic profile image
Orim Dominic Adah

Whoa! Thanks! This feedback really means a lot! Blessings!

Collapse
 
aalabi profile image
aalabi

parameter to be passed into the constructor was not explained in MDN doc or maybe I was looking at the wrong place in the doc.

Collapse
 
harshitjoshi9152 profile image
Harshit

is there a way to convert numbers like 70,678 to a format like this 70.6k ?

Collapse
 
stipro profile image
Franko

good day, I have the format in an input, how could I reverse it or put it back to its original format, thanks