Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / web / HTML

[TinyERP: SPA for Enterprise Application]Multiple languages

5.00/5 (1 vote)
9 Dec 2018Apache4 min read 2.5K  
Overview. In this article, let see how we use multiple languages in TinyERP.. Currently, In html files, ts file for HRM were still using hard-code value (I mean hard-code value of string). And this was not good for enterprise application which supports multi languages as default..

Overview

In this article, let see how we use multiple languages in TinyERP.

Currently, In html files, ts file for HRM were still using hard-code value (I mean hard-code value of string). And this was not good for enterprise application which supports multi languages as default.

Use locale texts

This is what I have for stafs.html file at the moment:

<page>
    <page-header>
        Manage Staffs
        <page-actions class="pull-right" [actions]=model.actions></page-actions>
    </page-header>
    <page-content>
        <grid 
            [options]="model.options" 
            [fetch]="fetch">
        </grid>
    </page-content>
</page>

The title fro this page was "Manage Staffs". So I would prefer to replace this by "i18n.hrm.staff.title".

Why "i18n.hrm.staff.title"?

i18n is the standard name for localization, so "i18n" will help other developer easier to understand the cope of this variable. it was limited to localization only.

and why "hrm"?

Each module will have its own locale file, for example HRM module will have the locale file named hrm.json. this file will contain all text value  used in HRM module, and of-course, other module should not store its locale texts in this file. this is the convention in TinyERP. Locale files were stored in "<root>\resources\locales\<module_name>.<language>.json" format.

"module_name" is the name of module, such as hrm in this case.

"language" is the language we support inside our app. such as en for Enlish, vn for Vietnames. for more information, see at the bottom of this article, we have the same for multi-languages.

Why "staffs"?

this also contains all texts for staff page. so in this page, we can have text for title, text for first name, ....

With the name "i18n.hrm.staffs.title", we know the meaning and we can use it. of-course, if somewhere in your all use the same text with i18n.hrm.staffs.title. I suggest that you should define new value for that location. should not re-use this value in other location. Except, we describe the scope in the name, such as: "i18n.hrm.common.manageStaff". this value we can use around in side HRM module.

And the result for staffs.html will be:

<page>
    <page-header>
        {{i18n.hrm.staffs.title}}
        <page-actions class="pull-right" [actions]=model.actions></page-actions>
    </page-header>
    <page-content>
        <grid 
            [options]="model.options" 
            [fetch]="fetch">
        </grid>
    </page-content>
</page>

It was easy to understand, right?

And we can access to locale value from ts by using i18n property of Page object, so staffs.ts will be changed to:

export class Staffs extends BasePage<StaffsModel>{
    public model: StaffsModel;
    constructor() {
        super();
        let self = this;
        self.model = new StaffsModel(this.i18n);
        self.model.addAction(new PageAction("",()=>{self.onAddNewStaffClicked();}).setText(self.i18n.hrm.staffs.addNewStaff));
    }
    private onAddNewStaffClicked():void{
        this.navigate(routes.addNewStaff.name);
    }
    public fetch(): Promise {
        let def: Promise = PromiseFactory.create();
        let service: IStaffService = window.ioc.resolve(LocalIoCNames.IStaffService);
        service.getStaffs().then(function (searchResult: any) {
            def.resolve(searchResult.items || []);
        });
        return def;
    }
}

If you was not really like to use "this.i18n" variable, you can change to:

self.model.addAction(new PageAction("hrm.staffs.addNewStaff",()=>{self.onAddNewStaffClicked();}));

they work in the same way.

Ok, what about StaffsModel class, we also need to get locale text for the header of grid.  See line 6 above, we have:

self.model = new StaffsModel(this.i18n);

and in side StaffsModel, we can get locale text from i18n varaible:

export class StaffsModel{
    public actions:Array<PageAction>=[];
    public options: any = {};
    constructor(i18n: any){
        this.options = {
            columns: [
                { field: "firstName", title: i18n.hrm.staffs.firstName},
                { field: "lastName", title: i18n.hrm.staffs.lastName},
                { field: "department", title: i18n.hrm.staffs.department}
            ]
        };
    }
    public addAction(action: PageAction):void{
        this.actions.push(action);
    }
}

It was simple, right?  I think the answer is "yes".

the last step, let open "hrm.en.json" in <root>/resources/locales/ folder and update as below:

{
    "staffs":{
        "title":"Manage Staffs",
        "addNewStaff":"Add Staff",
        "firstName":"First Name",
        "lastName":"Last Name",
        "department":"Department"
    }
}

Ok, it is ok for staffs page, you can do the same for "addNewStaff" page yourself, and we have the result for "addNewStaff.html" as below:

<page>
    <page-header>{{i18n.hrm.addNewStaff.title}}</page-header>
    <page-content>
        <horizontal-form>
            <form-text-input [labelText]="i18n.hrm.addNewStaff.firstName" [(model)]=model.firstName></form-text-input>
            <form-text-input [labelText]="i18n.hrm.addNewStaff.lastName" [(model)]=model.lastName></form-text-input>
            <form-primary-button [label]="i18n.common.form.save" (onClick)="onSaveClicked($event)"></form-primary-button>
            <form-default-button [label]="i18n.common.form.cancel" (onClick)="onCancelClicked($event)"></form-default-button>
        </horizontal-form>
    </page-content>
</page>

and the content of hrm.en.json will be:

{
    "staffs":{
        "title":"Manage Staffs",
        "addNewStaff":"Add Staff",
        "firstName":"First Name",
        "lastName":"Last Name",
        "department":"Department"
    },
    "addNewStaff":{
        "title":"Add new Staff",
        "firstName":"First Name",
        "lastName":"Last Name"
    }
}

woa woa, inside hrm module uses locale texts from other, I see we have "i18n.comnmon.form". I break the rule????

No, In our application, there are some cases, we share the same locale texts with the same meaning in all situations, such as: "save" action on the form. SO we can create new locale file names common and put all of them there. So the scope for those locale texts is the whole app. every where can access and use it.

Ok, let compile and run, we see it was the same:

and AddNewStaff:

 

 Let change the language

How does it work if we change current working language in the application.

Let add "Change language" button into AddNewStaff page:

<page>
    <page-header>
        {{i18n.hrm.addNewStaff.title}}
        <form-default-button [label]="'Change Language'" (onClick)="onChangeLanguageClicked($event)"></form-default-button>
    </page-header>
	////....
</page>

and also update in AddNewStaff.ts:

export class AddNewStaff extends BasePage<AddNewStaffModel>{
    private currentLanguage:string="en";

    public onChangeLanguageClicked(){
        let newLanguage:string=this.currentLanguage=="en"?"vn":"en";
        this.i18nHelper.reload(newLanguage);
        this.currentLanguage=newLanguage;
    }
//...	
}

We can see that we have "currentLanguage" local variable which tell us the current language for the app. we temporarily use hard-code value to show how to change the language.

Click on the "Change Language" button, we will call to reload method with new language as parameter. not too complicated.

We also need to create the copy of current hrm.en.json and named hrm.vn.json, update content of this file as below:

{
    "staffs":{
        "title":"Manage Staffs vn",
        "addNewStaff":"Add Staff  vn",
        "firstName":"First Name vn",
        "lastName":"Last Name vn",
        "department":"Department vn"
    },
    "addNewStaff":{
        "title":"Add new Staff vn",
        "firstName":"First Name vn",
        "lastName":"Last Name vn"
    }
}

I only add "VN" into the text, Please create the copy for common.en.json, default.en.json and support.en.json also, new files should be named common.vn.json, default.vn.json and support.vn.json.

Let compile and run, we have the result:

 

 

 

For more information about source-code for this part, please have a look at https://github.com/tranthanhtu0vn/TinyERP (in feature/multi_languages).

Other articles in series

 

Thank you for reading,

 

License

This article, along with any associated source code and files, is licensed under The Apache License, Version 2.0