i18next/i18next-http-middleware

fastify: can't access i18n inside custom error handler

tswaters opened this issue ยท 2 comments

๐Ÿ› Bug Report

When trying to access the i18n object attached to req inside an error handler inside fastify, it is not available.

To Reproduce

const fp = require('fastify-plugin')
const i18next = require('i18next')
const {LanguageDetector, plugin: i18nextPlugin} = require('i18next-http-middleware')

const MyI18nPlugin = fp(async function MySpecialI18nPlugin(app) {
  i18next.use(LanguageDetector).init({...normal options...})
  app.register(i18nextPlugin, {i18next})
})

app.register(MyI18nPlugin)
app.setErrorHandler(function (error, request, reply) {
  assert(request.i18n) // fails
})

Expected behaviour

the i18n object should be available here, but it is not.

The contents of the "plugin" export are currently, (from cjs transpiled)

function plugin(instance, options, next) {
  options.attachLocals = true;
  var middleware = handle(options.i18next, options);
  instance.addHook('preHandler', function (request, reply, next) {
    return middleware(request, reply, next);
  });
  return next();
}

The preHandler fires much later in the fastify lifecycle, https://www.fastify.io/docs/latest/Lifecycle/ -- if any errors are to crop up prior to that (schema validation errors, say) the middleware won't get attached, and the end result is trying to perform translations inside the application's error handler will fail due to no i18n object on request.

Workaround

This module does expose the "handle" function -- I've been able to work around this with the following:

-const {LanguageDetector, plugin: i18nextPlugin} = require('i18next-http-middleware')
+const {LanguageDetector, handle: i18nextHandle} = require('i18next-http-middleware')

- app.register(i18nextPlugin, {i18next})
+ app.decorateRequest('i18n', null)
+ app.addHook('onRequest', i18nextHandle(i18next, {attachLocals: true})) 

i.e., don't use the plugin export directly, instead attach handle to the onRequest hook.

I'm not sure if this module should attach sooner via onRequest or not.

There is some overhead there that can be avoided if requests go into error -- I can see using i18n inside the error handler being an outlier use case, but figured I would share my workaround here in case anyone else encounters this.

Your Environment

  • runtime version: node 14.17.6
  • i18next version: 20.6.1,
  • i18next-http-middleware: 3.1.4
  • os: Linux
adrai commented

This is probably because of your MyI18nPlugin plugin which makes use of the encapsulation feature of fastify.

This example works: https://github.com/i18next/i18next-http-middleware/blob/master/example/fastify/index.js#L31

Huh! That's weird... it's wrapped in fastify-plugin.

Thanks for pointing me at that example, not sure how I missed it.

I'll close this, seems the issue is on my end.