Skip to content

ExpressJS - Internationalization(i18n)

Express.js - Modern Internationalization (i18n)

Section titled “Express.js - Modern Internationalization (i18n)”

Internationalization, often abbreviated as i18n, is the process of designing a software application so that it can be adapted to various languages and regions without engineering changes. This tutorial demonstrates how to implement i18n in a modern Express.js application.

We will use a robust and popular set of libraries to handle translations:

  • i18next: The core i18n framework, providing the main translation functionality.
  • i18next-http-middleware: A modern middleware to detect the user’s language and integrate i18n capabilities into Express requests and responses.
  • i18next-fs-backend: A backend module for i18next that loads translation resources from the local file system.

First, initialize a new Node.js project and install Express and the required i18n modules.

# 1. Create a new project directory
mkdir express-i18n-example && cd express-i18n-example
# 2. Initialize a Node.js project
npm init -y
# 3. Install dependencies
npm install express i18next i18next-http-middleware i18next-fs-backend

Organize your translation files in a structured way. A common practice is to have a locales directory with subdirectories for each language.

.
├── locales/
│ ├── en/
│ │ └── translation.json
│ └── fr/
│ └── translation.json
├── node_modules/
├── index.js
└── package.json
{
"welcome": "Welcome to our modern Express application!",
"greeting": "Hello, {{name}}! We are glad to have you here."
}
{
"welcome": "Bienvenue dans notre application Express moderne !",
"greeting": "Bonjour, {{name}} ! Nous sommes ravis de vous avoir ici."
}

Now, let’s configure i18next and apply its middleware in our main application file, index.js.

// index.js
import express from 'express';
import i18next from 'i18next';
import Backend from 'i18next-fs-backend';
import middleware from 'i18next-http-middleware';
// Initialize i18next
i18next
.use(Backend) // Loads translations from the file system
.use(middleware.LanguageDetector) // Detects user language from request
.init({
fallbackLng: 'en',
backend: {
loadPath: './locales/{{lng}}/translation.json',
},
detection: {
order: ['querystring', 'cookie', 'header'],
caches: ['cookie'],
lookupQuerystring: 'lang', // e.g., /?lang=fr
lookupCookie: 'i18next',
},
// It's recommended to escape values to prevent XSS attacks
// if not using a frontend library that already does it.
interpolation: {
escapeValue: true
}
});
const app = express();
const PORT = process.env.PORT || 3000;
// Apply the i18next middleware
app.use(middleware.handle(i18next));
// --- Routes ---
app.get('/', (req, res) => {
// The t function is added to the req object by the middleware
res.status(200).send(req.t('welcome'));
});
app.get('/greet/:name', (req, res) => {
const { name } = req.params;
res.status(200).send(req.t('greeting', { name }));
});
// Basic error handling
app.use((err, req, res, next) => {
console.error(err.stack);
res.status(500).send('Something broke!');
});
app.listen(PORT, () => {
console.log(`Server is running on http://localhost:${PORT}`);
});
  • import syntax: We use modern ES6 module syntax. To enable this, add "type": "module" to your package.json file.
  • .use(Backend): Configures i18next-fs-backend to read translation JSON files.
  • .use(middleware.LanguageDetector): This powerful detector automatically finds the user’s preferred language by checking (in order) a query string parameter (?lang=fr), a cookie, and the Accept-Language HTTP header.
  • fallbackLng: 'en': If a translation key is not found in the detected language, it will fall back to English.
  • app.use(middleware.handle(i18next)): This is the crucial step that integrates i18next into the Express request-response cycle, making the req.t() function available in all subsequent routes.

Run your server with node index.js. You can now test the different language outputs.

  • Default (English): Open your browser or use curl: curl http://localhost:3000/
  • French via Query String: curl "http://localhost:3000/?lang=fr"
  • Greeting in English: curl http://localhost:3000/greet/Alex
  • Greeting in French: curl "http://localhost:3000/greet/Alex?lang=fr"
  • Translations Not Loading: Double-check the loadPath in your i18next.init() configuration. Ensure it correctly points to your locales directory relative to where you run the node process.
  • req.t is not a function: This error means the i18next-http-middleware is not correctly configured or is placed after your routes. Ensure app.use(middleware.handle(i18next)); comes before you define any routes.
  • ESM import Syntax Error: If you see an error like SyntaxError: Cannot use import statement outside a module, make sure you have added "type": "module" to your package.json file.