Multi-Language Support in a PhoneGap Mobile App

Description

Adding multi-language support for an offline-enabled PhoneGap application cannot be done using Language tags or Text Dictionary tags since these tags are resolved by the Alpha Anywhere Application Server, requiring an Ajax Callback. This article explains how to add multi-language support in an offline application.

Discussion

Normally, when you create a multi-language application you add Language tags (<a5:r>) or Text Dictionary tags (<a5:t>) around the strings that you want to translate into different languages. So, for example, the label for a Lastname control might be specified as <a5:r>Lastname</a5:r> (Language tag) or <a5:t>Lastname</a5:t> (Text Dictionary tag).

Language tags are resolved on the server, and the HTML that is sent from the server to browser has all of the strings in the selected language.

But in a PhoneGap application, you can't use the approach because the app is loaded from the filesystem on the device. There is no Ajax callback to the server. In fact, the server might not even be running when the app is loaded. Therefore, in order to create a multi-language app that can run on PhoneGap and can run disconnected, you need a solution that can be implemented on the client side using JavaScript.

The approach that you will take is similar to wrapping strings in language tags or text dictionary tags, except that you will wrap the strings you want to translate in special <span> tags. For example if you want to translate the label for the 'LastName' control, you would encode the label as follows:

<span id="_language_LASTNAME" class="_language">Last Name</span>

Notice that the <span> tags have a special id that is used as a key into the language translation object (discussed below) and a special class name (_language) that is simply used so that all of the elements that need to be translated can be quickly found using the JavaScript getElementsByClassName() method.

Once you have tagged all of the strings that need to be translated, you will need to create some JavaScript that defines the translated strings. You can either defined this JavaScript in the Javascript Functions section in your UX component, or you can define it in an external file that is linked by your component.

Assume that your app should support English, French, German and Spanish. Assume also that you have defined the following strings in your component that will need to be translated:

<span id="_language_LASTNAME" class="_language">Last Name</span>
<span id="_language_FIRSTNAME" class="_language">First Name</span>
<span id="_language_CITY" class="_language">City</span>

Your JavaScript will define an object that has properties for each string that must be translated. So, in the above example, your JavaScript will define an object like this:

var _translations = {
    "LASTNAME" : {
        "english" : 'Last Name',
        "french" : 'Nom de famille',
        "german" : 'Familienname',
        "spanish" : 'Apellido'
    },
    "FIRSTNAME" : {
        "english" : 'First Name',
        "french" : 'Prénom',
        "german" : 'Vorname',
        "spanish" : 'Nombre de pila'
    },
    "CITY" : {
        "english" : 'City',
        "french" : 'Ville',
        "german" : 'Stadt',
        "spanish" : 'Ciudad'
     }
}

At run-time, when the user wants to change from one language to another, your JavaScript will loop over all of the strings that need to be translated and it will set the inner HTML of the span to the text in the correct language. To get an array of all of the strings that need to be translated, you can use this JavaScript:

var arr = document.getElementByClassName('_language');

To get the translated string, you do a lookup into _translations JavaScript object. For example, to find the value for the Last Name string in French you would use this code:

var string = _translation['LASTNAME']['french'];

To replace the value of the Last Name string with its French version, you would use this code:

$('_language_LASTNAME').innerHTML = _translation['LASTNAME']['french'];

You can automate the process of setting the language strings to their translated value using this code:

var arr = document.getElementsByClassName('_language');
var ele = '';
var id = '';
var key = '';
for(var i = 0; i < arr.length; i++) {
    ele = arr[i];
    id = ele.id;
    key = id.split('_language_')[1];
    var string = _translations[key][language];
    $(id).innerHTML = string;
}

This code starts by getting an array of all of the element that have a class name of _language. These are the <span> elements that wrap the strings to be translated. The code loops over this array. For each item in the array, we get the element id. This will be a value like _language_LASTNAME.

Next, the key is derived from the element id. So for an element id of _language_LASTNAME a key of LASTNAME is obtained. Once we have the key we can lookup a value in the _translations object for a particular key and language. For example, _translations['LASTNAME']['spanish'] is the Spanish value for the 'LASTNAME' field.

Once we have the translated string value, we can set the inner HTML of the element (ele.id).

A more complex version of the above script is shown here. In this version, if a translated string is not found for a particular string, then the string value is not changed.

function doTranslate(language) {
    if(typeof _translations == 'undefined') return false;
    var arr = document.getElementsByClassName('_language');
    var ele = '';
    var id = '';
    var key = '';
    for(var i = 0; i < arr.length; i++) {
        ele = arr[i];
        id = ele.id;
        key = id.split('_language_')[1];
        if(typeof _translations[key] == 'undefined' || _translations[key] == null) return false;
        var string = _translations[key][language];
        if(typeof string != 'undefined' && string != null && string != '') $(id).innerHTML = string;
    }
}

 Sample Template

A sample template that shows the technique discussed in this article can be loaded when you create a new UX component. Search for the MobileAppFramework_Client-side-Language_Translation template in the list of available templates.

See Also