i18n Module for Node and Express.js

As a follow-up to my post from last week on a strategy for i18n and Node.js I’ve published my module for handling internationalization in Node and, specifically, Express.js.

The module is now available on NPM and can be installed by running:

npm install i18n-2

The code and documentation for the module is available on Github here:

https://github.com/jeresig/i18n-node-2

I’ve designed the API to work as simply as possible with Express.js – while still supporting a simple Node.js usage or usage with another web framework.

The module includes a number of features built-in:

  • Automatic integration with Express as middleware and integration with templating solutions.
  • Support for handling the setting of locale based upon query strings and/or subdomain.
  • Dynamic reading and updating of translation files during development mode.
  • Automatic caching of translation files in production mode.

Usage is simple, in your Express app.js:

// load modules
var express = require('express'),
	I18n = require('i18n-2');

// Express Configuration
app.configure(function() {
	// ...

	// Attach the i18n property to the express request object
	// And attach helper methods for use in templates
	I18n.expressBind(app, {
		// setup some locales - other locales default to en silently
		locales: ['en', 'de']
	}));

	// Set up the rest of the Express middleware
	app.use(app.router);
	app.use(express.static(__dirname + '/public'));
});

Inside your Express view:

module.exports = {
	index: function(req, res) {
		req.render("index", {
			title: req.i18n.__("My Site Title"),
			desc: req.i18n.__("My Site Description")
		});
	}
};

Inside your templates (this example uses the Swig templating system).

{% extends "page.swig" %}
{% block content %}
<h1>{{ __("Welcome to: %s", title) }}</h1>
<p>{{ desc }}</p>
{% endblock %}

My module is based off of the i18n-node module by Marcus Spiegel.

I used the original i18n-node module as a basis for further work as it provided the closest solution to full Express.js integration that I needed. After some initial usage though I saw that it was very much lacking. As I described in my previous post there is potential for severe problems to occur in an asynchronous environment like Node.js.

The problem that I was having was rather severe and, unfortunately, required a complete rewrite of the module. The original i18n-node module stored the locale information in a closure. Calling setLocale changed the locale but did so for every instance that was currently active, resulting in templates being rendered in the wrong language.

Here is the issue that is especially surprising (but not so much once you know how modules work in Node.js): Since the state was stored in a closure repeated calls to require('i18n') resulted in the current locale state being held the entire time, not reset. This meant that when a new request came in, the locale was set, changing the locale for all other active requests.

The only way to fix this particular problem is to simply encapsulate all state into a single object — I did this by making an object that you instantiate: new I18n(options).

I looked at other JavaScript translation solutions, including the excellent Jed and messageformat and while their translation capabilities are top-notch what they provided was overkill for my particular application and did not provide the Express.js integration that I needed.

I hope others will find this module to be useful, especially when used in conjunction with my strategy for i18n and Node.js.

Posted: January 15th, 2013


Subscribe for email updates

4 Comments (Show Comments)



Comments are closed.
Comments are automatically turned off two weeks after the original post. If you have a question concerning the content of this post, please feel free to contact me.


Secrets of the JavaScript Ninja

Secrets of the JS Ninja

Secret techniques of top JavaScript programmers. Published by Manning.

John Resig Twitter Updates

@jeresig / Mastodon

Infrequent, short, updates and links.