Node.js Integration

Learn how to integrate i18next with Node.js applications for server-side internationalization.

Integrate i18next with your Node.js backend application to support multiple languages using Lengrise-managed translations.

Prerequisites

  • Node.js project
  • Node.js (v16.0.0+)
  • Package manager (npm, yarn, or pnpm)
  • Translations downloaded from Lengrise

Pull Translation Files

First, you must pull your translation files from Lengrise API. These files will contain all the translated text for your backend application.

  1. Go to the Installation Guide and follow the steps to download your translations
  2. Place the downloaded JSON files in your project as shown in the project structure below
  3. Ensure that each language has its own JSON file named with the language code (e.g., en.json, es.json)

Integration Setup

After downloading your translation files, install the necessary packages:

npm install i18next i18next-fs-backend --save

Project Structure

package.jsonadd
server.jsadd
srcadd
i18n.jsadd
routesadd
api.jsadd
middlewareadd
i18n-middleware.jsadd
localesadd
en.jsonadd
es.jsonadd

Configuration Steps

1. Initialize i18next

Create a file called src/i18n.js to set up i18next:

const i18next = require("i18next");
const Backend = require("i18next-fs-backend");
const path = require("path");

// Initialize i18next
const i18n = i18next
  // Use file system backend for Node.js
  .use(Backend)
  // Initialize with configuration
  .init({
    // Default language
    fallbackLng: "en",
    // Supported languages
    supportedLngs: ["en", "es"],
    // Debug mode in development
    debug: process.env.NODE_ENV === "development",

    // Backend configuration for loading translations
    backend: {
      // Path to translation files
      loadPath: path.join(__dirname, "../locales/{{lng}}.json"),
    },

    // Allows keys to be phrases
    keySeparator: false,
    // Don't escape values for HTML
    interpolation: {
      escapeValue: false,
    },
  });

module.exports = i18n;

2. Create an i18n middleware

Create a file called src/middleware/i18n-middleware.js for Express.js applications:

const i18n = require("../i18n");

/**
 * Middleware to handle language detection and i18n setup for requests
 */
module.exports = function i18nMiddleware(req, res, next) {
  // Get language from query parameter, cookie, or accept-language header
  const lng =
    req.query.lng ||
    req.cookies?.i18next ||
    req.headers["accept-language"]?.split(",")[0] ||
    "en";

  // Set language for this request
  req.language = lng;

  // Make i18next instance available on the request object
  req.i18n = i18n;

  // Add translation function to response locals for use in templates
  res.locals.t = (key, options) => i18n.t(key, { lng, ...options });

  // Add current language to response locals
  res.locals.currentLanguage = lng;
  res.locals.availableLanguages = i18n.options.supportedLngs;

  // Continue with the request
  next();
};

3. Set up your server

Update your server.js file to use i18next:

const express = require("express");
const cookieParser = require("cookie-parser");
const path = require("path");
const i18n = require("./src/i18n");
const i18nMiddleware = require("./src/middleware/i18n-middleware");

// Create Express app
const app = express();

// Apply middleware
app.use(cookieParser());
app.use(express.json());
app.use(express.urlencoded({ extended: true }));

// Apply i18n middleware to all routes
app.use(i18nMiddleware);

// Example API route
app.get("/api/greeting", (req, res) => {
  const { name = "Guest" } = req.query;

  // Use translations with the detected language
  const greeting = req.i18n.t("greeting", {
    lng: req.language,
    name,
  });

  res.json({ message: greeting });
});

// Language switcher API endpoint
app.get("/api/language/:lng", (req, res) => {
  const { lng } = req.params;

  // Check if requested language is supported
  if (i18n.options.supportedLngs.includes(lng)) {
    // Set language cookie
    res.cookie("i18next", lng, { maxAge: 365 * 24 * 60 * 60 * 1000 }); // 1 year
    res.json({ language: lng, success: true });
  } else {
    res.status(400).json({
      error: "Language not supported",
      supportedLanguages: i18n.options.supportedLngs,
    });
  }
});

// Start server
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
  console.log(`Server running on port ${PORT}`);
});

Using Translations

In Express Routes

Use translations directly in your route handlers:

// src/routes/api.js
const express = require("express");
const router = express.Router();

// Example route with translations
router.get("/welcome", (req, res) => {
  // Get the user's name from the request
  const { user } = req.query;

  // Translate the welcome message with parameters
  const welcomeMessage = req.i18n.t("welcome.message", {
    lng: req.language,
    user: user || "Guest",
    count: 3,
  });

  // Return the translated message
  res.json({ message: welcomeMessage });
});

// Get all translations for a specific namespace
router.get("/translations", (req, res) => {
  const namespace = req.query.ns || "translation";

  // Get all translations for the current language and namespace
  const translations = req.i18n.getResourceBundle(req.language, namespace);

  res.json(translations);
});

module.exports = router;

With Template Engines

If you're using a template engine like EJS:

// Configure EJS
app.set("view engine", "ejs");
app.set("views", path.join(__dirname, "views"));

// Route that renders a template
app.get("/", (req, res) => {
  res.render("index", {
    title: req.i18n.t("site.title"),
    welcomeMessage: req.i18n.t("welcome.message", { user: "Developer" }),
    // The t function is already available in templates via res.locals.t
  });
});

And in your EJS template (views/index.ejs):

<!DOCTYPE html>
<html lang="<%= currentLanguage %>">
  <head>
    <meta charset="UTF-8" />
    <title><%= title %></title>
  </head>
  <body>
    <h1><%= welcomeMessage %></h1>

    <!-- Using the t function directly in templates -->
    <p><%= t('common.description') %></p>

    <!-- Language switcher -->
    <div>
      <% availableLanguages.forEach(function(language) { %>
      <a
        href="/api/language/<%= language %>"
        class="<%= currentLanguage === language ? 'active' : '' %>"
      >
        <%= language.toUpperCase() %>
      </a>
      <% }); %>
    </div>
  </body>
</html>

Dynamic Language Detection

Handling language changes in your API:

// src/middleware/dynamic-language.js
const i18n = require("../i18n");

/**
 * Middleware that allows language to be changed per-request
 * via the 'Accept-Language' header or 'lang' query parameter
 */
module.exports = function dynamicLanguageMiddleware(req, res, next) {
  // Priority: query parameter > header > cookie > default
  const language =
    req.query.lang ||
    req.headers["accept-language"]?.split(",")[0] ||
    req.cookies?.lang ||
    i18n.options.fallbackLng;

  // Set the specific language for this request's translations
  req.language = language;

  // Add a function that translates with the detected language
  req.t = (key, options) => i18n.t(key, { lng: language, ...options });

  next();
};

Pluralization and Formatting

Your translation files can include pluralization rules and formatting:

locales/en.json:

{
  "items": "{{count}} item",
  "items_plural": "{{count}} items",
  "greeting": "Hello {{name}}!",
  "messages": "You have {{count}} new message",
  "messages_plural": "You have {{count}} new messages",
  "lastLogin": "Last login: {{date, YYYY-MM-DD}}",
  "price": "Price: {{amount, currency}}"
}

locales/es.json:

{
  "items": "{{count}} artículo",
  "items_plural": "{{count}} artículos",
  "greeting": "¡Hola {{name}}!",
  "messages": "Tienes {{count}} mensaje nuevo",
  "messages_plural": "Tienes {{count}} mensajes nuevos",
  "lastLogin": "Último inicio de sesión: {{date, YYYY-MM-DD}}",
  "price": "Precio: {{amount, currency}}"
}

Using pluralization in your code:

// Will output "1 item" or "5 items" depending on the count
const itemText = i18n.t("items", { count: 5 });

// Will output "You have 3 new messages" or "Tienes 3 mensajes nuevos"
const messageText = i18n.t("messages", { count: 3 });

Resources

For more detailed information, check out these resources: