Skip to content
This repository has been archived by the owner on Jul 8, 2020. It is now read-only.

Internationalization (The M Project 1.x)

hano edited this page Dec 3, 2013 · 1 revision

Introduction

Since variety is one of the goals of The M-Project, we both support a large number of different devices and provide a built-in mechanism to localize an application. With M.18N, i18n is an abbreviation of internationalization, you are able to localize any String within an application, to automatically detect the user's language, to define the application's default / fallback language and even to persistently set the user's language right inside your application.

How do I get started?

Working with M.I18N is pretty easy. All you need to do is to create a language file for every language you want your application to “speak”. These language files are written in JSON syntax and stored in an i18n folder inside your application. The name of a language file is based on the language it stands for, the file extension is .js. To match the language file with your Controller you have to tell your config.json with language your app speaks. Too much information for one paragraph? Don't worry, we will go into details now.

Let's say you want to specify your application with an english language file. What do you need to do? First of all you need to create a folder inside your application folder called i18n eg. mkdir app/resources/i18n. Inside that folder you need to create a file called en_us.js. The file's name is based on both the language (English) and the country (U.S.) since there might be differences between British English (“en_gb”) and American English (“en_us”). These language codes are based on ISO 639. The file extension .i18n works as a reference for our internal language detector.

Once you've created your language file, you can start specifying the localized strings for this language. As mentioned before, a language file is written in JSON syntax. The following sample file, en_us.js, will give you an impression of how such a file looks like:

M.I18N.en_us = {

    "registry": "Registry",

    "firstname": "Firstname",

    "lastname": "Lastname",

    "submit_btn": "Submit",

    "firstname_req": "Firstname is required",

    "lastname_req": "Lastname is required",

    "date_format": "mm/dd/yyyy HH:MM"

}

As you can see, you basically extend M.I18N by a property that is called according to the language you want to specify respectively according to the name of your language file, e.g. M.I18N.en_us. Inside that property you simply specify key / value pairs, while the key is what you will later refer to in your view or controller. So let's take a look at how you do that.

How to use the specified languages in the view?

Once you've specified some values inside your language file, you can use them inside your view. The key for this is the l() method inside M.I18N. Just call this method anywhere you want a localized string to be displayed and pass along the correct key, specified inside the language file. M.I18N then will return the according value, based on the user's language. If the user's language doesn't match a language file, the default language is taken. But let's take a look at some code for giving you a better understanding of how to use M.I18N.l():

page: M.PageView.design({

    childViews: 'header content',

    header: M.ToolbarView.design({

        value: M.I18N.l('registry'),

        anchorLocation: M.TOP
    }),

    content: M.ScrollView.design({

        childViews: 'label',

        label: M.LabelView.design({

            value: M.I18N.l('firstname')

        })

    })

})

Tell your App which languages ​​it speaks

Now you have to build a bridge between your language files eg. en_en.js and your Controller or View. So you have to add "supportedLanguages" to your config.json file. "supportedLanguages" represents an array that contains all supported languages eg.: "en_us".

...
"supportedLanguages": [
        "en_us",
        "en_gb",
        "de_de"
    ]
...

Can I also use it inside of a controller?

Sure! You can use M.I18N wherever a string is needed. For example, M.I18N is a pretty convenient way to specify a date format for a dynamically loaded or user entered date. Let's say your application provides an input element for a date and the users enters or selects a specific date and then submits it to your controller. Before applying it to a view you'd probably like to format the date. If this is a specific formatting for just one view, you might use Dynamic Value Computing, but if it is a general formatting, you can easily do this inside the controller by using M.I18N right there. This could look something like the following:

MyApp.MyController = M.Controller.extend({
    
    date: null,

    setDate: function() {

        // retrieve the date string from a view or any storage
        var dateString = M.ViewManager.getView('page', 'date').value;

        // create a date object, using M.Date.create()
        var dateObj = M.Date.create(dateString);

        // format the date using M.Date.format and a language specific date format string
        var dateFormat = M.Date.format(dateObj , M.I18N.l('date_format'));

        // asign the formatted date string to the controller's date property so any observer gets notified
        this.set('date', dateFormat);

    }

});

How to set the application's language programmatically?

The default behaviour of M.I18N is to detect the user's language based on its browser. If there is a language file specified for this language, this one is applied to the application. Otherwise the application's default language is selected. If there is no default language specified, the system's fallback language is selected: American English (“en_us”). But if you want the user to be able to select the application's language right inside the application, M.I18N provides you with mechanism for that, too. You can use the setLanguage() method to programmatically set the application's language. Just pass along a string, referring to the desired language, e.g. “de_de” (German). The setLanguage() method then will check if the desired language is available. If so, the language is stored in the browser's locale storage and then the application is reloaded automatically. The language detection process on the application's startup then will detect the language stored in the browser's locale storage and take this as the application's current language.

Is there a view for the language selection?

No, since this is a very specific problem, there is no built-in “languageSelector” view. But a pretty convenient way is to use M.SelectionList in the M.SingleSelection mode. The M.SelectionList's onSelect property can be used to specify a method inside your controller where you actually do the language switch by calling M.I18N's setLanguage() method. The following code sample will give you an impression of how this could look like:

langSelection: M.SelectionListView.design({

    childViews: 'item1 item2 item3',

    selectionMode: M.SINGLE_SELECTION,

    name: 'language',

    onSelect: {
        target: MyApp.MyController,
        action: 'changeLanguage'
    },

    item1: M.SelectionListItemView.design({
    
        label: M.I18N.l('german'),
        value: 'de_de'

    }),

    item2: M.SelectionListItemView.design({

        label: M.I18N.l('english'),
        value: 'en_us'

    }),

    item3: M.SelectionListItemView.design({

        label: M.I18N.l('spanish'),
        value: 'es_es'

    })

})

Integrated in a real application, this language selection element could look somethin like this: