Ext JS - Learning Center

Tutorial:Localizing Ext

From Learn About the Ext JavaScript Library

Jump to: navigation, search
Summary: This tutorial will show you how to localize (translate) Ext.
Author: Jozef Sakalos
Published: March 9, 2008
Ext Version: 2.0+
Languages: en.png Englishkr.png Koreancn.png Chinese

Contents

Introduction

If you are reading this tutorial you would not need any localization (translation to non-English language) at all as you must understand English. But what about our poor users, managers, secretaries, salesmen? They would prefer for sure to see Ext applications in their native language, right?

OK, let's see how could we do that.

Take it easy first

If you explore the Ext 2.x distribution tree you will find directory source/locale (or src/locale in SVN). This directory contains localization files for Ext classes. Without too much analysis and theories let's utilize these files first.

The following code contains an example of using localization that comes in-the-box of Ext. As usually, you will need to adjust paths in the head to point to your installation of Ext. Especially mind the path to localization directory.

Copy and paste the following to your server and adjust mentioned paths:

Notice: The code below works in Firefox only because for the tutorial purposes I dynamically include javascript file(s) in the head. You wouldn't use this technique for real application, you would let your server generate the appropriate locale script tag in the head instead.

<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <link rel="stylesheet" type="text/css" href="../ext/resources/css/ext-all.css">
    <script type="text/javascript" src="../ext/adapter/ext/ext-base.js"></script>
    <script type="text/javascript" src="../ext/ext-all-debug.js"></script>
    <script type="text/javascript">
 
    // decode language passed in url
    var locale = window.location.search 
                 ? Ext.urlDecode(window.location.search.substring(1)).locale 
                 : '';
 
    // append locale script to the head
    var head = Ext.fly(document.getElementsByTagName('head')[0]);
    if(locale) {
        Ext.DomHelper.append(head, {
             tag:'script'
            ,type:'text/javascript'
            ,src:'../ext/src/locale/ext-lang-' + locale + '.js'
        });
    }
 
    // create pre-configured example window extension class
    Ext.ns('Tutorial');
    Tutorial.LocalizationWin = Ext.extend(Ext.Window, {
        initComponent:function() {
            Ext.apply(this, {
                 width:500
                ,id:'winid'
                ,height:300
                ,layout:'fit'
                ,border:false
                ,closable:false
                ,title:Ext.get('title').dom.innerHTML
                ,items:[{
                     xtype:'form'
                    ,frame:true
                    ,defaultType:'textfield'
                    ,items:[{
                          xtype:'combo'
                         ,fieldLabel:'Select Language'
                         ,name:'locale'
                         ,store:new Ext.data.SimpleStore({
                             id:0
                            ,fields:['file', 'locale']
                            ,data:[
                                 ['cs', 'Czech']
                                ,['', 'English']
                                ,['fr', 'French']
                                ,['de', 'German']
                                ,['gr', 'Greece']
                                ,['hu', 'Hungarian']
                                ,['it', 'Italian']
                                ,['ja', 'Japaneese']
                                ,['pl', 'Polish']
                                ,['pt', 'Portugal']
                                ,['ru', 'Russian']
                                ,['sk', 'Slovak']
                                ,['es', 'Spanish']
                                ,['sv_SE', 'Swedish']
                                ,['tr', 'Turkish']
                            ]
                         })
                        ,listeners:{
                            select:{fn:function(combo){
                                window.location.search = '?' 
                                    + Ext.urlEncode({locale:combo.getValue()})
                                ;
                            }}
                        }
                        ,mode:'local'
                        ,editable:false
                        ,forceSelection:true
                        ,valueField:'file'
                        ,displayField:'locale'
                        ,triggerAction:'all'
                        ,value:locale
                     },{
                         fieldLabel:'Text Field'
                        ,allowBlank:false
                    },{
                         xtype:'datefield'
                        ,fieldLabel:'Date Field'
                        ,allowBlank:false
                    }]
                }]
            }); // eo apply
            Tutorial.LocalizationWin.superclass.initComponent.apply(this, arguments);
        } // eo function initComponent
    }); // eo Tutorial.LocalizationWin
 
Ext.BLANK_IMAGE_URL = '../ext/resources/images/default/s.gif';
Ext.onReady(function() {
    Ext.QuickTips.init();
    Ext.form.Field.prototype.msgTarget = 'side';
 
    // create example window
    var win = new Tutorial.LocalizationWin();
    win.show();
});
    </script>
    <title id="title">Localization Example</title>
</head>
<body>
</body>
</html>

The whole localization is now limited to basic Ext components that are ComboBox, TextField and DateField, in this example. Play a bit with it to see that you're really getting translated version of DatePicker and invalid texts.

How does it work?

Based on the selection in the "Select Language" combo box we include the particular "lang" file from the Ext locale directory. (I am using some tricks in the example, normally the server would generate the appropriate <script> tag in the head.)

What is inside of localization files?

Let's take a look at the content of localization files; understanding that will help us to localize not only Ext but whole applications. We take French translation of DatePicker :

if(Ext.DatePicker){
   Ext.override(Ext.DatePicker, {
      todayText         : "Aujourd'hui",
      minText           : "Cette date est antérieure à la date minimum",
      maxText           : "Cette date est postérieure à la date maximum",
      disabledDaysText  : "",
      disabledDatesText : "",
      monthNames        : Date.monthNames,
      dayNames          : Date.dayNames,
      nextText          : 'Mois suivant (CTRL+Flèche droite)',
      prevText          : "Mois précédent (CTRL+Flèche gauche)",
      monthYearText     : "Choisissez un mois (CTRL+Flèche haut ou bas pour changer d'année.)",
      todayTip          : "{0} (Barre d'espace)",
      okText            : "&#160;OK&#160;",
      cancelText        : "Annuler",
      format            : "d/m/y",
      startDay          : 1
   });
}

We can see that after initial test if DatePicker exists (this is needed because you can create your own Ext that does not need to have DatePicker class defined) we override some properties of DatePicker; simply, we replace English texts with French ones. Ext.override changes prototype of the class so the above code has to run before any DatePicker instance is created.

Application Localization

Let's rearrange our example application a bit, mainly, let's remove all static texts used and put them to class variables. The resulting code could look as follows:

<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <link rel="stylesheet" type="text/css" href="../ext/resources/css/ext-all.css">
    <script type="text/javascript" src="../ext/adapter/ext/ext-base.js"></script>
    <script type="text/javascript" src="../ext/ext-all-debug.js"></script>
 
    <!-- Ext localization javascript -->
    <script type="text/javascript" id="extlocale"></script>
 
    <!-- Locale and example extension javascript -->
    <script type="text/javascript">
 
    // decode language passed in url
    var locale = window.location.search 
                 ? Ext.urlDecode(window.location.search.substring(1)).locale 
                 : ''
    ;
 
    // append locale script to the head
    var head = Ext.fly(document.getElementsByTagName('head')[0]);
    if(locale) {
        Ext.fly('extlocale').set({src:'../ext/src/locale/ext-lang-' + locale + '.js'});
    }
 
    // create pre-configured example window extension class
    Ext.ns('Tutorial');
    Tutorial.LocalizationWin = Ext.extend(Ext.Window, {
         titleText:'Localization Example'
        ,selectLangText:'Select Language'
        ,textFieldText:'Text Field'
        ,dateFieldText:'Date Field'
        ,initComponent:function() {
            Ext.apply(this, {
                 width:500
                ,id:'winid'
                ,height:300
                ,layout:'fit'
                ,border:false
                ,closable:false
                ,title:this.titleText
                ,items:[{
                     xtype:'form'
                    ,frame:true
                    ,defaultType:'textfield'
                    ,items:[{
                          xtype:'combo'
                         ,fieldLabel:this.selectLangText
                         ,name:'locale'
                         ,store:new Ext.data.SimpleStore({
                             id:0
                            ,fields:['file', 'locale']
                            ,data:[
                                 ['cs', 'Czech']
                                ,['', 'English']
                                ,['fr', 'French']
                                ,['de', 'German']
                                ,['gr', 'Greece']
                                ,['hu', 'Hungarian']
                                ,['it', 'Italian']
                                ,['ja', 'Japaneese']
                                ,['pl', 'Polish']
                                ,['pt', 'Portugal']
                                ,['ru', 'Russian']
                                ,['sk', 'Slovak']
                                ,['es', 'Spanish']
                                ,['sv_SE', 'Swedish']
                                ,['tr', 'Turkish']
                            ]
                         })
                        ,listeners:{
                            select:{fn:function(combo){
                                window.location.search = '?' 
                                    + Ext.urlEncode({locale:combo.getValue()})
                                ;
                            }}
                        }
                        ,mode:'local'
                        ,editable:false
                        ,forceSelection:true
                        ,valueField:'file'
                        ,displayField:'locale'
                        ,triggerAction:'all'
                        ,value:locale
                     },{
                         fieldLabel:this.textFieldText
                        ,allowBlank:false
                    },{
                         xtype:'datefield'
                        ,fieldLabel:this.dateFieldText
                        ,allowBlank:false
                    }]
                }]
            }); // eo apply
            Tutorial.LocalizationWin.superclass.initComponent.apply(this, arguments);
        } // eo function initComponent
    }); // eo Tutorial.LocalizationWin
    </script>
 
    <!-- Application localization javascript -->
    <script type="text/javascript" id="applocale"></script>
 
    <!-- Set src for application localization javascript -->
    <script>
    if(locale) {
        Ext.fly('applocale').set({src:'app-lang-' + locale + '.js'});
    }
    </script>
 
    <!-- Main application -->
    <script type="text/javascript">
    Ext.BLANK_IMAGE_URL = '../ext/resources/images/default/s.gif';
    Ext.onReady(function() {
        Ext.QuickTips.init();
        Ext.form.Field.prototype.msgTarget = 'side';
 
        // create example window
        var win = new Tutorial.LocalizationWin();
        win.show();
    });
    </script>
    <title id="title">Localization Example</title>
</head>
<body>
</body>
</html>

And, the last step, we need to create application localization (translation, language) files. I speak Slovakian so here is Slovak app-lang-sk.js file - you can create your own language version (put the file to the same directory as html or adjust path to it in the above code):

/**
 * Slovak localization file of Localization Tutorial Example Window
 */
if(Tutorial.LocalizationWin) {
    Ext.override(Tutorial.LocalizationWin, {
         titleText:'Príklad lokalizácie'
        ,selectLangText:'Zvoľ jazyk'
        ,textFieldText:'Textové pole'
        ,dateFieldText:'Dátumové pole'
    });
}

Advanced Hints

Please, take the above as basics of principles of localization applications in Ext. The key point is: Put all texts to public class variables and then override them with translated versions.

Advanced developers will immediately feel some drawback of having, maintaining and deploying that many localization files especially if they already have a server with some translating infrastructure such as GNU gettext. For these users I would recommend to generate localization files on the fly by the server using gettext as backend.

The main advantage of this approach would be the central translation files (*.po) for both client and server side purposes.

Should this subject become hot and you would be very interested in how to do it I would write an Advanced Localization of Ext tutorial.

Enjoy!

Further reading:

  • This page was last modified 14:19, 7 May 2009.
  • This page has been accessed 28,480 times.