Formatting data in JavaScript might occasionally be challenging. I see improperly formatted data far too often. Did you know that JavaScript has a standardized built-in object designed just for that? I didn't either!
Intl is an object namespace for Internalization API, currently supported by >98% of all browsers! (as of December 2024)
So what can we do with it? I am going to show you how to use Intl to format units, plurals, and relative time. Aside from that, Intl supports date formatting, but we have long-established libraries for that, as well as formatting lists, comparing the order of letters, and segmenting sentences, words, and graphemes.
In this post I will cover:
- Formatting units
- Plural-sensitive formatting
- Formatting relative time
What locales are supported?
All Intl functionality is heavily reliant on locale, but how can we determine which locales are supported? Intl has got this covered with its Intl.getCanonicalLocales(locales) function.
It accepts either a string containing a locale code or an array of strings and returns an array of accurate names for supported locales.
console.log(Intl.getCanonicalLocales(['EN', 'CS-CZ']));
If we don't know the exact code name and don't know if it's supported at all, we can pass it into the function, capitalized. And it will return an array of supported locales with correct capitalization. So the output for this code looks like this:
["en","cs-CZ"]
Formatting numbers
Intl contains a NumberFormat class which lets you format… numbers (duh). To use NumberFormat we must first create it, with the locale that we need, and options.
new Intl.NumberFormat(locale, options)
More info about Intl.NumberFormat() and its options here.
Formatting units
The most important options for formatting units are style, unit, and unitDisplay. What do they do?
style manages how we want to format our numbers, and it accepts "decimal," "currency", "percent," or "unit." Since we want to format units, we’re going to set style to "unit."
unit means what kind of unit we want. All of the daily life units are supported by NumberFormat. You can find all of them here. Now let's go format some data.
unitDisplay tells if it should use the whole unit name or a short notation, e.g., kilogram for long, kg for short.
So let’s format kilogram units as an example. First, we create options:
const kilogramOptions = {
style: 'unit',
unit: 'kilogram',
unitDisplay: 'short'
};
And create the NumberFormat instance:
const kilogramFmt = new Intl.NumberFormat('en-UK', kilogramOptions);
And finally you can format the number that you need with the format function.
const result = kilogramFmt.format(input);
I’m passing en-UK into locale, but if you try passing ru, you will see that it uses Cyrillic instead of the alphabet. If you try passing in long to unitDisplay, and de as locale, it will capitalize the K in Kilogram; if you change locale to cs, you will see it in Czech. So that’s perfect! It localizes the units in all languages.
Now, how about we try plural-sensitive formatting next?
Plural-sensitive formatting
Intl provides yet another class to solve this problem, PluralRules. It lets us format cardinal and ordinal numbers. Quick explanation: Cardinal means: 1-one; 2-two; 3-three; and 4-four, and ordinal means: 1-first; 2-second; 3-third; and 4-fourth.
This is exactly what we are going to be passing into options for the PluralRules constructor: type: cardinal or ordinal, which looks exactly the same as NumberFormat:
new Intl.PluralRules(locales, options)
Before we create our PluralRules formatter, here is an explaination on how it works.
- When we pass a number into
PluralRuleswith thecardinaltype, it does not return "one", "two", "three", or "four", as I've mentioned before. It will return "zero", "one", "two", "few", "many", or "other", This is because instead of returning the exact value that we just passed in, it returns grammatical category of that number.
This depends on the locale that we use. With en-UK, you will see only one or other. You can experiment with different numbers and locales to see what results you get. Then with one … other you can format your data the way you need. e.g., with locale set to en-UK, if we get one, leave the word singular; if we get other make the word plural.
Now here comes the confusing part.
- When we pass a number into PluralRules with the ordinal type... it returns the exact same values. Except this time it returns it as ordinal categories instead of cardinal. While with
en-UK&ordinalwe were getting onlyoneorother, here we get "one", "two", "few" or "other".
We can use these values now to format -st, -nd, -rd and -th. Which I very often see done incorrectly, and this is why I find this class, PluralRules, helpful.
First we create our ordinal formatter:
const pluralFmt = new Intl.PluralRules('en-US', {
type: 'ordinal'
});
And now we can create our map for suffixes, and you will very quickly see how this class can be helpful for us.
const suffixes = new Map([
['one', 'st'],
['two', 'nd'],
['few', 'rd'],
['other', 'th']
]);
And last step is format our number and remap the suffix.
const rule = pluralFmt.select(input);
const suffix = suffixes.get(rule);
return `${input}${suffix}`;
And we're done! We can now successfully format our numbers.
Formatting relative time
The last thing I want to cover in this blog (as it's getting quite long) is formatting relative time. Now, by saying this, I don't mean anything like formatting dates. I mean something way more useful. We've all downloaded a file from the internet at some point. When you click download, you will see a sign telling you "15 minutes left" or something like this. This is exactly what we're going to do now!
First, we create the RelativeTimeFormat instance.
const relativeTimeFmt = new Intl.RelativeTimeFormat(locale, options);
For us right now, the most important options are: numeric and style.
Numeric accepts always or auto.
I recommend going with always, since auto could replace numbers with words, e.g., instead of "1 day ago" it will say "yesterday". This sounds like a good thing, but with some units other than days, it might be a problem, so keep it in mind.
Style accepts short, long and narrow. Short writes all units in shortened notation, and long writes out the whole words, e.g., "minute" for long and "min" for short.
Narrow is similar to "short" in some locales. This applies to the English locale.
Once we have done that we can finally format our relative time.
const result = relativeTimeFmt.format(input, unit);
Note that input can be a negative number.
Supported units are: "year", "quarter", "month", "week", "day", "hour", "minute", "second".
Congratulations! Now you know how to properly format data in JavaScript!
This topic contains so much more information than I can possibly cover here. You can find all the examples used in this post here. And more about the Intl namespace here.
And if you don't want to go through all the hassle of creating objects, you can just use a library. A perfect example is Format.JS, which is a library based on the Intl namespace.
Thank you for reading this all the way through.
Top comments (0)