ExtJS 5/6 : Grid’s RowEditing Locale & Options

Within a Grid, RowEditing plugin is convenient to edit values directly. However, Locale (l10n, i18n) is  (sometimes) a mess with ExtJS 5 or 6, and that’s still the case with RowEditing.

However, one very simple way to solve this is to override button labels/messages while declaring/configuring the plugin:

Ext.define('MyApp.view.DataGrid',{
    extend: 'Ext.grid.Panel'
    ,requires: [
        'Ext.grid.plugin.RowEditing'
    ]
    ,plugins: [
        {
            ptype: 'rowediting',
            clicksToEdit: 2,  
            disabled: false, // disable RowEditing, tgrough binding for example
            saveBtnText: i18n('global.update'), // label for update/save btn
            cancelBtnText: i18n('global.cancel') // label for cancel btn
            errorsText: 'Errors', // errors text dirtyText: 'You need to commit or cancel...' // if record is dirty 
         } 
    ] /* ... */ });

And that’s all !!!  You could notice that I also declare “disabled” field as I bind it to enable/disable RowEditing plugin on the fly (for example, based on user profile).

For example, in the following screenshot, buttons are in french:

ExtJS Grid Row Editing in French
ExtJS Grid Row Editing in French

ExtJS 5/6 : localization / i18n / l10n

 

This post is an update of previous one : https://abarre.wordpress.com/2015/09/29/extjs-5-and-localization/

Project files are now hosted on GitHub : GitHub “extjs-i8n-lang” Project

Approach

This approach is very simple:

  1. Create a ‘Lang’ class
  2. Add languages string based on a ‘yaml/json’ tree approach
  3. Create some shortcuts
  4. Add you ‘Lang’ class in ExtJS’s Application requires section
  5. Use it

The ‘Lang’ class template

Ext.define('Lang',{
    singleton : true

    ,config : {
        currentLang : null,
        defaultLang : 'us'
    }

    ,getStrings: function(lang) {
        if (!lang || !Ext.isDefined(this.strings[lang]))
            lang=this.getDefaultLang();
        if (Ext.isString(this.strings[lang])) // got an aliase
            lang = this.strings[lang];
        return Ext.isDefined(this.strings[lang])
                ? this.strings[lang]
                : { };
    }

    ,t : function(label, lang) {
        var path = label.toLowerCase().split('.'),
            p = this.getStrings(lang); // strings
        for (var i = 0; i<path.length; i++) {
            if (Ext.isDefined( p[ path[i] ]))
                p = p[ path[i] ];
            else return '<<' + label + '>>';
        }
        return p;
    }

    ,constructor : function(config) {
        this.initConfig(config);
        if (!this.getCurrentLang())
            this.setCurrentLang( this.getDefaultLang());
    }

    strings: {
        'us_US': {
            'hello_world': 'Hello World!',
            'map' : 'Map'
        },
        'fr_FR': {
            'hello_world': 'Bonjour Le Monde!',
            'map' : 'Carte'
        },
        'es_ES': {
            'hello_world': 'Ola el Mundo!',
            'map' : 'Carto.'
        }
    }
});
var i18n = function(label, lang) { return Lang.t(label, lang); };

Usage

i18n('hello_world')
i18n('map')

ExtJS 5/6 : Localization / i18n / l10n

Ok, let’s be honest. Current localization in ExtJS 5.x is a mess and everything but efficient at this time.

IMO, the best approach is to set everything outside. The approach I’m using is quite simple and is deeply inspired from a YAML approach (and next release of my class Lang/i8n class will support YAML directly).

The cons: only one : At this time, you cannot change the lang dynamically/on-the-fly. Language is set just before Main App starts.

The “YAM-inspired” implementation:

Ext.define('Lang',{
    singleton : true

    ,config : {
        currentLang : null,
        defaultLang : 'fr'
    }
// Here starts string declarations
    ,strings: {
        'fr_FR' : {
            desktop: {
                map : "Carte"              
            }
            ,settings: {
                stretch: "Ajuster/Etirer"
                ,wallpaper: "Fond d'écran"
                ,preview: "Aperçu"
                ,none: "Aucun"
            }
        }
        ,'us_US' : {
            desktop: {
                map : "Map"
            }
            ,settings: {
                stretch: "Stretch to fit"
                ,wallpaper: "Wallpaper"
                ,preview: "Preview"
                ,none: "None"
            }
        }
// end of string declarations
        // shortcuts
        ,fr : 'fr_FR'
        ,en : 'us_US'
        ,us : 'us_US'
    }

    ,getStrings: function(lang) {
        if (!lang || !Ext.isDefined(this.strings[lang]))
            lang=this.getDefaultLang();
        if (Ext.isString(this.strings[lang])) // got an aliase
            lang = this.strings[lang];
        return Ext.isDefined(this.strings[lang])
                ? this.strings[lang]
                : { };
    }
    // Do the translation
    ,t : function(label, lang) {
        var path = label.toLowerCase().split('.'),
            p = this.getStrings(lang); // strings
        for (var i = 0; i<path.length; i++) {
            if (Ext.isDefined( p[ path[i] ]))
                p = p[ path[i] ];
            else return '<<' + label + '>>'; // not found
        }
        return p;
    }

    ,constructor : function(config) {
        this.initConfig(config);
        if (!this.getCurrentLang())
            this.setCurrentLang( this.getDefaultLang());
    }
});
var i18n = function(label, lang) { return Lang.t(label, lang); };

How to use it :
– in main app, add ‘Lang’ to requires  (it Lang is in main directory)

requires: [
    'Lang',
]

– set language : Lang.SetCurrentLang(‘en’) for example
– get a string : i18n(“settings.wallpaper”) or Lang.t(“settings.wallpaper”)

Improvements/ToDo List

  • Import YAML or JSON directly as a lang file (ie not built-in)
  • Change current language on the fly, without reloading