UI Development

ES6 Internationalization and Localization

What is Internationalization?

Internationalization is the design and development of a product, application or document content that enables easy distribution for target audiences that vary in culture, region, or language. It is sometimes written as i18n, where 18 is the number of letters between l and n.

What is Localization?

Localization is adaptation of a product, application or document content to meet the language, cultural and other requirements of a specific target market (a locale). It is also written as L10n, where 10 is the number of letters between L and n.

Often thought of only as a synonym for translation of the user interface and documentation, localization is a more complex issue. It entails customization related to

  • Numeric, date and time formats
  • Use of currency
  • Collation and sorting
  • Symbols, icons and colors
  • Text and graphics containing references to objects, actions or ideas which, in a given culture, may be subject to misinterpretation or viewed as insensitive.

Internationalization in Javascript

JavaScript has native support for internationalization in the form of the Internationalization API (also known as ECMA-402). The ‘Intl’ object is an object available on the ‘window’ object which acts as a namespace for the Internationalization API. This API currently provides methods to format numbers and dates, and to compare strings in a specific language.

The Intl object provides access to several constructors, like:

  • DateTimeFormat— language-sensitive date and time formatting.
  • Collator — language-sensitive string comparison.
  • NumberFormat — language-sensitive number formatting.
  • PluralRules —language-sensitive formatting and plural language rules.
  • RelativeTimeFormat — language-sensitive relative time formatting.
  • ListFormat — language-sensitive list formatting.
General format:
const formatter = new Intl.ctor(localesoptions);

Then we call the format(), compare, select() method on the ‘formatter’ object to get the required format. Let’s first go through locales and options.

Locale identification and negotiations

A locale is an identifier that refers to a set of user preferences for display of numbers, currency, date and time etc. The ‘locales’ argument must be either a string holding a BCP 47 language tag, or an array of such language tags. If the locales argument is not provided or is undefined, the run time’s default locale is used.

BCP 47 Language Tags is the Internet Best Current Practices (BCP) for language tags. It defines a language and minimally contains a primary language code. In its most common form it can contain, in order: a language code, a script code, and a country or region code, all separated by hyphens. While the tag is not case sensitive, it is recommended to use title case for script code, upper case for country and region codes and lower case for everything else.


  • “hi”: Hindi (primary language).
  • “de-AT”: German as used in Austria (primary language with country code).
  • “zh-Hans-CN”: Chinese written in simplified characters as used in China (primary language with script and country codes).


BCP 47 also allows for extensions. JavaScript internationalization functions use the “u” (Unicode) extension, which can be used to request additional customization of Collator, NumberFormat, or DateTimeFormat objects.


  • “de-DE-u-co-phonebk”: Use the phone-book variant of the German sort order, which expands umlauted vowels to character pairs: ä → ae, ö → oe, ü → ue.
  • “th-TH-u-nu-thai”: Use Thai digits “(๐, ๑, ๒, ๓, ๔, ๕, ๖, ๗, ๘, ๙)” in number formatting.
  • “en-GB-u-ca-islamic”: use British English with the Islamic (Hijri) calendar, where the Gregorian date 14 October, 2017 is the Hijri date 24 Muharram, 1439.

Note: The subtags identifying languages, scripts, countries (regions), and variants in BCP 47 language tags can be found in the IANA Language Subtag Registry.

We can use navigator.language to get the browser language for the user, which we can use as ‘locale‘. The environment compares it against the locales it has available and picks the best one.

There are two matching algorithms:

  • lookup: checks from more specific to less: if zh-Hans-SG is not available, get zh-Hans, if not — zh, else — a default locale.
  • best fit(default): Improved algorithm. If “es-GT” — Spanish for Guatemala is requested, but not found, then instead of providing a fallback as “es”, the “es-MX” — Spanish in Mexico will be chosen.
‘Options’ option

We can modify the results as per user requirement by passing an object with information like style, currency, day, month, year, hour, timezone, minute, second, etc regarding the format. Lets see them through examples.


It is used for formatting the date and time depending on locale.

Example 1:

const date = new Date();
const locale = 'zh-Hans-CN-bauddha-u-nu-hanidec';
const formatter = new Intl.DateTimeFormat(locale);
const formattedDate = formatter.format(date);
console.log(formattedDate); // 二〇二〇/四/二一

Our locale contains all possible parts:

  • zh(language code) — Chinese language
  • Hans(script code) — written in simplified characters
  • CN(country-code) — as used in China.
  • bauddha(variant) — using a Buddhist Hybrid Sanskrit dialect
  • u-nu-hanidec(extension) — using Han decimal numbers

Example 2:

const presentDate = new Date();
new Intl.DateTimeFormat("hi-IN", {month: "long", day:"numeric", year:"numeric"}).format(presentDate); //"21 अप्रैल 2020"

Possible options for the ‘option’ object :

year: “numeric”,
month: “long”,
day: “numeric”,
hour: “numeric”,
minute: “numeric”
second: “numeric”,
weekday: “long”,
hour12: true,
timeZone: “America/Los_Angeles”


It is used for sorting the string. Lets say we have to sort some data which is in German or Swedish. We shouldn’t do it manually as the order depends on the language.


const sortarr = "ä","a","z";
const l10nDE = new Intl.Collator("de");
const l10nSV = new Intl.Collator("sv");
console.log(sortarr.sort(l10nDE.compare)); //"a", "ä", "z"
console.log(sortarr.sort(l10nSV.compare)); //"a", "z", "ä"



Constructor for objects that enable language-sensitive number and currency formatting.


new Intl.NumberFormat("hi-IN").format(12374784678); //12,37,47,84,678
new Intl.NumberFormat("hi-IN",{"style":"percent"}).format(.37); //"37%"
new Intl.NumberFormat("de",{"style":"percent"}).format(.37); //"37 %"
new Intl.NumberFormat("hi-IN",{"style":"currency","currency":"INR"}).format(153768); //"₹1,53,768.00"
new Intl.NumberFormat("hi-IN",{"style":"currency","currency":"INR", "useGrouping":false}).format(153768); //"₹153768.00"



Constructor for objects that enable plural-sensitive formatting and language-specific rules for plurals. Handling plurals is one of many problems that might seem simple, until we realize every language has its own pluralization rules.

Example 1:

const pluralrule = new Intl.PluralRules('en-US');
pluralrule.select(0);   // 'other' (e.g. '0 cats')
pluralrule.select(0.5); // 'other' (e.g. '0.5 cats')
pluralrule.select(1);   // 'one'   (e.g. '1 cat')

Example 2:

const pr = new Intl.PluralRules('en-US', {'type': 'ordinal'});
const suffixes = new Map([['one','st'],['two','nd'],['few','rd'],['other','th']]);
const formatOrdinals = (n) => {
    const rule = pr.select(n);
    const suffix = suffixes.get(rule);
    return `${n}${suffix}`;
formatOrdinals(0);   // '0th'
formatOrdinals(1);   // '1st'
formatOrdinals(2);   // '2nd'
formatOrdinals(3);   // '3rd'
formatOrdinals(4);   // '4th'
formatOrdinals(11);  // '11th'
formatOrdinals(21);  // '21st'
formatOrdinals(42);  // '42nd'
formatOrdinals(103); // '103rd'



Constructor for objects that enable language-sensitive relative time formatting.


const rtf = new Intl.RelativeTimeFormat('en');
rtf.format(-2,"day") //"2 days ago"
rtf.format(10,"hour") //"in 10 hours"
rtf.format(-1,"second") //"1 second ago"
const rtf2 = new Intl.RelativeTimeFormat('en',{"numeric": "auto"});
rtf2.format(0, 'week'); // "this week"
rtf2.format(-1, 'day'); //"yesterday



Constructor for objects that enable language-sensitive list formatting.


const listformat = new Intl.ListFormat('hi');
listformat.format(['Rahul']) //"Rahul"
listformat.format(['Rahul','Rohit']) //"Rahul और Rohit"

Options available for ListFormat:

standard (or no type) {} (default) A typical “and” list for arbitrary placeholders 'January, February, and March'
or {type: 'disjunction'} A typical “or” list for arbitrary placeholders 'January, February, or March'
unit {type: 'unit'} A list suitable for wide units '3 feet, 7 inches'
unit-short {type: 'unit', style: 'short'} A list suitable for short units '3 ft, 7 in'
unit-narrow {type: 'unit', style: 'narrow'} A list suitable for narrow units, where space on the screen is very limited '3′ 7″'


Need for Internationalization

Internationalization helps in product’s localization. Making changes to meet demands for linguistically- and culturally different audience after a product has been delivered is obviously much more difficult and time-consuming than designing a deliverable with the intent of presenting it globally. In ideal situations, Internationalization should be considered as fundamental step in the design and development process rather than as an afterthought which results into expensive re-engineering and unoptimized and non-scalable product. Today we might have to deliver a product for just one country in one locale, but in future when the business expands it might require us to make the same code available for different countries and in different locale. At that point the base code quality(internationalization capable or not) would define the course of action.


Internationalization API support


The use of native API is always preferred as it boost up the performance but there are jQuery libraries which provide full support for internationalization. Eg: Globalize.js, moment.js .  Also the polyfill available for the same can be found at https://github.com/andyearnshaw/Intl.js/

About The Author