Installations
npm install @sandhose/i18next-http-middleware
Score
72.6
Supply Chain
99
Quality
75
Maintenance
100
Vulnerability
100
License
Releases
Unable to fetch releases
Contributors
Developer
i18next
Module System
ESM
Statistics
153 Stars
181 Commits
28 Forks
6 Watching
1 Branches
18 Contributors
Updated on 22 Nov 2024
Languages
JavaScript (97.55%)
TypeScript (1.31%)
Pug (0.68%)
HTML (0.46%)
Total Downloads
Cumulative downloads
Total Downloads
1,139
Last day
0%
2
Compared to previous day
Last week
25%
5
Compared to previous week
Last month
-48.6%
19
Compared to previous month
Last year
225.7%
596
Compared to previous year
Daily Downloads
Weekly Downloads
Monthly Downloads
Yearly Downloads
Dev Dependencies
20
Introduction
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
1# npm package 2$ npm install i18next-http-middleware
wire up i18next to request object
1var i18next = require('i18next') 2var middleware = require('i18next-http-middleware') 3var express = require('express') 4 5i18next.use(middleware.LanguageDetector).init({ 6 preload: ['en', 'de', 'it'], 7 ...otherOptions 8}) 9 10var app = express() 11app.use( 12 middleware.handle(i18next, { 13 ignoreRoutes: ['/foo'], // or function(req, res, options, i18next) { /* return true to ignore */ } 14 removeLngFromUrl: false // removes the language from the url when language detected in path 15 }) 16) 17 18// in your request handler 19app.get('myRoute', (req, res) => { 20 var lng = req.language // 'de-CH' 21 var lngs = req.languages // ['de-CH', 'de', 'en'] 22 req.i18n.changeLanguage('en') // will not load that!!! assert it was preloaded 23 24 var exists = req.i18n.exists('myKey') 25 var translation = req.t('myKey') 26}) 27 28// in your views, eg. in pug (ex. jade) 29div = t('myKey')
Fastify usage
1var i18next = require('i18next') 2var middleware = require('i18next-http-middleware') 3var fastify = require('fastify') 4 5i18next.use(middleware.LanguageDetector).init({ 6 preload: ['en', 'de', 'it'], 7 ...otherOptions 8}) 9 10var app = fastify() 11app.register(i18nextMiddleware.plugin, { 12 i18next, 13 ignoreRoutes: ['/foo'] // or function(req, res, options, i18next) { /* return true to ignore */ } 14}) 15// or 16// app.addHook('preHandler', i18nextMiddleware.handle(i18next, { 17// ignoreRoutes: ['/foo'] // or function(req, res, options, i18next) { /* return true to ignore */ } 18// })) 19 20// in your request handler 21app.get('myRoute', (request, reply) => { 22 var lng = request.language // 'de-CH' 23 var lngs = v.languages // ['de-CH', 'de', 'en'] 24 request.i18n.changeLanguage('en') // will not load that!!! assert it was preloaded 25 26 var exists = request.i18n.exists('myKey') 27 var translation = request.t('myKey') 28})
Hapi usage
1const i18next = require('i18next') 2const middleware = require('i18next-http-middleware') 3const Hapi = require('@hapi/hapi') 4 5i18next.use(middleware.LanguageDetector).init({ 6 preload: ['en', 'de', 'it'], 7 ...otherOptions 8}) 9 10const server = Hapi.server({ 11 port: port, 12 host: '0.0.0.0', 13 14await server.register({ 15 plugin: i18nextMiddleware.hapiPlugin, 16 options: { 17 i18next, 18 ignoreRoutes: ['/foo'] // or function(req, res, options, i18next) { /* return true to ignore 19 } 20}) 21 22// in your request handler 23server.route({ 24 method: 'GET', 25 path: '/myRoute', 26 handler: (request, h) => { 27 var lng = request.language // 'de-CH' 28 var lngs = v.languages // ['de-CH', 'de', 'en'] 29 request.i18n.changeLanguage('en') // will not load that!!! assert it was preloaded 30 31 var exists = request.i18n.exists('myKey') 32 var translation = request.t('myKey') 33 } 34}) 35
Koa usage
1var i18next = require('i18next') 2var middleware = require('i18next-http-middleware') 3const Koa = require('koa') 4const router = require('@koa/router')() 5 6i18next.use(middleware.LanguageDetector).init({ 7 preload: ['en', 'de', 'it'], 8 ...otherOptions 9}) 10 11var app = new Koa() 12app.use(i18nextMiddleware.koaPlugin(i18next, { 13 ignoreRoutes: ['/foo'] // or function(req, res, options, i18next) { /* return true to ignore */ } 14})) 15 16// in your request handler 17router.get('/myRoute', ctx => { 18 ctx.body = JSON.stringify({ 19 'ctx.language': ctx.language, 20 'ctx.i18n.language': ctx.i18n.language, 21 'ctx.i18n.languages': ctx.i18n.languages, 22 'ctx.i18n.languages[0]': ctx.i18n.languages[0], 23 'ctx.t("home.title")': ctx.t('home.title') 24 }, null, 2) 25})
Deno usage
abc
1import i18next from 'https://deno.land/x/i18next/index.js' 2import Backend from 'https://cdn.jsdelivr.net/gh/i18next/i18next-fs-backend/index.js' 3import i18nextMiddleware from 'https://deno.land/x/i18next_http_middleware/index.js' 4import { Application } from 'https://deno.land/x/abc/mod.ts' 5import { config } from 'https://deno.land/x/dotenv/dotenv.ts' 6 7i18next 8 .use(Backend) 9 .use(i18nextMiddleware.LanguageDetector) 10 .init({ 11 // debug: true, 12 backend: { 13 // eslint-disable-next-line no-path-concat 14 loadPath: 'locales/{{lng}}/{{ns}}.json', 15 // eslint-disable-next-line no-path-concat 16 addPath: 'locales/{{lng}}/{{ns}}.missing.json' 17 }, 18 fallbackLng: 'en', 19 preload: ['en', 'de'] 20 }) 21 22const port = config.PORT || 8080 23const app = new Application() 24const handle = i18nextMiddleware.handle(i18next) 25app.use((next) => (c) => { 26 handle(c.request, c.response, () => {}) 27 return next(c) 28}) 29app.get('/', (c) => c.request.t('home.title')) 30await app.start({ port })
ServestJS
1import i18next from 'https://deno.land/x/i18next/index.js' 2import Backend from 'https://cdn.jsdelivr.net/gh/i18next/i18next-fs-backend/index.js' 3import i18nextMiddleware from 'https://deno.land/x/i18next_http_middleware/index.js' 4import { createApp } from 'https://servestjs.org/@v1.0.0-rc2/mod.ts' 5import { config } from 'https://deno.land/x/dotenv/dotenv.ts' 6 7i18next 8 .use(Backend) 9 .use(i18nextMiddleware.LanguageDetector) 10 .init({ 11 // debug: true, 12 backend: { 13 // eslint-disable-next-line no-path-concat 14 loadPath: 'locales/{{lng}}/{{ns}}.json', 15 // eslint-disable-next-line no-path-concat 16 addPath: 'locales/{{lng}}/{{ns}}.missing.json' 17 }, 18 fallbackLng: 'en', 19 preload: ['en', 'de'] 20 }) 21 22const port = config.PORT || 8080 23const app = createApp() 24app.use(i18nextMiddleware.handle(i18next)) 25app.get('/', async (req) => { 26 await req.respond({ 27 status: 200, 28 headers: new Headers({ 29 'content-type': 'text/plain' 30 }), 31 body: req.t('home.title') 32 }) 33}) 34await app.listen({ port })
add routes
1// missing keys make sure the body is parsed (i.e. with [body-parser](https://github.com/expressjs/body-parser#bodyparserjsonoptions)) 2app.post('/locales/add/:lng/:ns', middleware.missingKeyHandler(i18next)) 3// addPath for client: http://localhost:8080/locales/add/{{lng}}/{{ns}} 4 5// multiload backend route 6app.get('/locales/resources.json', middleware.getResourcesHandler(i18next)) 7// can be used like: 8// GET /locales/resources.json 9// GET /locales/resources.json?lng=en 10// GET /locales/resources.json?lng=en&ns=translation 11 12// serve translations: 13app.use('/locales', express.static('locales')) 14// GET /locales/en/translation.json 15// loadPath for client: http://localhost:8080/locales/{{lng}}/{{ns}}.json 16 17// or instead of static 18app.get('/locales/:lng/:ns', middleware.getResourcesHandler(i18next)) 19// GET /locales/en/translation 20// loadPath for client: http://localhost:8080/locales/{{lng}}/{{ns}} 21 22app.get('/locales/:lng/:ns', middleware.getResourcesHandler(i18next, { 23 maxAge: 60 * 60 * 24 * 30, // adds appropriate cache header if cache option is passed or NODE_ENV === 'production', defaults to 30 days 24 cache: true // defaults to false 25}))
add localized routes
You can add your routes directly to the express app
1var express = require('express'), 2 app = express(), 3 i18next = require('i18next'), 4 FilesystemBackend = require('i18next-fs-backend'), 5 i18nextMiddleware = require('i18next-http-middleware'), 6 port = 3000 7 8i18next 9 .use(i18nextMiddleware.LanguageDetector) 10 .use(FilesystemBackend) 11 .init({ preload: ['en', 'de', 'it'], ...otherOptions }, () => { 12 i18nextMiddleware.addRoute( 13 i18next, 14 '/:lng/key-to-translate', 15 ['en', 'de', 'it'], 16 app, 17 'get', 18 (req, res) => { 19 //endpoint function 20 } 21 ) 22 }) 23app.use(i18nextMiddleware.handle(i18next)) 24app.listen(port, () => { 25 console.log('Server listening on port', port) 26})
or to an express router
1var express = require('express'), 2 app = express(), 3 i18next = require('i18next'), 4 FilesystemBackend = require('i18next-fs-backend'), 5 i18nextMiddleware = require('i18next-http-middleware'), 6 router = require('express').Router(), 7 port = 3000 8 9i18next 10 .use(i18nextMiddleware.LanguageDetector) 11 .use(FilesystemBackend) 12 .init({ preload: ['en', 'de', 'it'], ...otherOptions }, () => { 13 i18nextMiddleware.addRoute( 14 i18next, 15 '/:lng/key-to-translate', 16 ['en', 'de', 'it'], 17 router, 18 'get', 19 (req, res) => { 20 //endpoint function 21 } 22 ) 23 app.use('/', router) 24 }) 25app.use(i18nextMiddleware.handle(i18next)) 26app.listen(port, () => { 27 console.log('Server listening on port', port) 28})
custom http server
Define your own functions to handle your custom request or response
1middleware.handle(i18next, { 2 getPath: (req) => req.path, 3 getUrl: (req) => req.url, 4 setUrl: (req, url) => (req.url = url), 5 getQuery: (req) => req.query, 6 getParams: (req) => req.params, 7 getBody: (req) => req.body, 8 setHeader: (res, name, value) => res.setHeader(name, value), 9 setContentType: (res, type) => res.contentType(type), 10 setStatus: (res, code) => res.status(code), 11 send: (res, body) => res.send(body) 12})
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:
1var i18next = require('i18next') 2var middleware = require('i18next-http-middleware') 3 4i18next.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
1{ 2 // order and from where user language should be detected 3 order: [/*'path', 'session', */ 'querystring', 'cookie', 'header'], 4 5 // keys or params to lookup language from 6 lookupQuerystring: 'lng', 7 lookupCookie: 'i18next', 8 lookupHeader: 'accept-language', 9 lookupHeaderRegex: /(([a-z]{2})-?([A-Z]{2})?)\s*;?\s*(q=([0-9.]+))?/gi, 10 lookupSession: 'lng', 11 lookupPath: 'lng', 12 lookupFromPathIndex: 0, 13 14 // cache user language, you can define if an how the detected language should be "saved" => 'cookie' and/or 'session' 15 caches: false, // ['cookie'] 16 17 ignoreCase: true, // ignore case of detected language 18 19 // optional expire and domain for set cookie 20 cookieExpirationDate: new Date(), 21 cookieDomain: 'myDomain', 22 cookiePath: '/my/path', 23 cookieSecure: true, // if need secure cookie 24 cookieSameSite: 'strict', // 'strict', 'lax' or 'none' 25 26 // optional conversion function used to modify the detected language code 27 convertDetectedLanguage: 'Iso15897', 28 convertDetectedLanguage: (lng) => lng.replace('-', '_') 29}
Options can be passed in:
preferred - by setting options.detection in i18next.init:
1var i18next = require('i18next') 2var middleware = require('i18next-http-middleware') 3 4i18next.use(middleware.LanguageDetector).init({ 5 detection: options 6})
on construction:
1var middleware = require('i18next-http-middleware') 2var lngDetector = new middleware.LanguageDetector(null, options)
via calling init:
1var middleware = require('i18next-http-middleware') 2 3var lngDetector = new middleware.LanguageDetector() 4lngDetector.init(options)
Adding own detection functionality
interface
1module.exports = { 2 name: 'myDetectorsName', 3 4 lookup: function (req, res, options) { 5 // options -> are passed in options 6 return 'en' 7 }, 8 9 cacheUserLanguage: function (req, res, lng, options) { 10 // options -> are passed in options 11 // lng -> current language, will be called after init and on changeLanguage 12 // store it 13 } 14}
adding it
1var i18next = require('i18next') 2var middleware = require('i18next-http-middleware') 3 4var lngDetector = new middleware.LanguageDetector() 5lngDetector.addDetector(myDetector) 6 7i18next.use(lngDetector).init({ 8 detection: options 9})
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
No vulnerabilities found.
Reason
no dangerous workflow patterns detected
Reason
no binaries found in the repo
Reason
0 existing vulnerabilities detected
Reason
license file detected
Details
- Info: project has a license file: licence:0
- Info: FSF or OSI recognized license: MIT License: licence:0
Reason
3 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 2
Reason
Found 2/24 approved changesets -- score normalized to 0
Reason
no effort to earn an OpenSSF best practices badge detected
Reason
dependency not pinned by hash detected -- score normalized to 0
Details
- Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/deno.yml:23: update your workflow using https://app.stepsecurity.io/secureworkflow/i18next/i18next-http-middleware/deno.yml/master?enable=pin
- Warn: third-party GitHubAction not pinned by hash: .github/workflows/deno.yml:25: update your workflow using https://app.stepsecurity.io/secureworkflow/i18next/i18next-http-middleware/deno.yml/master?enable=pin
- Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/node.yml:23: update your workflow using https://app.stepsecurity.io/secureworkflow/i18next/i18next-http-middleware/node.yml/master?enable=pin
- Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/node.yml:25: update your workflow using https://app.stepsecurity.io/secureworkflow/i18next/i18next-http-middleware/node.yml/master?enable=pin
- Warn: npmCommand not pinned by hash: .github/workflows/node.yml:29
- Info: 0 out of 3 GitHub-owned GitHubAction dependencies pinned
- Info: 0 out of 1 third-party GitHubAction dependencies pinned
- Info: 0 out of 1 npmCommand dependencies pinned
Reason
detected GitHub workflow tokens with excessive permissions
Details
- Warn: no topLevel permission defined: .github/workflows/deno.yml:1
- Warn: no topLevel permission defined: .github/workflows/node.yml:1
- Info: no jobLevel write permissions found
Reason
project is not fuzzed
Details
- Warn: no fuzzer integrations found
Reason
branch protection not enabled on development/release branches
Details
- Warn: branch protection not enabled for branch 'master'
Reason
security policy file not detected
Details
- Warn: no security policy file detected
- Warn: no security file to analyze
- Warn: no security file to analyze
- Warn: no security file to analyze
Reason
SAST tool is not run on all commits -- score normalized to 0
Details
- Warn: 0 commits out of 8 are checked with a SAST tool
Score
3.6
/10
Last Scanned on 2024-11-18
The Open Source Security Foundation is a cross-industry collaboration to improve the security of open source software (OSS). The Scorecard provides security health metrics for open source projects.
Learn More