Skip to content

Commit

Permalink
support koa #61
Browse files Browse the repository at this point in the history
  • Loading branch information
adrai committed Sep 27, 2023
1 parent 67e39a5 commit 10f8859
Show file tree
Hide file tree
Showing 16 changed files with 395 additions and 13 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
## [v3.4.0](https://github.com/i18next/i18next-http-middleware/compare/v3.3.2...v3.4.0)
- support koa [#61](https://github.com/i18next/i18next-http-middleware/issues/61)

## [v3.3.2](https://github.com/i18next/i18next-http-middleware/compare/v3.3.1...v3.3.2)
- deno: oak fix [#59](https://github.com/i18next/i18next-http-middleware/issues/59)

Expand Down
30 changes: 30 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,36 @@ server.route({

```
### Koa usage
```js
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.language': ctx.language,
'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
Expand Down
8 changes: 8 additions & 0 deletions example/koa/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# run the sample

```
$ npm i
$ npm start
```

open: http://localhost:8080
84 changes: 84 additions & 0 deletions example/koa/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
const Koa = require('koa')
const router = require('@koa/router')()
const koaBody = require('koa-body').default
const serve = require('koa-static')
const mount = require('koa-mount')
const i18next = require('i18next')
// const i18nextMiddleware = require('i18next-http-middleware')
const i18nextMiddleware = require('../../../i18next-http-middleware')
const Backend = require('i18next-fs-backend')
// const Backend = require('../../../i18next-fs-backend')

const app = new Koa()
app.use(koaBody({
jsonLimit: '1kb'
}))
const port = process.env.PORT || 8080

i18next
.use(Backend)
// .use(languageDetector)
.use(i18nextMiddleware.LanguageDetector)
.init({
// debug: true,
// detection: {
// order: ['customDetector']
// },
backend: {
// eslint-disable-next-line no-path-concat
loadPath: __dirname + '/locales/{{lng}}/{{ns}}.json',
// eslint-disable-next-line no-path-concat
addPath: __dirname + '/locales/{{lng}}/{{ns}}.missing.json'
},
fallbackLng: 'en',
// nonExplicitSupportedLngs: true,
// supportedLngs: ['en', 'de'],
load: 'languageOnly',
saveMissing: true
})

app.use(i18nextMiddleware.koaPlugin(i18next))

router.get('/', ctx => {
ctx.body = JSON.stringify({
'ctx.language': ctx.language,
'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)
})


router.get('/missingtest', ctx => {
ctx.t('nonExisting', 'some default value')
ctx.body = 'check the locales files...'
})

// loadPath for client: http://localhost:8080/locales/{{lng}}/{{ns}}.json
app.use(mount('/locales', serve('./locales')))

// or instead of static
// router.get('/locales/:lng/:ns', i18nextMiddleware.getResourcesHandler(i18next))
// loadPath for client: http://localhost:8080/locales/{{lng}}/{{ns}}

// missing keys make sure the body is parsed (i.e. with [body-parser](https://github.com/expressjs/body-parser#bodyparserjsonoptions))
router.post('/locales/add/:lng/:ns', i18nextMiddleware.missingKeyHandler(i18next))
// The client can be configured with i18next-http-backend, for example like this:
// import HttpBackend from 'i18next-http-backend'
// i18next.use(HttpBackend).init({
// lng: 'en',
// fallbackLng: 'en',
// backend: {
// loadPath: 'http://localhost:8080/locales/{{lng}}/{{ns}}.json',
// addPath: 'http://localhost:8080/locales/add/{{lng}}/{{ns}}'
// }
// })

app.use(router.routes())

app.listen(port, () => {
console.log(`Server is listening on port ${port}`)
})

// curl localhost:8080 -H 'Accept-Language: de-de'
5 changes: 5 additions & 0 deletions example/koa/locales/de/translation.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"home": {
"title": "Hallo Welt!"
}
}
5 changes: 5 additions & 0 deletions example/koa/locales/en/translation.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"home": {
"title": "Hello World!"
}
}
5 changes: 5 additions & 0 deletions example/koa/locales/fr/translation.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"home": {
"title": "Bonjour le monde!"
}
}
20 changes: 20 additions & 0 deletions example/koa/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"name": "i18next-express-basic",
"version": "1.0.0",
"description": "Node Express server with i18next.",
"main": "index.js",
"type": "commonjs",
"scripts": {
"start": "node index.js"
},
"dependencies": {
"@koa/router": "12.0.0",
"i18next": "23.5.1",
"i18next-fs-backend": "2.2.0",
"i18next-http-middleware": "3.3.2",
"koa": "2.14.2",
"koa-body": "6.0.1",
"koa-mount": "4.0.0",
"koa-static": "5.0.0"
}
}
2 changes: 2 additions & 0 deletions index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,8 @@ type IgnoreRoutesFunction = (

export function handle(i18next: I18next, options?: HandleOptions): Handler;

export function koaPlugin(i18next: I18next, options?: HandleOptions): (context: unknown, next: Function) => any;

export function plugin(
instance: any,
options: HandleOptions & { i18next?: I18next },
Expand Down
5 changes: 5 additions & 0 deletions lib/httpFunctions.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ export const getBody = (req) => {
if (req.json) return req.json
if (req.body) return req.body
if (req.payload) return req.payload
if (req.request && req.request.body) return req.request.body
console.log('no possibility found to get body')
return {}
}
Expand All @@ -94,6 +95,9 @@ export const setHeader = (res, name, value) => {
if (res.headers && typeof res.headers.set === 'function') {
return res.headers.set(name, value)
}
if (typeof res.set === 'function') {
return res.set(name, value)
}
console.log('no possibility found to set header')
}
export const setContentType = (res, type) => {
Expand All @@ -109,6 +113,7 @@ export const setStatus = (res, code) => {
}
export const send = (res, body) => {
if (typeof res.send === 'function') return res.send(body)
if (res.request && res.response && res.app) res.body = body
return body
}
export const getSession = (req) => {
Expand Down
15 changes: 15 additions & 0 deletions lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,12 @@ const checkForCombinedReqRes = (req, res, next) => {
res = req
if (!next) next = () => {}
}
} else if (!next && typeof res === 'function' && req.req && req.res) {
return {
req,
res: req,
next: res
}
}
return { req, res, next }
}
Expand Down Expand Up @@ -119,6 +125,14 @@ export function plugin (instance, options, next) {
return next()
}

export function koaPlugin (i18next, options) {
const middleware = handle(i18next, options)
return async function koaMiddleware (ctx, next) {
await new Promise((resolve) => middleware(ctx, ctx, resolve))
await next()
}
}

export const hapiPlugin = {
name: 'i18next-http-middleware',
version: '1',
Expand Down Expand Up @@ -291,6 +305,7 @@ export function addRoute (i18next, route, lngs, app, verb, fc) {
export default {
plugin,
hapiPlugin,
koaPlugin,
handle,
getResourcesHandler,
missingKeyHandler,
Expand Down
27 changes: 14 additions & 13 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,28 +27,29 @@
}
},
"module": "./esm/index.js",
"dependencies": {},
"devDependencies": {
"@babel/cli": "7.21.5",
"@babel/core": "7.21.8",
"@babel/preset-env": "7.21.5",
"@hapi/hapi": "^20.2.2",
"@types/express-serve-static-core": "^4.17.35",
"@babel/cli": "7.23.0",
"@babel/core": "7.23.0",
"@babel/preset-env": "7.22.20",
"@hapi/hapi": "^21.3.2",
"@types/express-serve-static-core": "^4.17.37",
"@koa/router": "12.0.0",
"koa": "2.14.2",
"babel-plugin-add-module-exports": "1.0.4",
"eslint": "8.41.0",
"eslint-config-standard": "17.0.0",
"eslint-plugin-import": "2.27.5",
"eslint-plugin-n": "15.7.0",
"eslint": "8.50.0",
"eslint-config-standard": "17.1.0",
"eslint-plugin-import": "2.28.1",
"eslint-plugin-n": "16.1.0",
"eslint-plugin-promise": "6.1.1",
"eslint-plugin-require-path-exists": "1.1.9",
"eslint-plugin-standard": "5.0.0",
"expect.js": "0.3.1",
"express": "4.18.2",
"fastify": "4.17.0",
"i18next": "22.5.0",
"fastify": "4.23.2",
"i18next": "23.5.1",
"mocha": "10.2.0",
"supertest": "6.3.3",
"tsd": "0.28.1",
"tsd": "0.29.0",
"uglify-js": "3.17.4"
},
"description": "i18next-http-middleware is a middleware to be used with Node.js web frameworks like express or Fastify and also for Deno.",
Expand Down
53 changes: 53 additions & 0 deletions test/addRoute.koa.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import expect from 'expect.js'
import i18nextMiddleware from '../index.js'
import i18next from 'i18next'
import Koa from 'koa'
import Router from '@koa/router'
import request from 'supertest'

const router = Router()
i18next.init({
fallbackLng: 'en',
preload: ['en', 'de'],
saveMissing: true
})

describe('addRoute koa', () => {
describe('and handling a request', () => {
const app = new Koa()
app.use(i18nextMiddleware.koaPlugin(i18next))
let server

before((done) => {
server = app.listen(7002, done)
})
after((done) => server.close(done))

it('should return the appropriate resource', (done) => {
app.use(i18nextMiddleware.handle(i18next))
const handle = (ctx) => {
expect(ctx).to.have.property('lng', 'en')
expect(ctx).to.have.property('locale', 'en')
expect(ctx).to.have.property('language', 'en')
expect(ctx).to.have.property('languages')
expect(ctx.languages).to.eql(['en'])
expect(ctx).to.have.property('i18n')
expect(ctx).to.have.property('t')
expect(ctx.t('key')).to.eql('key')
ctx.body = ctx.t('key')
}
i18nextMiddleware.addRoute(i18next, '/myroute/:lng/:ns', ['en'], router, 'get', handle)

app.use(router.routes())

request(server)
.get('/myroute/en/test')
.expect('Content-Language', 'en')
.expect(200, (err, res) => {
expect(err).not.to.be.ok()
expect(res.text).to.eql('key')
done()
})
})
})
})
53 changes: 53 additions & 0 deletions test/getResourcesHandler.koa.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import expect from 'expect.js'
import i18nextMiddleware from '../index.js'
import i18next from 'i18next'
import Koa from 'koa'
import Router from '@koa/router'
import request from 'supertest'

const router = Router()
i18next.init({
fallbackLng: 'en',
preload: ['en', 'de'],
saveMissing: true,
resources: {
en: {
translation: { hi: 'there' }
}
}
})

describe('getResourcesHandler koa', () => {
describe('handling a request', () => {
const app = new Koa()
let server

before((done) => {
server = app.listen(7002, done)
})
after((done) => server.close(done))

it('should return the appropriate resource', (done) => {
router.get('/', i18nextMiddleware.getResourcesHandler(i18next))

app.use(router.routes())

request(server)
.get('/')
.query({
lng: 'en',
ns: 'translation'
})
.expect('content-type', /json/)
.expect('cache-control', 'no-cache')
.expect('pragma', 'no-cache')
.expect(200, (err, res) => {
expect(err).not.to.be.ok()
expect(res.body).to.have.property('en')
expect(res.body.en).to.have.property('translation')
expect(res.body.en.translation).to.have.property('hi', 'there')
done()
})
})
})
})
Loading

0 comments on commit 10f8859

Please sign in to comment.