Profile
Back to NewsBack
GitHub Trending 9 min
Reader Mode
i18next/i18next-http-middleware: i18next-http-middleware is a middleware to be used with Node.js web frameworks like express or Fastify and also for Deno.

i18next/i18next-http-middleware: i18next-http-middleware is a middleware to be used with Node.js web frameworks like express or Fastify and also for Deno.

9 hours ago

Introduction

Actions</a> Actions deno</a> npm version</a>

This is a middleware to be used with Node.js web frameworks like express or Fastify and also for Deno.

It's based on the deprecated i18next-express-middleware and can be used as a drop-in replacement. _It's not bound to a specific http framework anymore._

Advice:

To get started with server side internationalization, you may also have a look at this blog post also using using i18next-http-middleware.

Getting started

# npm package
$ npm install i18next-http-middleware

wire up i18next to request object

var i18next = require('i18next')
var middleware = require('i18next-http-middleware')
var express = require('express')

i18next.use(middleware.LanguageDetector).init({ preload: ['en', 'de', 'it'], ...otherOptions })

var app = express() app.use( middleware.handle(i18next, { ignoreRoutes: ['/foo'], // or function(req, res, options, i18next) { / return true to ignore / } removeLngFromUrl: false // removes the language from the url when language detected in path }) )

// in your request handler app.get('myRoute', (req, res) => { var resolvedLng = req.resolvedLanguage // 'de-CH' var lng = req.language // 'de-CH' var lngs = req.languages // ['de-CH', 'de', 'en'] req.i18n.changeLanguage('en') // will not load that!!! assert it was preloaded

var exists = req.i18n.exists('myKey') var translation = req.t('myKey') })

// in your views, eg. in pug (ex. jade) div = t('myKey')

Fastify usage

var i18next = require('i18next')
var middleware = require('i18next-http-middleware')
var fastify = require('fastify')

i18next.use(middleware.LanguageDetector).init({ preload: ['en', 'de', 'it'], ...otherOptions })

var app = fastify() app.register(i18nextMiddleware.plugin, { i18next, ignoreRoutes: ['/foo'] // or function(req, res, options, i18next) { / return true to ignore / } }) // or // app.addHook('preHandler', i18nextMiddleware.handle(i18next, { // ignoreRoutes: ['/foo'] // or function(req, res, options, i18next) { / return true to ignore / } // }))

// in your request handler app.get('myRoute', (request, reply) => { var lng = request.language // 'de-CH' var lngs = v.languages // ['de-CH', 'de', 'en'] request.i18n.changeLanguage('en') // will not load that!!! assert it was preloaded

var exists = request.i18n.exists('myKey') var translation = request.t('myKey') })

Hapi usage

const i18next = require('i18next')
const middleware = require('i18next-http-middleware')
const Hapi = require('@hapi/hapi')

i18next.use(middleware.LanguageDetector).init({ preload: ['en', 'de', 'it'], ...otherOptions })

const server = Hapi.server({ port: port, host: '0.0.0.0',

await server.register({ plugin: i18nextMiddleware.hapiPlugin, options: { i18next, ignoreRoutes: ['/foo'] // or function(req, res, options, i18next) { /* return true to ignore } })

// in your request handler server.route({ method: 'GET', path: '/myRoute', handler: (request, h) => { var resolvedLng = request.resolvedLanguage // 'de-CH' var lng = request.language // 'de-CH' var lngs = v.languages // ['de-CH', 'de', 'en'] request.i18n.changeLanguage('en') // will not load that!!! assert it was preloaded

var exists = request.i18n.exists('myKey') var translation = request.t('myKey') } })

Koa usage

var i18next = require('i18next')
var middleware = require('i18next-http-middleware')
const Koa = require('koa')
const router = require('@koa/router')()

i18next.use(middleware.LanguageDetector).init({ preload: ['en', 'de', 'it'], ...otherOptions })

var app = new Koa() app.use(i18nextMiddleware.koaPlugin(i18next, { ignoreRoutes: ['/foo'] // or function(req, res, options, i18next) { / return true to ignore / } }))

// in your request handler router.get('/myRoute', ctx => { ctx.body = JSON.stringify({ 'ctx.resolvedLanguage': ctx.resolvedLanguage, 'ctx.language': ctx.language, 'ctx.i18n.resolvedLanguage': ctx.i18n.resolvedLanguage, 'ctx.i18n.language': ctx.i18n.language, 'ctx.i18n.languages': ctx.i18n.languages, 'ctx.i18n.languages[0]': ctx.i18n.languages[0], 'ctx.t("home.title")': ctx.t('home.title') }, null, 2) })

Deno usage

abc

import i18next from 'https://deno.land/x/i18next/index.js'
import Backend from 'https://cdn.jsdelivr.net/gh/i18next/i18next-fs-backend/index.js'
import i18nextMiddleware from 'https://deno.land/x/i18next_http_middleware/index.js'
import { Application } from 'https://deno.land/x/abc/mod.ts'
import { config } from 'https://deno.land/x/dotenv/dotenv.ts'

i18next .use(Backend) .use(i18nextMiddleware.LanguageDetector) .init({ // debug: true, backend: { // eslint-disable-next-line no-path-concat loadPath: 'locales/{{lng}}/{{ns}}.json', // eslint-disable-next-line no-path-concat addPath: 'locales/{{lng}}/{{ns}}.missing.json' }, fallbackLng: 'en', preload: ['en', 'de'] })

const port = config.PORT || 8080 const app = new Application() const handle = i18nextMiddleware.handle(i18next) app.use((next) => (c) => { handle(c.request, c.response, () => {}) return next(c) }) app.get('/', (c) => c.request.t('home.title')) await app.start({ port })

ServestJS

import i18next from 'https://deno.land/x/i18next/index.js'
import Backend from 'https://cdn.jsdelivr.net/gh/i18next/i18next-fs-backend/index.js'
import i18nextMiddleware from 'https://deno.land/x/i18next_http_middleware/index.js'
import { createApp } from 'https://servestjs.org/@v1.0.0-rc2/mod.ts'
import { config } from 'https://deno.land/x/dotenv/dotenv.ts'

i18next .use(Backend) .use(i18nextMiddleware.LanguageDetector) .init({ // debug: true, backend: { // eslint-disable-next-line no-path-concat loadPath: 'locales/{{lng}}/{{ns}}.json', // eslint-disable-next-line no-path-concat addPath: 'locales/{{lng}}/{{ns}}.missing.json' }, fallbackLng: 'en', preload: ['en', 'de'] })

const port = config.PORT || 8080 const app = createApp() app.use(i18nextMiddleware.handle(i18next)) app.get('/', async (req) => { await req.respond({ status: 200, headers: new Headers({ 'content-type': 'text/plain' }), body: req.t('home.title') }) }) await app.listen({ port })

Fresh 2.x

import i18next from 'https://deno.land/x/i18next/index.js'
import i18nextMiddleware from 'https://deno.land/x/i18next_http_middleware/index.js'
import { App, createDefine } from "jsr:@fresh/core";

i18next .use(i18nextMiddleware.LanguageDetector) .init({ preload: ["en", "fr"], fallbackLng: "en", resources: { en: { translation: { hi: "hello" } }, fr: { translation: { hi: "bonjour" } } } });

const app = new App() .use(i18nextMiddleware.freshPlugin(i18next)) .get("/", (ctx) => { return new Response(ctx.state.t('hi')) });

add routes

// missing keys make sure the body is parsed (i.e. with body-parser)
app.post('/locales/add/:lng/:ns', middleware.missingKeyHandler(i18next))
// addPath for client: http://localhost:8080/locales/add/{{lng}}/{{ns}}

// multiload backend route app.get('/locales/resources.json', middleware.getResourcesHandler(i18next)) // can be used like: // GET /locales/resources.json // GET /locales/resources.json?lng=en // GET /locales/resources.json?lng=en&ns=translation

// serve translations: app.use('/locales', express.static('locales')) // GET /locales/en/translation.json // loadPath for client: http://localhost:8080/locales/{{lng}}/{{ns}}.json

// or instead of static app.get('/locales/:lng/:ns', middleware.getResourcesHandler(i18next)) // GET /locales/en/translation // loadPath for client: http://localhost:8080/locales/{{lng}}/{{ns}}

app.get('/locales/:lng/:ns', middleware.getResourcesHandler(i18next, { maxAge: 60 60 24 * 30, // adds appropriate cache header if cache option is passed or NODE_ENV === 'production', defaults to 30 days cache: true // defaults to false }))

add localized routes

You can add your routes directly to the express app

var express = require('express'),
  app = express(),
  i18next = require('i18next'),
  FilesystemBackend = require('i18next-fs-backend'),
  i18nextMiddleware = require('i18next-http-middleware'),
  port = 3000

i18next .use(i18nextMiddleware.LanguageDetector) .use(FilesystemBackend) .init({ preload: ['en', 'de', 'it'], ...otherOptions }, () => { i18nextMiddleware.addRoute( i18next, '/:lng/key-to-translate', ['en', 'de', 'it'], app, 'get', (req, res) => { //endpoint function } ) }) app.use(i18nextMiddleware.handle(i18next)) app.listen(port, () => { console.log('Server listening on port', port) })

or to an express router

var express = require('express'),
  app = express(),
  i18next = require('i18next'),
  FilesystemBackend = require('i18next-fs-backend'),
  i18nextMiddleware = require('i18next-http-middleware'),
  router = require('express').Router(),
  port = 3000

i18next .use(i18nextMiddleware.LanguageDetector) .use(FilesystemBackend) .init({ preload: ['en', 'de', 'it'], ...otherOptions }, () => { i18nextMiddleware.addRoute( i18next, '/:lng/key-to-translate', ['en', 'de', 'it'], router, 'get', (req, res) => { //endpoint function } ) app.use('/', router) }) app.use(i18nextMiddleware.handle(i18next)) app.listen(port, () => { console.log('Server listening on port', port) })

custom http server

Define your own functions to handle your custom request or response

middleware.handle(i18next, {
  getPath: (req) => req.path,
  getUrl: (req) => req.url,
  setUrl: (req, url) => (req.url = url),
  getQuery: (req) => req.query,
  getParams: (req) => req.params,
  getBody: (req) => req.body,
  setHeader: (res, name, value) => res.setHeader(name, value),
  setContentType: (res, type) => res.contentType(type),
  setStatus: (res, code) => res.status(code),
  send: (res, body) => res.send(body)
})

language detection

Detects user language from current request. Comes with support for:

  • path
  • cookie
  • header
  • querystring
  • session
Based on the i18next language detection handling: https://www.i18next.com/misc/creating-own-plugins#languagedetector

Wiring up:

var i18next = require('i18next')
var middleware = require('i18next-http-middleware')

i18next.use(middleware.LanguageDetector).init(i18nextOptions)

As with all modules you can either pass the constructor function (class) to the i18next.use or a concrete instance.

Detector Options

{
  // order and from where user language should be detected
  order: [/'path', 'session', / 'querystring', 'cookie', 'header'],

// keys or params to lookup language from lookupQuerystring: 'lng', lookupCookie: 'i18next', lookupHeader: 'accept-language', lookupHeaderRegex: /(([a-z]{2})-?([A-Z]{2})?)\s;?\s(q=([0-9.]+))?/gi, lookupSession: 'lng', lookupPath: 'lng', lookupFromPathIndex: 0,

// cache user language, you can define if an how the detected language should be "saved" => 'cookie' and/or 'session' caches: false, // ['cookie']

ignoreCase: true, // ignore case of detected language

// optional expire and domain for set cookie cookieExpirationDate: new Date(), cookieDomain: 'myDomain', cookiePath: '/my/path', cookieSecure: true, // if need secure cookie cookieSameSite: 'strict', // 'strict', 'lax' or 'none' cookieHttpOnly: true // prevent client-side script access to the cookie

// optional conversion function used to modify the detected language code convertDetectedLanguage: 'Iso15897', convertDetectedLanguage: (lng) => lng.replace('-', '_') }

Options can be passed in:

preferred - by setting options.detection in i18next.init:

var i18next = require('i18next')
var middleware = require('i18next-http-middleware')

i18next.use(middleware.LanguageDetector).init({ detection: options })

on construction:

var middleware = require('i18next-http-middleware')
var lngDetector = new middleware.LanguageDetector(null, options)

via calling init:

var middleware = require('i18next-http-middleware')

var lngDetector = new middleware.LanguageDetector() lngDetector.init(options)

Adding own detection functionality

interface

module.exports = {
  name: 'myDetectorsName',

lookup: function (req, res, options) { // options -> are passed in options return 'en' },

cacheUserLanguage: function (req, res, lng, options) { // options -> are passed in options // lng -> current language, will be called after init and on changeLanguage // store it } }

adding it

var i18next = require('i18next')
var middleware = require('i18next-http-middleware')

var lngDetector = new middleware.LanguageDetector() lngDetector.addDetector(myDetector)

i18next.use(lngDetector).init({ detection: options })

Don't forget: You have to add the name of your detector (myDetectorsName in this case) to the order array in your options object. Without that, your detector won't be used. See the Detector Options section for more.


Gold Sponsors

Chat with me