1

I am setting up i18next middleware in my express handlebars app, i18next works for any translation I put as the fallbackLng, the problem is none of the i18next middleware features are working like for example getting the lng param from url

Here is my i18next init setup

import { filterNodesByGroups, getNodeLabel } from "@ory/integrations/ui"
import express, { Request, Response } from "express"
import handlebars from "express-handlebars"
import * as fs from "fs"
import * as https from "https"

import { middleware as middlewareLogger } from "./pkg/logger"
import { toUiNodePartial } from "./pkg/ui"
import {
  register404Route,
  register500Route,
  registerErrorRoute,
  registerHealthRoute,
  registerLoginRoute,
  registerRecoveryRoute,
  registerRegistrationRoute,
  registerSettingsRoute,
  registerStaticRoutes,
  registerVerificationRoute,
  registerWelcomeRoute,
} from "./routes"

const i18next = require('i18next')
const i18nextMiddleware = require('i18next-http-middleware')
const Backend = require('i18next-fs-backend')
const HandlebarsI18n = require("handlebars-i18n");

const app = express()

console.log("were here")
i18next
  .use(Backend)
  // .use(languageDetector)
  .use(i18nextMiddleware.LanguageDetector)
  .init({
    debug: true,
    backend: {
      // eslint-disable-next-line no-path-concat
      loadPath: __dirname + '/i18n/{{lng}}/{{ns}}.json'
    },
    fallbackLng: 'en',
    preload: ['en', 'fr'],
    // nonExplicitSupportedLngs: true,
    // supportedLngs: ['en', 'fr'],
    load: 'languageOnly'
  })

app.use(middlewareLogger)
app.set("view engine", "hbs")
app.use(i18nextMiddleware.handle(i18next))

HandlebarsI18n.init();

app.engine(
  "hbs",
  handlebars({
    extname: "hbs",
    layoutsDir: `${__dirname}/../views/layouts/`,
    partialsDir: `${__dirname}/../views/partials/`,
    defaultLayout: "main",
    helpers: {
      ...require("handlebars-helpers")(),
      jsonPretty: (context: any) => JSON.stringify(context, null, 2),
      onlyNodes: filterNodesByGroups,
      toUiNodePartial,
      getNodeLabel: getNodeLabel,
    },
  }),
)

registerStaticRoutes(app)
registerHealthRoute(app)
registerLoginRoute(app)
registerRecoveryRoute(app)
registerRegistrationRoute(app)
registerSettingsRoute(app)
registerVerificationRoute(app)
registerWelcomeRoute(app)
registerErrorRoute(app)

app.get("/", (req: Request, res: Response) => {
  res.redirect("welcome", 303)
})

register404Route(app)
register500Route(app)

const port = Number(process.env.PORT) || 3000

let listener = (proto: "http" | "https") => () => {
  console.log(`Listening on ${proto}://0.0.0.0:${port}`)
}

if (process.env.TLS_CERT_PATH?.length && process.env.TLS_KEY_PATH?.length) {
  const options = {
    cert: fs.readFileSync(process.env.TLS_CERT_PATH),
    key: fs.readFileSync(process.env.TLS_KEY_PATH),
  }

  https.createServer(options, app).listen(port, listener("https"))
} else {
  app.listen(port, listener("http"))
}

Here is the new package example

The deprecated package has an example that is close to the new package here

What could be wrong with my initialization of i18next-http-middleware?

Edit: If I change the language in the url header from en to fr in the debug output I get several language changes between requests for example:

i18next: languageChanged en
i18next: languageChanged fr
{"level":"info","message":"HTTP GET ... "}
i18next: languageChanged en
i18next: languageChanged en-US
{"level":"info","message":"HTTP GET ... "}
i18next: languageChanged en
i18next: languageChanged en-US
{"level":"info","message":"HTTP GET ... "}
i18next: languageChanged en
i18next: languageChanged en-US
i18next: languageChanged en
i18next: languageChanged en-US
i18next: languageChanged en
i18next: languageChanged en-US
i18next: languageChanged en
i18next: languageChanged en-US

2 Answers2

1

I think this is a problem of integration between https://github.com/Aller-Couleur/handlebars-i18n/ and https://github.com/i18next/i18next-http-middleware

i18next-http-middleware sets the language on a clone of i18next instance that is reported on request (req.i18n), while handlebars-i18n use the i18next global instance, and I don't see anyway it can be changed.

I opened an issue on handlebars-i18n: https://github.com/Aller-Couleur/handlebars-i18n/issues/43 as it could be an easy fix on their side.

alex garel
  • 26
  • 4
  • 1
    Also see my commit to fix it in the repository, by adding a middleware https://github.com/openfoodfacts/kratos-selfservice-ui-node/commit/901a3f675c10dd47c449686ac5e8fa7e1541a4f1 – alex garel Oct 13 '22 at 09:28
0

Seems like the middleware is not applied. Try to move this line after the app.set("view engine", "hbs") line:

app.use(i18nextMiddleware.handle(i18next))
adrai
  • 2,495
  • 1
  • 15
  • 18
  • The middleware is applied I edited my comment to include the debug output. I am getting a language change but it re changes back to the fallback. – Landon Pattison Oct 04 '22 at 20:58
  • Please provide a minimal reproducible example in a github repo... – adrai Oct 05 '22 at 07:45
  • I wrote up a readme on how to develop under OpenFoodFacts i18n development I made it as minimal as possible https://github.com/openfoodfacts/kratos-selfservice-ui-node/tree/i18n. Thank you – Landon Pattison Oct 05 '22 at 16:36
  • sorry, but this is not minimal… just i18next, express and handlebars… the rest is too much… sorry – adrai Oct 05 '22 at 20:28
  • btw: where are you using these translation keys? https://github.com/openfoodfacts/kratos-selfservice-ui-node/blob/i18n/src/i18n/en/translation.json#L4 – adrai Oct 05 '22 at 20:43
  • There should be something like calling the t function in your views: https://github.com/i18next/i18next-http-middleware/blob/master/example/basic-pug/views/index.pug#L5 – adrai Oct 05 '22 at 20:44
  • please provide a real minimum example... just 1 simple route, not your complete app... seems for 1 page view a lot of requests are done... without knowing exactly your complete app, this will be crazy to investigate... please isolate your problem first! – adrai Oct 05 '22 at 20:46
  • The problem with the minimum example is that the UI depends on a docker container to get the forms – Landon Pattison Oct 12 '22 at 14:44
  • The translations are being done here https://github.com/openfoodfacts/kratos-selfservice-ui-node/blob/i18n/views/partials/ui_node_input_default.hbs#L5 using the __ it is from this module https://github.com/Aller-Couleur/handlebars-i18n – Landon Pattison Oct 12 '22 at 14:47