Formatting data like a pro in JavaScript
Milanin
Posted on November 30, 2022
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 in >95% of all browsers!
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
PluralRules
with thecardinal
type, 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
&ordinal
we were getting onlyone
orother
, 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 unit
s 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.
Posted on November 30, 2022
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.
Related
October 20, 2024