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:
we would create a express app and listen on port 8080
var express = require('express'); var app = express(); app.listen(8080);
In order to use jade, we need to set app view engine to jade
app.set('view engine', 'jade');
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 } }));
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);
Finally, add language json files in locales folder. Since we provide two languages: English and Chinese, we should add two json files:
en.json
andzh.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