Express.js i18n Middleware
raw JSON →i18n-express is a lightweight internationalization middleware designed for Express.js applications, currently at version 1.1.3. It facilitates basic language switching and content localization by reading language-specific JSON files from a designated directory. The middleware determines the user's preferred language based on a hierarchy: a configured cookie, a URL query parameter, browser `Accept-Language` headers, or a default language. Once determined, it exposes a `textsVarName` (default: `texts`) variable to your view engine (e.g., EJS, Handlebars) containing the translated strings for the active language, along with a `lang` variable indicating the current language. Its primary differentiator is its extreme simplicity and file-based approach, avoiding complex CLDR data or advanced pluralization rules, making it suitable for very straightforward localization needs. The package has not seen updates in approximately seven years, suggesting it is no longer actively maintained and new releases are highly unlikely.
Common errors
error TypeError: i18n is not a function ↓
i18n with an options object: app.use(i18n({ /* options */ })); error Cannot read properties of undefined (reading 'WELCOME_MSG') ↓
translationsPath points to the correct directory containing valid .json language files (e.g., en.json, es.json) and that the textsVarName in your view matches the configuration. error ReferenceError: session is not defined ↓
const session = require('express-session'); and configure app.use(session(...)); before using i18n-express. error Language is not changing despite setting query param or cookie. ↓
app.use(cookieParser()); (and app.use(session(...)); if used) are placed *before* app.use(i18n(...)); in your Express application configuration. Warnings
breaking The package is effectively abandoned, with no updates in approximately seven years. This means there will be no fixes for bugs, security vulnerabilities, or compatibility issues with newer Node.js or Express versions. ↓
gotcha Requires `cookie-parser` and `express-session` middleware to be configured and used *before* i18n-express in the Express middleware chain for cookie and session-based language persistence features to work correctly. ↓
gotcha The package is a CommonJS module. While Node.js can often import CJS modules into ESM projects, direct `import { i18n } from 'i18n-express'` or complex ESM setups might lead to issues. ↓
gotcha Language detection follows a specific priority: `cookieLangName` (if set) > `paramLangName` (from URL query) > browser `Accept-Language` header > `defaultLang`. Misunderstanding this order can lead to unexpected language display. ↓
gotcha This library offers very basic internationalization. It lacks features such as pluralization rules, complex locale-aware formatting (dates, currencies), or integration with CLDR data, which are common in more robust i18n libraries. ↓
Install
npm install i18n-express yarn add i18n-express pnpm add i18n-express Imports
- i18n wrong
import { i18n } from 'i18n-express';correctimport i18n from 'i18n-express'; - i18n (CommonJS)
const i18n = require('i18n-express'); - Middleware Usage wrong
app.use(i18n);correctapp.use(i18n({ translationsPath: path.join(__dirname, 'i18n'), siteLangs: ['en', 'es'] }));
Quickstart
const express = require('express');
const path = require('path');
const cookieParser = require('cookie-parser');
const session = require('express-session'); // Required for session-based language persistence
const i18n = require('i18n-express');
const app = express();
// Create a dummy translations directory and files
const translationsPath = path.join(__dirname, 'i18n-translations');
const fs = require('fs');
if (!fs.existsSync(translationsPath)) fs.mkdirSync(translationsPath);
fs.writeFileSync(path.join(translationsPath, 'en.json'), JSON.stringify({ "WELCOME_MSG": "Hi! Welcome!" }));
fs.writeFileSync(path.join(translationsPath, 'es.json'), JSON.stringify({ "WELCOME_MSG": "¡Hola! ¡Bienvenido!" }));
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');
app.use(cookieParser());
app.use(session({
secret: process.env.SESSION_SECRET ?? 'supersecretkey',
resave: false,
saveUninitialized: true,
cookie: { maxAge: 60000 }
}));
app.use(i18n({
translationsPath: translationsPath, // Path to your JSON translation files
siteLangs: ["en", "es"],
textsVarName: 'translation', // Variable name in views
cookieLangName: 'ulang' // Cookie name for language persistence
}));
app.get('/', (req, res) => {
res.render('index', {
lang: res.locals.lang,
translation: res.locals.translation
});
});
// Dummy EJS view file (views/index.ejs)
// Create 'views' directory and 'index.ejs' with this content:
/*
<div>
<h1><%= translation.WELCOME_MSG %></h1>
<p>Current Language: <%= lang %></p>
<p>
<a href="/?clang=en">English</a> |
<a href="/?clang=es">Español</a>
</p>
</div>
*/
const PORT = 3000;
app.listen(PORT, () => {
console.log(`Server running on http://localhost:${PORT}`);
console.log(`Try http://localhost:${PORT}/?clang=es to switch language`);
});