Please enable JavaScript to view the comments powered by Disqus.

i18n Implementation For Node Application

Posted on July 11, 2015, by markocen

About me Blog Project Contacts

Nowadays, more and more websites support two or more languages. More languages supporting simply means more customers your website would. i18n (internationalization) is a solution to localize a web application into different languages and cultures, this is not simple process especially you have a large web application.

However, if you are using nodejs, thanks to many open-source i18n node middleware, you can deploy i18n solution without too much pain. This blog provides a simple demo to show how to build a multi-language website by using node and its i18n module.

A Simple Website with Multi-language Supported

In this demo, we would build a simple website with express and jade. It has two languages supported (English and Chinese). In main page, user can choose the language options, and after choosing, we would like to keep the user option into cookie, therefore, we can use it for the rest of pages. The file structure is:

i18n_demo
    |-- locales /* Used to store language json files*/
    |     |--en.json
    |     |--zh.json
    |-- views
    |     |-- main.jade
    |     |-- contact.jade
    |-- node_modules
    |-- package.json
    |-- server.js 

Modules Dependency

i18n : a light-weight i18n translation module for nodejs. It supports dynamic json storage and different node template engine.
express : a popuplar framework for nodejs. Using a framework is optional, we can just build this demo by plain nodejs.
express-session : we need to use session to store user language option.
cookie-parser : use cookie-parser to edit cookie object in user session.

The completed Package.json file:

{
    "name": "i18n_demo",
    "version": "1.0.0",
    "main": "server.js",
    "author": "Marko Cen",
    "license": "MIT",
    "dependencies": {
    "cookie-parser": "^1.3.5",
    "express": "^4.13.1",
    "express-session": "^1.11.3",
    "i18n": "^0.5.0",
    "jade": "^1.11.0"
  }
}

App Configuration

First, let’s setup our server side code:

  1. we would create a express app and listen on port 8080

    var express = require('express');
        var app = express();
    
        app.listen(8080);
  2. In order to use jade, we need to set app view engine to jade

    app.set('view engine', 'jade');
    
  3. Now, let's mount our session middleware and cookie-parser middleware. Please be aware, they need to use same secret string

    var session = require('express-session');
    var cookieParser = require('cookie-parser');
    
    app.use(cookieParser("i18n_demo"));
    
    app.use(session({
        secret: "i18n_demo",
        resave: true,
        saveUninitialized: true,
        cookie: { maxAge: 60000 }
    }));
  4. Config i18n and mount it to our app. Here, the mounting order between i18n and cookieParser is important, we always want i18n mounted after cookieParser

    var i18n = require('i18n');
    
    i18n.configure({
    
    //define how many languages we would support in our application
    locales:['en', 'zh'],
    
    //define the path to language json files, default is /locales
    directory: __dirname + '/locales',
    
    //define the default language
    defaultLocale: 'en',
    
    // define a custom cookie name to parse locale settings from 
    cookie: 'i18n'
    });
    
    app.use(cookieParser("i18n_demo"));
    
    app.use(session({
        secret: "i18n_demo",
        resave: true,
        saveUninitialized: true,
        cookie: { maxAge: 60000 }
    }));
    
    //init i18n after cookie-parser
    app.use(i18n.init);
  5. Finally, add language json files in locales folder. Since we provide two languages: English and Chinese, we should add two json files:en.json and zh.json

Views

In this application, we only have two views, main.jade and contact.jade, In main.jade, we would allow user to choose their language, and in contact.jade we would show some information in the language user just choose.

//main.jade

    doctype html

    html(lang='en')
        head
            title i18n Demo
            meta(charset="utf-8")
        body

            p #{i18n.__("Welcome")}

            p
                a(href="/contact") Contact Information

            p #{i18n.__("Language")}

            p
                ul
                    li
                        a(href="/zh") Chinese
                    li
                        a(href="/en") English
//contact.jade

    doctype html
        html
            head
                title Contact
                meta(charset="utf-8")
        body
            p #{i18n.__("Contact Information")}

Notice the i18n.__ function, it would load string from different language json files base on the language user choose, and insert it into paragraph tag

Routes

The last step is to setup the routes, we have four routes:

  • / get main page
  • /contact get contact page
  • /en change language to English
  • /ch change language to Chinese
app.get('/', function (req, res) {
    res.setLocale(req.cookies.i18n);
    res.render('main', {
    i18n: res
    })
});

app.get('/contact', function (req, res) {
    res.render('contact', {
    i18n: res
    })
});

app.get('/zh', function (req, res) {
    res.cookie('i18n', 'zh');
    res.redirect('/')
});

app.get('/en', function (req, res) {
    res.cookie('i18n', 'en');
    res.redirect('/')
});

In /zh and /en routes, we use cookie-parser to set i18n field to related language value, then in / route, we use res.setLocale function which provided by i18n middleware to dynamic set the language our site used. When rendering the template, we pass response object as a option data into the template, therefore, we can use res.__ function in our template

JSON Files

Till now, everything is hooked up, and the last but most important thing is editing our json file:

//en.json

{
    "Welcome": "Hi, welcome to our site",
    "Language": "Please choose your language",
    "Contact Information" : "1 Elf rd, Unicorn Village, Wonderland, Earth"
}
//zh.json

{
    "Welcome": "欢迎",
    "Language": "请选择语言",
    "Contact Information" : "一号 精灵路, 独角兽村, 幸福国, 地球"
}

both files should have same fields, and only the field values are different