Skip to main content

Internationalizing Web applications using Dojo

Allow users to use your application in their own language

Yoav Rubin (yoav@il.ibm.com), Software engineer, IBM
Yoav Rubin holds a B.Sc. in Information Systems Engineering from the Computer Science faculty in the Technion, Israel Institute of Technology, and for the last eight years, he has been working as a Software engineer in IBM Haifa Research Lab, mostly in the fields of visual application development tools and complex event processing. His main interests are Java and Web 2.0 technologies, end user development and usability.
Gal Shachor, Senior Technical Staff Member, IBM
Gal Shachor is an IBM Senior Technical Staff Member and researcher working at the IBM Haifa Research Lab, on various topics related to middleware and rich Internet applications.

Summary:  The mother tongue of most of the people in the world is not English. It might be a widely used language like Chinese or French, or a rarely used language like the Bask language or Yiddish. These people, regardless of their English skills, may be potential clients; the only problem is how to reach them. It is one thing to reach a potential client's screen, and quite another to convey the message from their screen to their minds. Following various internationalization (i18n) guidelines helps to address this problem, especially in properly presenting your application Web site to the user in his or her native language. This can result in exposure to huge markets where the only barrier is language and cultural differences. In this article, discover a way to perform native language support in the context of Web sites and Web applications using the i18n feature of the Dojo toolkit.

Date:  05 Aug 2008
Level:  Intermediate PDF:  A4 and Letter (49KB | 11 pages)Get Adobe® Reader®
Activity:  3201 views

Introduction

Internationalism, as defined by Wikipedia, is the process of designing a software application so that it can be adapted to various languages and regions without engineering changes (see Resources). Using this definition, in order to have internationalized software, the presence of three elements is essential:

  • An element that is responsible to tell the software the locale in which the software is running
  • A set of translation files that can be applied to the software's current locale
  • A component that is responsible to connect the previous two elements

In this article, we will create a simple internationalized Web application and demonstrate the Dojo toolkit standards for the first two elements (see Resources for more on Dojo). Then we will examine two Dojo usage scenarios for the third element: an html file or a widget.

Setting the locale in a Dojo-based application

The locale is a parameter defining the language that should be used in the application's user interface. There may be situations where specifying the language may not be enough. Different countries may use the same language with subtle changes, ranging from spelling changes (for example, "center" in the United States as opposed to "centre" in the United Kingdom) to different words for the same meaning ("Elevator" in the U.S. as opposed to "Lift" in the UK). Therefore, the locale parameter may contain a country code in addition to the language code, to specify the specific language flavor that should be used.

Dojo provides two mechanisms of specifying the locale of the Web application. The first is programmatically (either in run time or design time), and the other is to rely on the default locale of the browser (which is defined during the browser’s installation).

Setting the locale programmatically is done by specifying the value of the "locale" attribute in the global object djConfig. The example in Listing 1 shows how to set the locale to en-us locale in design time:


Listing 1: Setting the locale programmatically in design time
          
          <script type="text/javascript" SRC="dojo.js" djConfig="locale:'en-us'"></script>

Another possibility is programmatically calculating the locale (for example, by extracting it from the URL) and then setting locale. The example in Listing 2 shows how to set the locale programmatically in run time:


Listing 2: Setting the locale programmatically in run time
          
<script type="text/javascript"> 
// Note: this must be done before dojo loads!!!
var djConfig = new Object(); 
var theLocale = getLocale(); // this function is responsible to determine
                            // the appropriate locale
djConfig.locale = theLocale; 

function getLocale()
{
	return “en-us”;
}
</script> 

The last possibility is to not specify the locale, which results in using the default locale of the browser, which Dojo extracts from the navigator object. The default behavior, like any usage of default for that matter, is useful in cases where you can predict how your client’s browser and machine are configured. This is rarely the case, and installing the browser in a language which is not the user’s mother tongue, or a locale with which your application is not familiar, is not uncommon (so do try to avoid using this approach).

The translation files in Dojo applications

Now that you understand how to state the application’s locale, it is time to learn to provide the set of the translation files, called "resource bundle(s)," to Dojo applications.

A resource bundle is a group of files, all named the same, in which each file is applicable for a specific locale. Each file should be in the JSON format. For our greeting application, the resource bundle files are all named greeting.js. Their contents are shown in Listing 3.


Listing 3: Resource bundles for different English locales

Content for the American English locale:


{
	PAGE_TITLE:"God bless America",
	GREETING: “What’s up”,
	PERSON: “dude”,
	GREETING_SENTENCE: “${greeting} ${personTitle}”
}
 
                      
      
Content for the British English locale: { PAGE_TITLE:"God save the queen", GREETING:”Hello”, PERSON:”dear”, GREETING_SENTENCE: “${greeting} ${personTitle}” }
Content for the Australian English locale: { PAGE_TITLE:"God bless the ozis", GREETING:”G’day”, PERSON:”mate”, GREETING_SENTENCE: “${greeting} ${personTitle}” }
Content for the French locale: { PAGE_TITLE:"Vive la France", GREETING:”Bonjour”, PERSON:”monsieur”, GREETING_SENTENCE: “${greeting} ${personTitle}” }

You now need to place these files in the proper location, so that Dojo can read them. In order to do so, you need to construct a hierarchy of folders, in the way that Dojo expects. Assume that the application defines a module path called "sampleApp" in the location "../../sample/application" relative to Dojo. So the directory structure you need to create is like the one seen in Figure 1.


Figure 1. Directory structure
Directory structure

Basically, a folder named “nls” should be under the defined module. It contains the locale folders, which are lower cased, and a hyphen separates the language code from the optional country code.

Note that in the translation files we have separated the greeting into two parts, since different languages may have different sentence structures and may build the greeting differently. Hence, we need a way to construct the greeting from its components in an internationalized way. For this we use Dojo’s utility dojo.string.substitute, which receives a template for a string, with parameterized values, and substitutes the placeholders in the templates with the given values. The template itself is the entry GREETING_SENTENCE in the resource bundle.

Connecting the pieces within an HTML file

In order to connect all the previously defined pieces, we create the html file that contains our application, shown in Listing 4.


Listing 4: The application's HTML file
          
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
  <head>
    <title id="titleId"></title>
    <script type="text/javascript">
      var djConfig = { modulePaths: {sampleApp: "../../sample/application"},
                       parseOnLoad: true,
                       locale:'en-us'};
    </script>
    <script type="text/javascript" src="dojoBase/dojo/dojo.js"></script>
    <script type="text/javascript">
      dojo.require("dojo.string");
      dojo.requireLocalization("sampleApp", "greeting");
      function init()
      {
        var nlsStrings = dojo.i18n.getLocalization("sampleApp","greeting");
        var greetingString = nlsStrings.GREETING; var personString = nlsStrings.PERSON;
        var greetingTemplate = nlsStrings.GREETING_SENTENCE;
        var finalGreeting = dojo.string.substitute(greetingTemplate,
                                                   {greeting:greetingString,
                                                    personTitle:personString});
        dojo.byId("helloDiv").innerHTML = finalGreeting;
        dojo.byId("titleId").text = finalGreeting;
      }
      dojo.addOnLoad(init);
    </script>
  </head>
  <body>
    <div id="helloDiv"></div>
</body>
</html>
        

The most important thing to notice in this application is the usage of two Dojo commands that extract the localized information. The first one is: dojo.requireLocalization("sampleApp", "greeting"). This call is responsible for requesting from the server the resource bundle called "greeting" that is found under the defined module "sampleApp." The second one is: var nlsStrings = dojo.i18n.getLocalization("sampleApp","greeting"). This call is responsible for transforming the received "greeting" resource bundle (which was found under the "sampleApp" module) into a JavaScript object, which is returned. Once you have this object (the nlsStrings object), you can refer to any of its fields in order to set the appropriate dom element with the needed strings.

Connecting the pieces and displaying the content using custom-created widgets

Usually, when the application gets a little bigger than a sample application, custom-created widgets are introduced. In this section, we recreate the sample application, now using custom-created widgets. You'll see how properly to separate all the mechanisms of internationalism from the content displaying widgets.

First of all, create the widget that is responsible for handling all the internationalism issues, starting with the "mixin," shown in Listing 5, which is responsible for all the native language support (NLS) operations.


Listing 5: The NLS mixin
           

dojo.require("dojo.i18n");
dojo.require("dojo.string");
dojo.requireLocalization("sampleApp", "greeting");
dojo.provide("sampleApp.widget.NlsMixin");

dojo.declare("sampleApp.widget.NlsMixin",null,
  {
    data: {__initialized: false},

    constructor: function()
    {
      if(!this.data.__initialized)
      {
        this.data.nlsStrings = dojo.i18n.getLocalization("sampleApp",                   
                                                         "greeting");
        this.data.__initialized = true;
      }
    },

    /**
    *
    * @param {String} key - the name of the key in the translation file
    * @param {Object or Array?} substitutes - in cases where the translated  
    *   string is a template for string substitution, this parameter
    *   holds the values to be used by dojo.string.substitute on that  
    *   template
    */
    getString: function(/*String*/ key,
                        /*Object or Array?*/ substitutes)
    {
      var str = this.data.nlsStrings[key];
      return (substituteValues)?  
                               dojo.string.substitute(str,substitutes):
                               str;
    },

    postMixInProperties: function()
    {
      this.inherited('postMixInProperties', arguments);
      this.initializeStrings();
    },

    initializeStrings: function(){}
  }
);

There are three things to note in this mixin:

  • In order to reduce memory usage, the resource bundle object is static and singleton.
  • Widgets that use this mixin need to override the function 'initializeStrings', and populate it with calls to the getString function. This method is invoked during the call to postMixinProperties in order to make all the internationalized strings available to use while rendering this widget (in other words, using these strings within the widget's template).
  • The getString function receives two parameters. One is the key within the resource bundle. If the returned string needs further handling by dojo.string.substitute, then the second parameter is used to supply the substitution object or array (depending on the way that the template was defined in the resource bundle).

Now we'll show you how to create the simple greeting widget, which would be placed within your page to greet your application's users. See Listing 6.


Listing 6: The greeting widget's code
          

dojo.provide("sampleApp.widget.Greeting");

dojo.require("dijit._Widget");
dojo.require("dijit._Templated");
dojo.require("sampleApp.widget.NlsMixin");

dojo.declare("sampleApp.widget.Greeting",
    		[dijit._Widget,dijit._Templated ,sampleApp.widget.NlsMixin],
  {        
    templateString: "<div>${greeting}</div>",
    greeting:””,
    initializeStrings: function()
    {
      var greetingString = this.getString("GREETING");
      var personString = this.getString("PERSON");      
      this.greeting =   this.getString("GREETING_SENTENCE",    
                                            {greeting:greetingString, 
                                             personTitle:personString});
  }
}
);

As you can see, the template refers to a variable that gets a "real" value during the call to initalizeStrings, which uses the getString method in order to get the proper internationalized content.

Now, all that needs to be done is use this widget in an HTML file to view the internationalized content, seen in Listing 7.


Listing 7: The greeting page for the en-au locale
        
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
    <script type="text/javascript">
      var djConfig = { isDebug: false, 
                       modulePaths:
                       { sampleApp: "../../sample/application" },
                       parseOnLoad: true, 
                       locale:'en-au'
                     };
    </script>
    <script type="text/javascript" src="dojoBase/dojo/dojo.js.uncompressed.js"></script>
    <script type="text/javascript">
      dojo.require("sampleApp.widget.Greeting");
    </script>
  </head>
  <body>
    <div dojoType="sampleApp.widget.Greeting" id="helloDiv"></div>
  </body>
</html>

Quick testing

Translating the application to languages that are not the language used by developers during development adds the necessity for three types of tests to be done on the software.

  • The first one is to test the quality of the translation, which is something that is usually very difficult to do, since it requires another person besides the translator that is fluent in the translated language. This kind of testing is beyond the scope of this article.
  • The second type is to test the way that the application's user interface displays each of the languages. Sentences or words may turn out to be much longer or shorter in other languages, and this change may cause the UI to look different. (There are also other aspects of i18n, which are not discussed here, such as the need to sometimes use a different set of colors and icons in different locales due to cultural differences.) This testing is done by the development team, and may result in using different style sheets for different locales. This kind of testing is also beyond the scope of this article.
  • The third type is a coverage test. It basically means that the developer needs to verify that each and every string that is presented to the end user by the application is not hard coded, but comes from the proper resource bundle. We'll present one way of doing this test. There may be others, but this one is simple, efficient, and there is no need to do something more complicated here.

Testing for hard-coded elements

Below is a step-by-step guide to performing a coverage test on the internationalized content:

  1. Create a dummy locale, called "en-num" (add a folder as a sibling of the other locale folders).
  2. Copy the resource bundle you want to test to this folder .
  3. Either by hand or automatically using some small program or a script written in your favorite programming language, change all the strings in this file (not including substitution markers for dojo.string.substitute) to numbers.
  4. Set the application's locale to be "en-num" and go over all the screens of your application. If you see a string that is not composed of numbers, then most likely this string did not originate from the resource bundle.

Summary

In conclusion, you have seen how to perform internationalism in Web applications using the Dojo toolkit. This article presented a way to design, implement, and test the translation aspect of i18n. There are other aspects, more related to localization, such as formatting some of the displayed elements according to the locale (different countries use different methods to present numbers, currencies, time, and date). Other aspects of i18n that are not addressed here are things that are derived from cultural differences. Icons that mean one thing in one country may mean the opposite in another country. For example, using an owl icon to signify a wise thing in the UI won't work in some Asian countries, as an owl sometimes symbolizes stupidity.

Still, the translation aspect of i18n is the most resource demanding, requiring much work from the software developers. Using information presented in this article may save you some time and money. If so, then our work here was worth doing.


Resources

Learn

  • See Wikipedia's page on Internationalization.

  • The Dojo toolkit is a JavaScript toolkit that has many components to support Ajax application development.

  • IBM globalization has many resources that handle various aspects regarding globalization concerns.

  • Blogamundo is an excellent blog that discusses various internationalization aspects.

  • Global by design is a blog that discusses various Web globalization aspects.

  • The Dojo campus holds many good tips and cookies regarding using Dojo.

  • Expand your Web development skills with articles and tutorials that specialize in Web technologies in the developerWorks Web development zone.

  • Browse the technology bookstore for books on these and other technical topics.

Discuss

About the authors

Yoav Rubin holds a B.Sc. in Information Systems Engineering from the Computer Science faculty in the Technion, Israel Institute of Technology, and for the last eight years, he has been working as a Software engineer in IBM Haifa Research Lab, mostly in the fields of visual application development tools and complex event processing. His main interests are Java and Web 2.0 technologies, end user development and usability.

Gal Shachor is an IBM Senior Technical Staff Member and researcher working at the IBM Haifa Research Lab, on various topics related to middleware and rich Internet applications.

Comments (Undergoing maintenance)



Trademarks  |  My developerWorks terms and conditions

Help: Update or add to My dW interests

What's this?

This little timesaver lets you update your My developerWorks profile with just one click! The general subject of this content (AIX and UNIX, Information Management, Lotus, Rational, Tivoli, WebSphere, Java, Linux, Open source, SOA and Web services, Web development, or XML) will be added to the interests section of your profile, if it's not there already. You only need to be logged in to My developerWorks.

And what's the point of adding your interests to your profile? That's how you find other users with the same interests as yours, and see what they're reading and contributing to the community. Your interests also help us recommend relevant developerWorks content to you.

View your My developerWorks profile

Return from help

Help: Remove from My dW interests

What's this?

Removing this interest does not alter your profile, but rather removes this piece of content from a list of all content for which you've indicated interest. In a future enhancement to My developerWorks, you'll be able to see a record of that content.

View your My developerWorks profile

Return from help

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Web development
ArticleID=327865
ArticleTitle=Internationalizing Web applications using Dojo
publish-date=08052008
author1-email=yoav@il.ibm.com
author1-email-cc=
author2-email=shachor@il.ibm.com
author2-email-cc=

My developerWorks community

Tags

Help
Use the search field to find all types of content in My developerWorks with that tag.

Use the slider bar to see more or fewer tags.

Popular tags shows the top tags for this particular content zone (for example, Java technology, Linux, WebSphere).

My tags shows your tags for this particular content zone (for example, Java technology, Linux, WebSphere).

Use the search field to find all types of content in My developerWorks with that tag. Popular tags shows the top tags for this particular content zone (for example, Java technology, Linux, WebSphere). My tags shows your tags for this particular content zone (for example, Java technology, Linux, WebSphere).

Rate a product. Write a review.

Special offers