i18next HTTP Middleware
raw JSON →i18next-http-middleware is a versatile, framework-agnostic middleware for integrating i18next into Node.js web applications (Express, Fastify, Hapi) and Deno. Currently at version 3.9.5, it is actively maintained with regular updates, with the last major update to 3.x series being 2 months ago. This package serves as a modern drop-in replacement for the deprecated `i18next-express-middleware`, offering broader compatibility beyond just Express. It facilitates language detection from various request sources (path, cookie, header, querystring, session) and injects the i18next instance directly onto the request object, providing methods like `req.t()`, `req.language`, and `req.languages` for seamless internationalization within server-side handlers and views. Its primary differentiator is its flexibility across different HTTP frameworks and its close integration with the i18next ecosystem for robust server-side internationalization.
Common errors
error TypeError: _this.fallbacks.map is not a function ↓
i18next-http-middleware to version 3.8.2 or newer. As a workaround for affected versions, configure fallbackLng as an array (e.g., fallbackLng: ['en']) instead of an object. error Translations not updating after calling req.i18n.changeLanguage() ↓
preload in your i18next.init() configuration, or ensure your i18next setup includes a backend that can asynchronously load resources for new languages. To persist language changes across requests, you typically need to update a user's language preference in a cookie or session, which the LanguageDetector can then pick up on subsequent requests. error TypeError: Cannot read properties of undefined (reading 't') or (reading 'language') ↓
app.use(handle(i18next, ...)) for Express, app.register(i18nextMiddleware.plugin, ...) for Fastify, or server.register({ plugin: i18nextMiddleware.hapiPlugin, ...}) for Hapi, and that i18next itself is initialized with i18next.use(LanguageDetector).init(...) before applying the middleware to your application's request pipeline. Warnings
breaking Versions of `i18next-http-middleware` prior to 3.9.3 are vulnerable to HTTP response splitting, denial of service (DoS) in Node.js >= 14.6.0, and reflected XSS. This is due to insufficient sanitization of the `Content-Language` header and a weak XSS filter that could be bypassed by certain payloads. ↓
deprecated This package is the recommended replacement for the deprecated `i18next-express-middleware`. While it is designed as a drop-in replacement, it offers enhanced framework-agnostic usage and updated internals. ↓
gotcha Calling `req.i18n.changeLanguage('someCode')` within a request handler will only change the language instance for the current request's context. It will NOT dynamically load new translation resources if they haven't been preloaded or configured to load on demand via an i18next backend. Translations for the newly set language might be missing if not present. ↓
gotcha In `i18next-http-middleware` v3.8.1, configuring `fallbackLng` as an object (e.g., `{ default: ['en'] }`) could lead to a `TypeError` due to incorrect handling of the object structure by the LanguageDetector. This was a regression from previous versions. ↓
Install
npm install i18next-http-middleware yarn add i18next-http-middleware pnpm add i18next-http-middleware Imports
- handle wrong
const handle = require('i18next-http-middleware').handle;correctimport { handle } from 'i18next-http-middleware'; - LanguageDetector wrong
const LanguageDetector = require('i18next-http-middleware').LanguageDetector;correctimport { LanguageDetector } from 'i18next-http-middleware'; - plugin wrong
const plugin = require('i18next-http-middleware').plugin;correctimport { plugin } from 'i18next-http-middleware'; - hapiPlugin wrong
const hapiPlugin = require('i18next-http-middleware').hapiPlugin;correctimport { hapiPlugin } from 'i18next-http-middleware';
Quickstart
import express from 'express';
import i18next from 'i18next';
import { LanguageDetector, handle } from 'i18next-http-middleware';
const app = express();
const PORT = process.env.PORT || 3000;
// Initialize i18next with the language detector and some translations
i18next.use(LanguageDetector).init({
preload: ['en', 'de', 'fr'],
fallbackLng: 'en',
debug: true,
resources: {
en: {
translation: {
welcome: 'Hello world!',
greeting: 'Welcome to our internationalized app!',
howAreYou: 'How are you?'
}
},
de: {
translation: {
welcome: 'Hallo Welt!',
greeting: 'Willkommen in unserer internationalisierten App!',
howAreYou: 'Wie geht es dir?'
}
},
fr: {
translation: {
welcome: 'Bonjour le monde!',
greeting: 'Bienvenue dans notre application internationalisée!',
howAreYou: 'Comment allez-vous?'
}
}
}
});
// Apply the i18next-http-middleware
app.use(handle(i18next, {
ignoreRoutes: ['/health'], // Example: ignore specific routes from i18n processing
removeLngFromUrl: false // Set to true if language is part of the URL path (e.g., /en/home)
}));
// Example route demonstrating i18n usage
app.get('/', (req, res) => {
// Access i18n properties from the request object
const language = req.language || 'en';
const translatedGreeting = req.t('greeting');
const translatedWelcome = req.t('welcome');
res.send(`
<h1>${translatedWelcome}</h1>
<p>${translatedGreeting}</p>
<p>Current language: <strong>${language}</strong></p>
<p>Detected languages: ${req.languages?.join(', ') || 'N/A'}</p>
<p>Try going to <a href="/de">/de</a> or <a href="/fr">/fr</a></p>
`);
});
// Example route for a specific language path segment (if LanguageDetector is configured for path)
app.get('/:lng', (req, res, next) => {
// The middleware would have already set req.language based on the path if configured
// For this example, we just render the root path again with the detected language
if (['en', 'de', 'fr'].includes(req.params.lng)) {
return res.redirect('/');
}
next(); // Pass to next handler if not a language code
});
// Health check route, ignored by i18n middleware
app.get('/health', (req, res) => {
res.send('OK');
});
app.listen(PORT, () => {
console.log(`Server listening on http://localhost:${PORT}`);
console.log('Test with:');
console.log(`- http://localhost:${PORT}/en`);
console.log(`- http://localhost:${PORT}/de`);
console.log(`- http://localhost:${PORT}/fr`);
console.log(`- http://localhost:${PORT}?lng=fr`);
console.log(`- curl -H "Accept-Language: de" http://localhost:${PORT}`);
});