Translatable Resource bundles

Authors:Adam Peller
since:1.0

Introduction

The dojo/i18n loader plugin solves a problem in JavaScript: with a significant amount of logic now on the client, there are internationalization issues which cannot easily be solved by server-driven templates. Furthermore, a server-based solution for dynamic content is difficult to manage and couples the client-side toolkit to a particular server architecture, making it difficult to share JavaScript components or widgets. With a client-side internationalization framework, the integration point moves to the browser where simple or complex logic can be applied without becoming a bottleneck. This architecture also encourages encapsulation and efficient caching both at edge servers and in the browser. And, while all translations are present on the server, rest assured that only those which match the user’s locale are requested by the client and sent over the wire.

To internationalize a web application with Dojo, a combination of client and server techniques are typically employed. The methods used in Dojo to substitute localized resources are intended for dynamic content generated by JavaScript. It is usually best to continue using a server-side mechanism to localize static page content, rather than trying to generate all page content through Dojo and JavaScript.

Dojo and Dijit provide resource bundles for all strings which are made visible to the user on the page, with translations provided in many languages. Those augmenting Dojo or writing their own widgets may to create and translate their own set of resources, as needed. Error information, such as that sent to a browser console, are not translated.

Localizing Strings

With the introduction of AMD-style loading in Dojo 1.7, localized content is loaded much like JavaScript modules, using the dojo/i18n! plugin as follows:

<html>
<head>
    <script
        src="dojo/dojo.js"
        data-dojo-config="'packages':[{'name': 'myApp', 'location':'myApp'}]
    ></script>
    <script language="JavaScript" type="text/javascript">
        require([
            "dojo/ready",
            "dojo/dom",
            "dojo/i18n!myApp/nls/myResources"
        ], function(ready, dom, sampleStrings){
            ready(function() {
                dom.byId("myDiv").textContent = sampleStrings.greeting;
            })
        });
    </script>
</head>
<body>
    <div id="myDiv">
    </div>
</body>
</html>

where the localized content is simply an Object with properties, defined according to a special convention that gives a default set of strings as well as references to various translations. The resource at the path myApp/nls/myResources.js might look something like this:

define({
  root: {
    greeting: "Hello, world!"
  },

  de: true,
  'de-at': true
});

Here, English is provided as the default language, the fallback if no other translation is available. For German speaking users, on a page specifying ‘de’ as the locale or some de- variant, the property ‘de: true’ indicates that there is a translation available in a peer subdirectory called de, for a path of myApp/nls/de/myResources.js:

define({
  greeting: "Hallo, Welt!"
});

Continuing with the example, a variant may be provided for Austrian German at myApp/nls/de-at/myResources.js:

define({
  greeting: "Grüß Gott!"
});

Many more translations may be provided by simply appending a boolean flag to the root resource and creating the corresponding module in the appropriate subdirectory. The Dojo loader uses the conventions defined by the dojo/i18n! plugin to find the resource that is the best match for the user’s locale, mixing in variants with main languages and the ‘root’ resources such that the fallback will be used if a more specific string is not found. Therefore, multiple network requests may be involved to fetch a resource. Dojo’s builder optimizes this search by collecting or flattening all of the resources by locale, as well as concatenating multiple resource bundles used by the application, just as it does for JavaScript code modules. With or without the builder, the data is structured in such a way that only the translation for the particular locale in use is sent to the client.

Error in the documentation? Can’t find what you are looking for? Let us know!