i18next HTTP Middleware

raw JSON →
3.9.5 verified Thu Apr 23 auth: no javascript

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.

error TypeError: _this.fallbacks.map is not a function
cause This error typically occurs in `i18next-http-middleware` version 3.8.1 when `fallbackLng` is configured as an object in your i18next initialization options, which the `LanguageDetector` did not correctly process.
fix
Upgrade 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()
cause The `changeLanguage` call on the request-scoped i18n instance does not trigger loading of new resources by default; it only sets the active language for that request if resources are already available locally (e.g., preloaded).
fix
Verify that the language you are switching to is included in 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')
cause This usually indicates that the `i18next-http-middleware` has not been properly initialized or applied to your Express/Fastify/Hapi app *before* your route handlers attempt to access `req.i18n` or related properties.
fix
Ensure you have called 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.
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.
fix Upgrade to `i18next-http-middleware` version 3.9.3 or higher immediately. This version introduces robust sanitization of control characters and a strengthened XSS regex to mitigate these vulnerabilities.
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.
fix Migrate from `i18next-express-middleware` to `i18next-http-middleware`. Ensure you update your imports and middleware registration according to the new package's documentation, taking advantage of its broader framework support.
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.
fix Ensure all necessary languages are either `preload`ed in your `i18next.init()` configuration or that you have an i18next backend (e.g., `i18next-fs-backend`, `i18next-http-backend`) properly configured to fetch missing translations. To persist language changes across requests, you typically need to update a cookie or session via client-side or server-side logic outside of `req.i18n.changeLanguage()`.
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.
fix If experiencing this issue, upgrade to `i18next-http-middleware` version 3.8.2 or later, which includes a fix for this bug. Alternatively, configure `fallbackLng` as a simple array (e.g., `['en']`) to avoid the error in affected versions.
npm install i18next-http-middleware
yarn add i18next-http-middleware
pnpm add i18next-http-middleware

This example sets up `i18next-http-middleware` with an Express server, initializing i18next with multiple languages and preloaded resources. It demonstrates applying the middleware globally, accessing translation functions (`req.t`) and language properties (`req.language`, `req.languages`) from the request object, and handles basic routing for language switching based on URL path or query parameters. It also includes an ignored health check route.

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}`);
});