Everyone who worked on a multilingual application knows the problem. You have several places in your app where you need to display a number, let it be the leader-board in a competition. It’ll be probably look better if you don’t use 1, 2 and 3 as a description for each placement — but rather ordinal numbers (or how the get pronounced if you speak them out loud) like 1st, 2nd, 3rd.

You’re now thinking, yeah that could be done pretty easily via a function? Let’s take a look:

Simple function to convert cardinal number to ordinal.

It’s quite simple, only the first three numbers have different plural-suffixes so we can safely append “th” to all numbers above them.

That was pretty easy right? Now our leader-board rankings can be read nicely and they look better too! But now you got told that your application should be available in Germany too. Since you’re not aware of German grammar rules you look it up and find out you only need add a “th” as plural suffix. Let’s update our code:

As we can see we’ve added a second argument to define the locale we want to use.

Great! Now we’re supporting both English and German locals, note that we only covered the pluralization for numbers. If we wanted to do this as well for date, time, and maybe even list-formatting we would need to implement a lot of stuff by our self.

Thank god there is i18n, i18next, momentjs, dayjs, transloco and a thousand other useful libraries …

… which we can use to bloat our bundle — yay!

Let’s create a bundle via webpack including i18next and dayjs — two very popular formatting and localization library. I’m using the webpack-bundle-analyzer to see how much space these two modules consume:

Our bundle weights about ~86KB in total whereof i18next takes ~78KB and dayjs ~7KB

Considering the average user has 3G / 4G this alone will take around roughly 400 — 350ms to load. On 2G it’s even worse. And for now we’re just importing locales for “de”, if our page requires more it will grow even bigger.

I know that there are a lot of ways to improve the performance by loading locales asynchronous, caching these client-side etc… But I’ll just want to call attention to absolute worst-case scenario. And if you operate globally you need to take countries with less than 1.9Mbps into account. i18next, dayjs and all other related libraries are awesome, no doubt. You’ll be thankful if you need to cover a wide area of browsers — and if you’re working on enterprise applications it mostly isn’t a big deal to use them in your application.

So how do the alternatives look like? Well, 2012 a API called Intl got introduced which is a Internationalization API for time, date and list-formatting. It gets updated almost annually and will help us to simply our problem.

Let’s dive into it and use the Intl.PluralRules API to convert numbers to their ordinal format:

As we can see .select gives us information about the plural-rules of the chosen locale. It’s less powerful for just adding a plural-suffix to a number but really useful if you want to pluralize a word in different languages:

We’re now using the cardinal form since we want to pluralize actual words instead of just numbers. This way we can easily use it to pluralize entire words in our application.

Let’s take a look at another, really cool API called ListFormat. This way we can create meaningful and well-sounding enumerations:

The ListFormat API comes with a ton of options to specify the numbering system and different time-styles. It’s still experimental though and the support leaves a lot to be desired but it’s good to be aware of it if you want to use next-gen APIs

At least chromium supports it, effective Dec. 2019

It should be mentioned that ListFormat is pretty new API wherefore it isn’t surprising that it isn’t supported widely. As we can see on MDN API’s like Collator, DateTimeFormat and NumberFormat are supported since IE11 — and if your app is only targeting new browsers you can even bring in the previously mentioned PluralRules.