10ma19

The Ultimate Guide to JavaScript Localization

Javascript localization guide cover image

Kick-start your browser JavaScript localization with this comprehensive guide and use different i18n JavaScript code examples to make your application ready for international users.

  1. Phrase Blog
  2. Developers
  3. The Ultimate Guide to JavaScript Localization

Weird, maturing, arguably expressive, and amazing, JavaScript is the most used programming language today. Being the language of the browser—and putting in work on the server with Node—JavaScript is all over today’s web stacks.

And with many multiplatform mobile frameworks, desktop wrappers, game engines, and even internet-of-things (IoT) frameworks, it’s really JavaScript’s world—we just live in it.

Now, of course, you’re here because you want to take all that 🔥 and learn to localize JavaScript applications, enabling them for a global audience. Have no fear: This guide will cover everything you need to know to start browser JavaScript localization.

Let’s rock && roll.

🔗 Resource » Get all the code accompanying this article from our GitHub repo.

✋🏽 Heads up » This article receives major updates periodically. If you have any questions or comments, let us know in the Comments section below.

🗒 Note » Internet Explorer (IE), with a 2.15% global market share, can be considered a legacy browser. For brevity, we’re omitting IE-specific solutions in this guide. If you are supporting IE, be sure to check whether the built-in JavaScript features we’re covering in this article require forks or polyfills.

Contents

How do I localize a web page with JavaScript?

While it might be tempting to grab an off-the-shelf internationalization (i18n) library for your localization needs—and that might in fact be the right choice for your project—you’ll find that vanilla JavaScript can do you just fine for smaller projects. Rolling your own will also give you a nice cookbook of i18n techniques that you can use with any library you choose.

🤿 Go deeper »Our article, What Is I18n: A Simple Definition of Internationalization, goes into more detail regarding what internationalization (i18n) and localization (l10n) are.

✋🏽 Heads up » If you’re building a traditional MPA (multi-page application), it’s often the case that a lot of the localization happens on the server itself. We’re only working with browser localization here. We’ve got you covered server-side, though, with a Node i18n tutorial and a full-stack JavaScript i18n guide.

Alright, let’s say we have a page we want to localize.index.html<!DOCTYPE html><html lang=”en”><head> <meta charset=”UTF-8″> <!– … –> <title>My Appy Apperson</title></head><body> <div class=”container”> <h1>My Appy Apperson</h1> <p>Welcome to my little spot on the interwebs!</p> </div> <script src=”js/scripts.js”></script></body></html>

English version of a JavaScript demo app | Phrase

🔗 Resource » You can get all the code for the app we’re building in this section from the vanilla folder in our GitHub repo.

🔗 Resource » I’m using the skeletal Skeleton CSS library in case you were wondering.

This looks OK, but it isn’t exactly global-ready, is it? All the content is hard-coded in English. Let’s do some basic i18n here.index.html<!DOCTYPE html><html lang=”en”><head> <meta charset=”UTF-8″> <!– … –> <title>My Appy Apperson</title></head><body> <div class=”container”> <h1 data-i18n-key=”app-title”>My Appy Apperson</h1> <p data-i18n-key=”lead”>Welcome to my little spot on the interwebs!</p> </div> <script src=”js/scripts.js”></script></body></html>

Note the data-i18n-key attributes we added to our text containers above. We can tap into these when the document loads and replace their text with translations. In fact, let’s do just that./js/scripts.js// The active localeconst locale = “en”;// We can have as many locales here as we want, // and use any locales we want. We have English// and Arabic as locales here as examples.const translations = { // English translations “en”: { “app-title”: “My Appy Apperson”, “lead”: “Welcome to my little spot on the interwebs!”, }, // Arabic translations “ar”: { “app-title”: “تطبيقي المطبق”, “lead”: “أهلاً بك في مكاني الصغير على النت.”, },};// When the page content is ready…document.addEventListener(“DOMContentLoaded”, () => { document // Find all elements that have the key attribute .querySelectorAll(“[data-i18n-key]”) .forEach(translateElement);});// Replace the inner text of the given HTML element// with the translation in the active locale,// corresponding to the element’s data-i18n-keyfunction translateElement(element) { const key = element.getAttribute(“data-i18n-key”); const translation = translations[locale][key]; element.innerText = translation;}

With this in place, let’s change the second line above to const locale = "ar"; and reload the page. When the DOMContentLoaded event is triggered, our page takes on our Arabic translations.

Arabic version of a JavaScript demo app | Phrase

🗒 Note » "en" and "ar" above are the ISO 639-1 codes for English and Arabic, respectively. It’s standard to use ISO codes for languages and countries when localizing.

Loading translations asynchronously

We’re off to a good start with our i18n solution. However, adding locales and translations doesn’t scale well at the moment. As our app grows, we’d probably want to split our translations into separate, per-locale files. The translation file corresponding to the active locale could then be loaded without the cost of loading the other locales. We can implement this without too much effort.

First, let’s move our translations out of our main script and into JSON files, one for each locale we support./lang/en.json{ “app-title”: “My Appy Apperson”, “lead”: “Welcome to my little spot on the interwebs!”}/lang/ar.json{ “app-title”: “تطبيقي المطبق”, “lead”: “أهلاً بك في مكاني الصغير على النت.”}

Now let’s rework our script so that we load the JSON files asynchronously when needed./js/scripts.js// The locale our app first showsconst defaultLocale = “en”;// The active localelet locale;// Gets filled with active locale translationslet translations = {};// When the page content is ready…document.addEventListener(“DOMContentLoaded”, () => { // Translate the page to the default locale setLocale(defaultLocale);});// Load translations for the given locale and translate// the page to this localeasync function setLocale(newLocale) { if (newLocale === locale) return; const newTranslations = await fetchTranslationsFor(newLocale); locale = newLocale; translations = newTranslations; translatePage();}// Retrieve translations JSON object for the given// locale over the networkasync function fetchTranslationsFor(newLocale) { const response = await fetch(`/lang/${newLocale}.json`); return await response.json();}// Replace the inner text of each element that has a// data-i18n-key attribute with the translation corresponding// to its data-i18n-keyfunction translatePage() { document .querySelectorAll(“[data-i18n-key]”) .forEach(translateElement);}// Replace the inner text of the given HTML element// with the translation in the active locale,// corresponding to the element’s data-i18n-keyfunction translateElement(element) { const key = element.getAttribute(“data-i18n-key”); const translation = translations[key]; element.innerText = translation;}

If we reload our page now, it looks exactly as it did before. However, under the hood, we’ve made our app a lot more scalable and maintainable.

🗒 Note » We use the handy Fetch API built into modern browsers to grab our JSON files via the network.

Creating a locale switcher

Our users have no way to make use of our awesomely asynchronous abilities as of yet. Shall we build a language-switching dropdown for them?

We’ll add a navbar and house our switcher in said navbar.index.html<!DOCTYPE html><html lang=”en”><head> <!– … –> <title>My Appy Apperson</title></head><body> <div class=”container”> <nav class=”navbar”> <div class=”container”> <ul class=”navbar-list navbar-left”> <!– Nav links –> </ul> <div class=”navbar-right”> <!– … –> <select data-i18n-switcher class=”locale-switcher”> <option value=”en”>English</option> <option value=”ar”>Arabic (العربية)</option> </select> </div> </div> </nav> <h1 data-i18n-key=”app-title”>My Appy Apperson</h1> <p data-i18n-key=”lead”>Welcome to my little spot on the interwebs!</p> </div> <script src=”js/scripts.js”></script></body></html>

A simple <select> can do us here. We can use a data-i18n-switcher attribute to hook into from our JavaScript and load the user-selected locale./js/scripts.jsconst defaultLocale = “en”;let locale;// …// When the page content is ready…document.addEventListener(“DOMContentLoaded”, () => { setLocale(defaultLocale); bindLocaleSwitcher(defaultLocale);});// …

Please wait while you are redirected...or Click Here if you do not want to wait.