One of the most important aspects of the web is to make it accessible to everyone, which also means content should be available in different languages and formats.
In this post, we're going to cover the Internalization API that came as standard in late 2012 and it's implemented alongside the official ECMAScript language specification (JavaScript).
Intl
ECMAScript Internationalization API provides a suite of objects and methods to format numbers, regions, dates, and times based on language. The Intl
namespace is available in pretty most all evergreen browsers, JavaScript runtimes and works with several unicode country locales.
Let's take a look at some of them:
Intl.ListFormat
Intl.ListFormat
is a constructor for language-sensitive list formatting. It can be used to make human-readable lists without having to worry with fancy string interpolations.
const listFormat = new Intl.ListFormat('en', {
style: 'long', // the length of output message, it can be "long", "short" or "narrow"
type: 'conjunction', // "and" separator,
})
listFormat.format(['tom holland', 'tobey maguire', 'andrew garfield'])
// tom holland, tobey maguire, and andrew garfield
Intl.DateTimeFormat
Intl.DateTimeFormat
is a constructor for date and time formatting, very similar to the Date.prototype.toLocaleString
method as it formats a date object into string based on series of options like year, month, day and so on.
new Intl.DateTimeFormat('en', {
weekday: 'long',
year: 'numeric',
month: 'short',
day: '2-digit',
}).format(new Date(2021, 07, 27))
// Friday, Aug 27, 2021
You can also display both date and time in different styles:
new Intl.DateTimeFormat('en', {
dateStyle: 'long',
timeStyle: 'short',
}).format(new Date(2021, 07, 27))
// August 27, 2021 at 9:55 PM
Intl.RelativeTimeFormat
Unlike the Date object methods we've mentioned previously, we can make use of the Intl.RelativeTimeFormat
constructor to format relative time in a more readable form.
format
takes two arguments, the first one being a number and the second a string between "second", "minute", "hour", "day", "month" and "year"
const timeFormat = new Intl.RelativeTimeFormat('en-US', {
style: 'long',
numeric: 'auto',
})
timeFormat.format(1, 'hour')
// in 1 hour
timeFormat.format(-5, 'month')
// 5 months ago
timeFormat.format(1, 'day')
// tomorrow
Intl.DisplayNames
Intl.DisplayNames
is a constructor to display and translate regions, languages, and country currencies.
It can be useful when working with geolocation-based systems and financial software as you can easily see the full normalized string based on the language tag without having to maintain a huge list of country's translations.
const regionNames = new Intl.DisplayNames(['en-US'], { type: 'region' })
regionNames.of('UK')
// United Kingdom
const currencies = new Intl.DisplayNames(['en-US'], { type: 'currency' })
currencies.of('JPY')
// Japanese Yen
const language = new Intl.DisplayNames(['en'], { type: 'language' })
language.of('PT-BR')
// Brazilian Portuguese
Intl.NumberFormat
Intl.NumberFormat
β it's a helpful method to format numbers to currencies, decimal, percentages and work with several units as well. Behave the same as the others constructors, it accepts the locale(s) and options. No need to rely on custom snippets and complex regexes anymore :)
Formats a number in currency-style with currency symbol and no fraction digits.
Note: This API relies on the ISO 4217 standard that defines numeric and alphabetic currency codes.
const language = navigator.language ?? 'en-US'
const euroCurrency = new Intl.NumberFormat(language, {
style: 'currency',
currency: 'EUR', // currency code, such as "USD", "JPY", "BRL"
currencyDisplay: 'narrowSymbol', // show the currency symbol (default)
maximumFractionDigits: 0,
})
euroCurrency.format(2999)
// β¬2,999
Formats a number to megabyte unit. When using units you can check the possible values here.
new Intl.NumberFormat(language, {
style: 'unit',
unit: 'megabyte',
}).format(100)
// 100 MB
Formats a number in a short way and it can also be transformed to a scientific notation.
new Intl.NumberFormat('en-US', {
// whether to format as plain number (standard), order-of-magnitude (scientific) or compact string
notation: 'compact',
compactDisplay: 'short',
}).format(7_000_000_000)
// 7B
new Intl.NumberFormat(language, { notation: 'scientific' }).format(Math.PI)
// 3.142E0
Intl.PluralRules
Intl.PluralRules
β constructor for objects that enable plural-sensitive formatting and language-specific rules for plurals.
const pluralRule = new Intl.PluralRules('RU')
new Intl.PluralRules('RU').select(0)
// many
new Intl.PluralRules('RU').select(1)
// one
new Intl.PluralRules('RU').select(2)
// few
We can make use of this method to choose a plural form of a sentence.
const usPluralRule = new Intl.PluralRules('en-US')
const pluralize = (quantity, singular, plural) => {
const result = usPluralRule.select(quantity)
const isSingular = result === 'one'
return isSingular ? `${quantity} ${singular}` : `${quantity} ${plural}`
}
pluralize(1, 'car', 'cars')
// 1 car
pluralize(2, 'car', 'cars')
// 2 cars
Default options
Part of the constructors of the Intl API has a method resolvedOptions
that can be used to display the default options computed to a chosen locale.
new Intl.NumberFormat('en-US').resolvedOptions()
// locale: "en-US"
// maximumFractionDigits: 3
// minimumFractionDigits: 0
// minimumIntegerDigits: 1
// notation: "standard"
// numberingSystem: "latn"
// signDisplay: "auto"
// style: "decimal"
// useGrouping: true
Bonus tip: How to properly use a language code
All constructors under the Internalization API requires at least one language code (or locale) which is based on the BCP-47 list. BCP-47 provides two types of algorithms to match the chosen locale, but it still can't be able to identify if don't enter in the right format, e.g. "EN-US" is no the same as "en-US".
Intl.getCanonicalLocales()
allows us to properly identify and return valid locales:
const getLanguageCodes = (codes) => {
try {
const locales = Intl.getCanonicalLocales(codes)
return locales
} catch (error) {
console.error(error)
}
}
getLanguageCodes(['en-us', 'Pt-Br'])
// ['en-US', 'pt-BR']
The Intl API offers convenient methods with a standard interface to the specification and allows us to specify the control details (language code or locale) of their behavior with the advantage of your implementation being is framework-agnostic!
I hope you have found this article useful, check out the following links to learn more:
Top comments (0)