Managing Translatable UI Text in JavaScript with RequireJS

Old world map

Internationalizing a web application includes the task of extracting user interface text for translations. When text is separated from the rest of your application business logic, you are able to localize and translate it easier. Although the JavaScript language and browser environment don’t prescribe any particular method for creating externalized text resources, many libraries exist to help this effort. One such library is RequireJS. The library includes an i18n plugin that helps you organize your text resources and load them at runtime depending on the needed language. The goal of this article is to describe how to use the RequireJS i18n plugin on a simple, single page application.

This sample application has a single html file index-before.html that contains text headers and other UI elements. We will extract the text, put it into a separate resource file, translate that file, and use the translatable files at runtime as needed by the customer’s language.

NOTE: This is not a RequireJS tutorial. The article assumes that you have some RequireJS knowledge.

Setting Up Your Environment

Download the js-localization project on Github. The project contains the source code for this article, allowing you to see code both before and after using the i18n plugin.

The project’s base directory is js-localization. Two HTML files are in this directory, index-before.html and index-after.html, which are the before- and after-internationalization files. The scripts subdirectory holds all JavaScript libraries for the project. All 3rd-party libraries, including RequireJS, are in scripts/libs. This application’s primary application file is scripts/main.js. Externalized text bundles are in scripts/nls.

Understanding the Original Index File

The original file looks like this:

    <meta charset="UTF-8">
    <title>Localization with RequireJS</title>
    <link href="styles/quotes.css" rel="stylesheet"/>
    <h1>Famous Quotation</h1>
    I love deadlines. I like the whooshing sound they make as they fly by.
    Douglas Adams

This file contains the following translatable items that we will extract for translation:

  • The title element contents
  • The h1 element contents
  • Two p element contents

Enabling Your HTML File

Include the RequireJS core library in your HTML file with a script element within the head section:

<script src="scripts/libs/require.js" data-main="scripts/main" charset="UTF-8"></script>

This script loads the require JavaScript file and also tells RequireJS to load your main module. The main module is the application’s starting point.

Creating I18n Text Modules

We need to pull out the text and put it into a separate text resource bundle. We will create text resource bundles in the scripts/nls subdirectory. RequireJS will look for resource bundles within the nls sudirectory unless you configure it otherwise. For our needs, we’ll create scripts/nls/text.js, put all exported text there, and provide a key for each string.

The updated HTML file maintains the same core document structure that is in the original file. However, we’ve removed the UI text. The HTML file, found in index-after.html now looks like this without text:

    <meta charset="UTF-8">
    <title id="titleTxt"></title>
    <link href="styles/quotes.css" rel="stylesheet"/>
    <script src="scripts/libs/require.js" data-main="scripts/main" charset="utf-8"></script>
    <h1 id="headerTxt"></h1>
    <p id="quoteTxt"></p>
    <p id="authorTxt"></p>

Where is the text? It’s in scripts/nls/text.js:

    "root": {
        "titleTxt": "Localization with RequireJS",
        "headerTxt": "Famous Quotations",
        "quoteTxt": "I love deadlines. I like the whooshing sound they make as they fly by.",
        "authorTxt": "Douglas Adams"

In general, each string in the original HTML file should be extracted into one or more nls resource bundles, which are really just JavaScript files. The sole purpose of a resource bundle is to define localizable resources. The files that define your primary set of language key-values are called root bundles. As part of a root bundle, a JavaScript file should define a root object that contains content for your application’s base language. This application’s root language is used when no target language can be found that matches the requested language.

Every piece of localizable text should have a key. The key is used to extract the original and translated text from the bundles. For example, headerTxt contains the label for “Famous Quotations”.

Adding Translated Text

Now that you’ve separated text into one or more resource bundles, you can send those files away for translation. For each target language, you will create a subdirectory in the nls directory. In this example, I used Google Translate to translate the text.js content into Japanese and Spanish. The nls subdirectories that contain translations must be named using standard BCP-47 language tags. The sub-directories for Japanese and Spanish are nls/js and nls/es respectively. Because there is only one source file, there will be only one file in each translation subdirectory.

Informing the Library

You must inform the RequireJS library about the available translations. In each source file that contains translations, you must add a language tag that matches the translation subdirectory name. We then have to update the nls/text.js file to notify the library for both Japanese and Spanish like this:

    "root": {
        "titleTxt": "Localization with RequireJS",
        "headerTxt": "Famous Quotations",
        "quoteTxt": "I love deadlines. I like the whooshing sound they make as they fly by.",
        "authorTxt": "Douglas Adams"
    "es": true,
    "ja": true

For each translation, you should include an additional language tag key in the root bundle. Since our root bundle nls/text.js has been translated into both Japanese and Spanish, we include those language tags and set their value to true, indicating that the translation exists.

Configuring RequireJS

RequireJS determines your customer’s language in one of two ways:

1. It uses your browser's language setting via the `navigator.language` or `navigator.languages` object.
2. It uses your customized, explicit configuration.

The navigator.language object is generally available across all browsers and represents the preferred language that is typically configurable in your browser’s language settings. This may be a reasonable default language, but I don’t recommend that a professional, consumer-facing application rely on this setting.

Instead, you should explicitly configure RequireJS to use a language that you select for the customer, with navigator.language as a backup perhaps. Your RequireJS configuration should be in the primary application JavaScript file. In our case, the scripts/main.js file contains this configuration as well as our application code.

If you set the i18n.locale configuration option for the i18n plugin, RequireJS will use that setting as your application’s language. By setting the value of this field, you control what language RequireJS will attempt to use. Set the language/locale option in the main.js file like this:

    config: {
        i18n: {
            locale: "en"

In an actual application, you will not hard-code this locale setting. Instead, you will determine your customer’s language another way, perhaps using navigator.language as a default.

Accessing the Resource Bundle

Once things are configured, using the resource bundle is easy. You just have to include it as a module in your main.js file. Then, you access each key using the name you give the module.

define(["jquery", "i18n!nls/text"],  function($, text) {

    // pull the text from the bundle and insert it into the document


In the above case, I’ve required two modules: jquery and “i18n!nls/text”. When you require a module using a plugin, you must append a “!” to the plugin name. After the plugin name, append the root resource bundle path. In this case, even though we have three languages, we point RequireJS to the root bundle. The i18n plugin will read the root bundle and discover the additional supported translations.

Since the code uses text as the module name, we can retrieve the text values by simply referencing the keys in the bundle. For example, if we want the quoteTxt, we reference it with text.quoteTxt in our code. The above code uses this technique to populate all the UI text in our simple HTML file.

Demonstrating the Plugin

We’ve setup the environment, configured the plugin, translated a file, and have modified our application so that it pulls translated text from the bundles. Now let’s see this work. You shouldn’t need any additional files or tools. Just point your browser to the index-after.html file on your local drive. If you’ve not changed anything, you should see the following English content:

Quote en

Now if you update the main.js file and change the i18n.locale setting to ja, you will see the next image. Remember, this is not a professional translation and is only used for an example.

Quote ja


Although JavaScript has no predefined framework for providing translatable resources, it is reasonably easy to use a library like the RequireJS i18n plugin to help manage UI text strings. Interestingly, the Dojo libraries work similarly to RequireJS. So, if you’re using Dojo, you will manage translations in your application in much the same way.

One of the most interesting parts of JavaScript internationalization is the question of how to determine the user’s preferred language. I’ve written about this before, so instead of handling that question here, I’ll refer you to Language Signals on the Web.

Good luck in your internationalization efforts. Like anything else, the hardest part is just getting started. Hopefully this article makes that first step easier.

Internationalization as a form of technical debt


The term technical debt is often used to label implementation choices that trade long-term goals for limited, short-term solutions. Technical debt has a negative connotation because it means that you have accrued a technical obligation that must be resolved before you can make future progress. Teams take on technical debt for many reasons: short schedules, insufficient knowledge, poor team collaboration, and a host of others. Generally, you want to avoid technical debt because it represents a technical hurdle that you have avoided or have resolved only partly. Technical debt limits the rate at which can innovate and progress in the future.

I’ve often thought about how many product and software teams approach software internationalization. The typical team will begin development with a single geographical market. The team knows that they want to succeed internationally, but they don’t worry about that concern at first. They have schedules, product features, and short-term needs that demand attention. They sacrifice long-term goals for short-term wins. They ignore best practices in software internationalization because of insufficient knowledge or perhaps even laziness. Over time, internationalization work becomes technical debt that must be paid to make further progress into desired markets. 

The disheartening fact is that unattended technical debt in internationalization will eventually require code refactoring, new implementations, and even updated designs. Interest increases rapidly. At some point, you may not be able to do everything yourself, and you might need external help.

Fortunately, internationalization does not have to become technical debt. Basic internationalization usually does not have huge upfront costs for either schedules or resources. Internationalization can be integrated into every sprint or delivery schedule. The very basic concepts are simple, and a little up-front and regular consideration will pay huge dividends.

So, what can you do now to avoid technical debt in internationalization? I suggest you tackle this in a few steps:

  1. Make everyone responsible for knowing the basic issues and concerns in internationalization.
  2. Resolve to implement best practices for each of the concerns that will affect your product.
  3. Make internationalization a part of your ongoing development and review process.

In an upcoming blog, I’ll provide you with some resources for each of these steps. 

All the best,
John O’Conner

The New Date and Time API in Java 8

It’s no secret that developers have been unsatisfied with the existing Date and Calendar classes of previous Java versions. I’ve heard complaints that the Calendar API is difficult to understand, lacks needed features, and even causes unexpected concurrency bugs. As a result, developers sometimes migrated to the popular Joda Time library, which apparently satisfied their needs.

I’ve always suspected that the standard Date and Calendar API would be updated (or replaced), but I can’t help being a little surprised to see the new java.time package in Java 8. I’m not so surprised that it exists but that it is so comprehensive…and that it seems so familiar. If you’re one of those who moved to Joda Time, you’ll feel a sense of déjà vu. The new Java 8 library looks a lot like Joda Time. After a little snooping, now I understand why. The new Date and Time API was created by Stephen Colebourne, the author of Joda Time. Of course, he worked with Oracle and others within the umbrella of the JSR 310 proposal, but this is Joda Time in many ways.

As I take a first browse of the new API, I noted a couple simple thoughts: the API is feature-rich and complete, and it’s still complex.

Time, dates, and date manipulations are not simple, and no API is going to make that change . However, I think that this new API does a great job of making things less complicated than before. If you haven’t looked at it yet, please check it out. Let me know what you think. I’ll do the same and share how to use the APIs in upcoming blogs.


iOS vs Android

Yesterday someone told me that Google’s Android devices have shipped more units than iOS devices in Q3 and Q4 of 2012 — I will check and recheck my source on this. That’s a big claim, but seems plausible considering that Android ships on a lot more than your basic tablets. Android is in a lot of things, including smart televisions and many manufacturer’s smart phones.

It leaves me wondering…has Android finally got the momentum to dominate the small device market, smart phones, etc. More importantly to me, does it have developer interest?

I’m convinced that a successful computing platform for tablets and phones must serve two consumers. First, those customer-consumers that buy the devices and use them day to day must be happy with the usability and overall fitness of the OS. Second, the developer-consumer must be convinced that the platform is easy to develop for. The OS and platform tool chain must be robust and complete. Otherwise, developer interest fades quickly. Without developers, you simply don’t have those random, goofy, hacked apps that seed a market. Without those apps, customer-consumers don’t have any motivation to discover a newer platform.

I’ve finally made my own choice though…my choice about which platform I’m going to develop for. There’s no doubt that I’m fascinated by Android. So fascinated, in fact, that I suspect that many future posts will be devoted to Android. However, I’m going to use a couple tool sets. Of course, I’m going to write native applications in Java, but I’m also going to try something relatively new for me. I’m going to look at… PhoneGap. I only know the idea behind PhoneGap, and I haven’t tried to develop with it yet. However, that’s going to change too.

You know what’s the best thing about PhoneGap? Ready? It’s that you write your application once using PhoneGap APIs, and that application should now run on multiple platforms. I’ve always been fascinated and pulled into this promised of write once and deploy to many devices. Well, PhoneGap promises that. Interestingly, it’s taking on the same job that Java did a long time ago. Oddly, though, I recall that Java never quite made it onto the desktop. And instead of being the common language of all these devices, the common language seems to be descriptive HTML, CSS, and JavaScipt. Of course, my curiously can’t be satisfied easily. I’m going to give both a try: a native Android application and a PhoneGap one. Which will be easier to use? 

I suspect that the native application will be the snappiest, most desired application. However, I want to be pleasantly surprised by Phone Gap. In fact, I’d like to be so delighted with Phone Gap that I give up my other toolsets. In addition to having a single src code that works for both iOS and Java, I’d love to have that single tool chain that can help me develop apps across platforms too!

Still Can’t Use Apostrophes? Really?

Answer this for me. Why in the world are we still preventing very common characters from name fields in online forms, in bank account applications, in insurance forms…tax returns? Why? 

In 2012, many companies have adopted Unicode in their backend databases. But what’s wrong with their development teams that prevent them from allowing customers to spell their names correctly in their application’s user interface? I live in California. We have LOTS of hyphenated names, names with accents, names with apostrophes. There really is no excuse for preventing users from spelling their names online in the the same way that they spell them on paper.

At this point I’m just irritated. At one point I thought I could just tell people how to fix these things. Then I thought I could occasionally blog about it — thinking the word would get out slowly. Well, I suppose if it is working at all, the message is getting out slower than anticipated. I never had delusions that an i18n blog would be generally popular with the masses. This isn’t a soap opera or Hollywood expositor after all. However, you might thing that common sense would just spread, that it would simply be absorbed across the web. It ‘aint so.

Look, if you are a software developer and have ANY influence on how your company provides its input or signup forms online, can you do me a favor? Can you remember that some people have names that actually have an apostrophe or hyphen or n-with-an-accent-grave? You can easily parse these fields; you can check against sql attacks etc that use interesting characters to turn databases into mush. We have the technology people. Let’s consider what might happen if we use it.

All the best,

John O’Conner (note the apostrophe)

In Memory of Bill Hall

I met Bill Hall sometime in 1993 or 1994 when we both worked at Novell. He was already a well-known software engineer, consultant, and internationalization guru. As a recently minted college graduate, I adopted Bill as my mentor. Like many mentors, Bill probably never knew this. And yet, he mentored me for more than 16 years in this globalization industry. He is the one, the only one, that I thought knew all there is to know.

Bill Hall could laugh until tears came to his eyes, and he could look at you and freeze a moment with you as if you were the only person in the world that mattered. Later in his life, his eyes would water for no good reason, except that maybe he was just getting older, and allergies or maybe just life itself had squeezed most of Bill out.

When Bill wasn’t talking about internationalization or piloting, he always spoke of his wife and children. I met his wife Ewa and one of his children, Kasia. They and my own wife toured around Tokyo one year long ago while Bill and I spoke at a conference or just happened to be in Tokyo together. I suppose the event doesn’t really matter; it was a long time ago. Kasia must be a junior or senior in college now….wow, time flies.

Just today, I received an email from Kasia, a personal email telling me that her father had died. I’ve since discovered that many others in the internationalization and globalization industry have received a similar but different email or notification from Kasia. At least a dozen other people that I know received those personal emails that said something that only Bill and you would know, something that Bill shared with you, and I got one of those from Kasia. After the initial shock of learning of his death, I couldn’t help but smile. Kasia had sent out an email to me, just to me, and it was personal, and I realized that his dear daughter had inherited Bill’s way of reaching out to people one on one, making them feel as if you were the only person in the world that mattered.

Thanks, Bill for your friendship, for your knowledge, and for what you’ve given our industry. We already miss you.



Internationalization & Unicode Conference 36 Call for Papers

The IUC 36 call for papers went out last week —

This conference event brings together the best minds, ideas, and practices in the worlds of internationalization and localization,  There’s content sessions to please everyone including technical engineers, project managers, and product managers.

The Program Committee is requesting proposals for presentations. Check out the website for details, but some of the general areas are the following:

  • Application Areas
    • Social Nets
    • SEO
    • Websites and web services
    • Libraries and educatoin
    • IDN
    • Mobile and Tablets
    • Security
    • Machine Translation
  • General Techniques
    • i18n libraries
    • bidirectionality and scripts
    • html5
    • Data formats: json, xml,
    • project mgmt
    • font dev
  • Culture and Tech
    • Endangered languages
    • Unencoded languages
    • Case studies
    • ISO language tag issues
  • Regional Considerations
    • Africa, Asia, Middle East
    • Locales and CLDR
    • Emoji Support … sigh…

If you think you might want to present something new and exciting that you have been working on, consider presenting at the conference. Read the above link to find out more.

One last thing. Check out that Gold Sponsor!







Seeking input on article topics

Hi there again,

This is just a quick note to say thank you for reading this blog. Internationalization is definitely a favorite topic of mine. The problem is that I enjoy so many topics that sometimes I don’t stay focused.

To help with that, I’m asking you to make suggestions. What would you like to read about here? What globalization topics interest you the most? What topics do you have trouble finding information about on the web or in your favorite magazine. I’m here to help you of course, but I get a lot out of researching material too!

Have a great weekend!

Countries with Multiple Time Zones

Recently I came across a W3C document about times, dates, and time zones. The document claims that only 20 countries observe more than one time zone. The United States is in that list. Can you name the rest of them?

I’ll post the answers to this question tomorrow! Until then, which countries do you think have more than one time zone?

P.S. Please provide your answers as comments!

Take care in speaking and writing your customer’s name

No matter how many times it happens, I still feel somewhat surprised that companies still don’t know how to gather form data, move it through their database and use it without destroying something as simple as a name. My most recent surprise came just today, this time from Ford Motor Company.

Apparently I had filled out an online form and included my name. Unfortunately, Ford didn’t quite know what to do with the apostrophe in my family name. They turned it into a form similar to an html character entity reference but they seem to have scrubbed out the semi-colon from the “&apos;” reference. Here’s the US postal address they used to reach me recently.


Aah, when will they learn?