Advanced Topics » Localization/Internationalization

Localization/Internationalization

Last modified by Michael mkantor on 2011/08/02 16:30

Localization

Localization refers to the tools, techniques and steps taken to enable your application to run in other languages where "things are done differently". There are two broad categories of localization that are commonly dealt with:

  1. Localize words to the language of users in this location. If you built your application in Swahili, and want Americans to use your application too, you can either require them to learn Swahili or provide an english language version of your application
  2. Localize the formatting of values. Americans don't format dates and times the same way as most European countries. The proper way to present large number or currencies may also vary from region to region.
  3. Not dealt with in this document: special cases of localization such as right-to-left languages, non-western calendaring systems, and related issues that have not been built into the WaveMaker Framework.

config.js, dojo.locale and HTTP_ACCEPT headers

Dojo manages localization by determining the best value for dojo.locale. It determines this by looking at the browser's navigation.language settings. However, these settings don't necessarily change when the user changes the browser's language; the only reliable way to get the language that a browser has been set for is using the HTTP_ACCEPT headers.

It used to be that you could specify in config.js:

djConfig.locale = "fr";
to force the language to be french. This ability has been replaced by allowing the browser to detect and automatically use the language sent by the browser to the server in the "HTTP_ACCEPT" headers where the server is told what language the browser prefers.

You can also change languages in the URL using for example:

http://localhost:8080/MyProject/?dojo.locale=fr

To understand location codes, and how dojo's localization framework works, its worth reading http://dojotoolkit.org/reference-guide/quickstart/internationalization/resource-bundling.html

A good listing of codes can be found in the first column of http://msdn.microsoft.com/en-us/library/ee825488(v=cs.20).aspx

As of 6.4, If your absolutely MUST override HTTP_ACCEPT, you can put wm.language="xx" in your config.js which acts like djConfig.locale used to work.

Widgets with Locale Properties

Various widgets change their presentation based on localization. DojoGrid presenting dates using its DateFormatter option; wm.Label with a DateFormatter can also change how it presents dates based on locale. Typically, you want to leave localization alone. The default presentation of a date will use the locale set by the user's browser. Only if you need to force it into some other presentation do you need to dig deeper.

For working with Label formatters and editors, there will typically be a locale property into which you can enter "fr", "ja", "en", "en-us" or other location codes. For DojoGrid, at this time, you will need to create your own custom formatter method in your Page code to change it from using the default formatter.

Dojo Formatters

There are also standard dojo methods to be familiar with for creating your own custom formatters:

dojo.date.locale

http://dojotoolkit.org/api/1.6/dojo/date/locale

This dojo package provides two methods: format and parse, which can leave locale to default or specify a new locale

// d is a string with the default locale and default formatting options
var d = dojo.date.locale.format(new Date()); 

// d is a string formatted using japanese default formatting options 
var d = dojo.date.locale.format(new Date(), {locale: "ja"});

dojo.number.parse/format

http://dojotoolkit.org/api/1.6/dojo/number/format

The example code for number is essentially the same as the date example above

dojo.currency.parse/format

http://dojotoolkit.org/api/1.6/dojo/currency

The example code for currency is essentially the same as the date example above

Localizing Currency

At this time, WaveMaker does not support automatic localization of currency. If your database says a product is worth 500, it can't format that as $500 in the United States and 500 pounds in Europe as these are not different formats, they are in fact, completely different values. wm.Label's Currency formatter and wm.Currency both let you enter a localization code "en-us", "fr", "ja", etc… to specify the currency. For wm.DojoGrid, the currency is hard coded to "$", and to change this you must write a custom formatter; perhaps using dojo.currency.format.

Starting in 6.4, all currency formats can be setup using the project property currencyLocale; select your project in the services tab, and edit the currentyLocale property.

Localizing the Server Language

If your java code returns textual responses that are not simply data but, for example, instructions to present to the user, you may need to localize your java code.

This document focuses on client-side localization, not server side localization. The key information that you need here is that you should receive an HTTP_ACCEPT header that specifies what languages are preferred by the client.

NOTE: HTTP_ACCEPT will not be correct if using dojo.locale= in the URL to force a new language to be used.

Localizing the Client Language

The i18n Property

Your application level widgets are localized by loading from your application-level dictionary files.

Your page level widgets are localized by loading from your page-level dictionary files.

Loading these dictionary files impacts the load time for an application, and therefore will only happen if you specify for that application or page that there is a dictionary.

Your project level properties now have an i18n property which determines whether the application-level dictionary is loaded.

Your page also needs an i18n property, which needs to be set as follows:

dojo.declare("Main", wm.Page, {
 i18n: true,
    start: function() {
    }
    _end: 0
});

Localization Synopsis

The WaveMaker Framework provides localization using

dojo.requireLocalization("wm.language", "components");
dojo.i18n.getLocalization("wm.language", "components");
Code sample 1

For more information on how these work, please start at http://dojotoolkit.org/reference-guide/quickstart/internationalization/resource-bundling.html. The key thing to understand is that if my computer tells the browser that its using Japanese, it finds the shortcode "ja" for japanese, and any time a dictionary is loaded, it will load two files:

<path-to-dictionary>/dictionary.js\\<path-to-dictionary>/ja/dictionary.js
If its english, it will load
<path-to-dictionary>/dictionary.js
<path-to-dictionary>/en/dictionary.js

All definitions in /dictionary.js that are not overridden by definitions in the language specific dictionary are kept, but any definition in the language specific dictionary takes precedence over the one in the main dictionary.

Projects (and Studio counts as a project) will use the following localization techniques:

TypeUsed by
DescriptionDictionary Location
Page level dictionaryStudio and ProjectsEach time a wm.Page is loaded it will load a dictionary file from the server. The user's javascript file can reference terms in this, and the widgets.js file will automatically look for property overrides in it.project/webapproot/language/nls/.js
studio/webapproot/language/nls/.js
Application level dictionaryProjects (studio could but doesn't use it)
This is the same as the page level dictionary, but allows Application-level javascript and components to be customized. File goes in webapproot/language/nls/app.js.project/webapproot/language/nls/app.js
studio/webapproot/language/nls/app.js
Component specific dictionaryStudio and ProjectsVarious components (wm.Component for example) use strings that can be localized. The toString method is an example of this. It looks up in the component dictionary terms to use when describing the current object. This is used by both studio and when running projects, but can only be edited by people localizing studio.
studio/webapproot/lib/wm/language/nls/components.js
Default property dictionary Studio and Projects Various components (wm.Button, wm.Label, wm.Dialog) use default properties that can be localized. For example, when I drag a button onto my canvas at design time, the default caption is "Button". You can change the default properties of all widgets for both studio and runtime.
studio/webapproot/lib/wm/language/nls/properties.js
Property namesStudioA mechanism has been provided to change the displayName of properties in studio's properties panel. This does not change the actual name (caption is still caption, but can be displayed as any string you want within the properties panel)studio/webapproot/language/nls/schema.js
Property group namesStudioChanges the group names from "display", "common", "validation" to localized strings.studio/webapproot/language/nls/schema.js
Property node namesStudioChanges the property node names such as "Properties", "Styles", "Events" and "Security" to localized namesstudio/webapproot/language/nls/schema.js
Property Values
NoneEventually it would be nice to localize property values; so instead of "left-to-right" layout, it could use a localized term. But this is not yet supported.

Page Level Dictionary

The Page level dictionary is used by the the user's javascript page (Main.js) and the widgets.js file (Main.widgets.js) to localize the page. The dictionary files for the page "Main" go in

webapproot/language/nls/Main.js
webapproot/language/nls/ja/Main.js (japanese)
webapproot/language/nls/fr/Main.js (french)
NOTE: for a full list of language codes, see the two letter "ISO 639-1" codes on http://www.loc.gov/standards/iso639-2/php/code_list.php

NOTE: If your page is MyPage, replace "Main.js" with "MyPage.js" in the examples here.

Here is a sample dictionary in webapproot/languages/nls/ja/Main.js; it will be explained in more detail in the next section.

{
helloWorldLabel: {caption: "&#12371;&#12435;&#12395;&#12385;&#12399;&#19990;&#30028;", width: "150px"},
okButton: {caption: "&#23436;&#20102;"},
SCRIPT_WELCOME_ALERT_SIMPLE: "&#12371;&#12435;&#12395;&#12385;&#12399;&#19990;&#30028;",
SCRIPT_WELCOME_ALERT: "&#12371;&#12435;&#12395;&#12385;&#12399;&#19990;&#30028; ${user}"
}
Code sample 2

Customizing your Widgets

When generating pages using your page's widgets file (Main.widgets.js), Studio will check your dictionary file to see if the widget has any property changes. Lets suppose that your widgets.js file looks like this:

Main.widgets = {
    layoutBox1: ["wm.Layout", {"height":"100%","horizontalAlign":"left","verticalAlign":"top","width":"100%"}, {}, {
        helloWorldLabel: ["wm.Label", {"border":"0","caption":"Hello World", width: "200px", "padding":"4"}, {}],
        okButton: ["wm.Button", {"caption":"OK","margin":"4"}, {}],
        label1: ["wm.Label", {"border":"0","caption":"label1","padding":"4"}, {}]
    }]
}]
Code sample 3

On creating each component (visual or nonvisual) the framework will check the dictionary to see if there is a component of that name in the dictionary, and if so, will read in its properties. Which means given the dictionary from Code sample 2 and widgets.js file from Code sample 3:

  1. When running in english, the japanese dictionary is not loaded, and all widgets behave exactly as specified in widgets.js
  2. When running in japanese,
    1. the japanese dictionary will automatically load
    2. helloWorldLabel will get the caption "こんにちは世界" and a width of "150px",
    3. okButton will get a caption of "完了"
    4. label1 will not be changed in any way
  3. When running in french
    1. the french dictionary will automatically load. If its there, it will behave just like the japanese dictionary; if its not there, the page will display its unmodified widgets.js file just as if we were running in english.

Customizing your Script

Lets suppose you have a script you want to localize. Your script might change a caption, prompt the user for information, provide a "Success" toast message, or try to communicate with the user in other ways. There are two basic calls used to localize your page:

  1. this.getDictionaryItem("SCRIPT_SOME_TERM") -> Returns "SCRIPT_SOME_TERM" from your page's dictionary
  2. this.getDictionaryItem("SCRIPT_SOME_TERM", {name1: value1, name2: value2}); -> Takes "SCRIPT_SOME_TERM" from your dictionary and substitutes in value1 and value2.
This sample page uses the dictionary from Code sample 2.
dojo.declare("Main", wm.Page, {
    start: function() {
        try {
            app.alert(this.getDictionaryItem("SCRIPT_WELCOME_ALERT_SIMPLE"));
        } catch(e) {
            app.toastError(this.name + ".start() Failed: " + e.toString()); 
        }
    },
         onLoginSuccess: function(inSender) {
            var userName = inSender.getValue("username");
            app.alert(this.getDictionaryItem("SCRIPT_WELCOME_ALERT", {user: userName}));
        }
    _end: 0
});
Code sample 4

NOTE: Substitution of parameters into the string uses dojo.string.substitute: http://dojotoolkit.org/api/1.5/dojo/string/substitute; your dictionary term is the first parameter, and your hash ({user: userName}) is the second parameter.

NOTE: Unlike customizing your widgets.js, you MUST have a default version of these dictionary terms. For the above example, there must be a language/nls/Main.js file, and it must define the default, unlocalized versions of SCRIPT_WELCOME_ALERT and SCRIPT_WELCOME_ALERT_SIMPLE

language/nls/Main.js:

{
SCRIPT_WELCOME_ALERT_SIMPLE: "Hello",
SCRIPT_WELCOME_ALERT: "Welcome ${user}"
}
Code sample 5: shows the minimum required dictionary at nls/Main.js that must go with the localized dictionary inCode sample 2. When running in english, the widget localizations are not needed, but all terms used by the script must be there or errors will be thrown and the page will fail to run.

App Level Dictionary

The App level dictionary follows all of the rules described above for pages, but applies to your application level widgets and event handlers. The dictionary files for the application go in

webapproot/languages/nls/app.js
webapproot/languages/nls/ja/app.js (japanese)
webapproot/languages/nls/fr/app.js (french)
App level dictionary is not needed to localize studio; at the time of writing this, it is intended only for localizing projects.

Localizing Studio

All of the data above is relevant for localizing studio. Additional services have been added to help localize studio that aren't required for other projects.

Localizing Studio

Tags:
Created by Michael mkantor on 2011/06/26 14:45

2012-2014 WaveMaker Inc. All Rights Reserved.
Share/Bookmark