i18next/i18next-http-middleware

fallbackLng option doesn't work as documented

plashenkov opened this issue ยท 8 comments

๐Ÿ› Bug Report

fallbackLng option passed as an object doesn't work as documented here: https://www.i18next.com/principles/fallback#fallback-language

To Reproduce

The code (I omit backend, etc. here for simplicity):

const i18next = require('i18next')
const {LanguageDetector, handle} = require('i18next-http-middleware')

i18next
  .use(LanguageDetector)
  .init({
    supportedLngs: ['en', 'ru'],
    fallbackLng: {
      kz: ['ru'],
      default: ['en'],
    },
    detection: {
      order: ['querystring'],
    }
  })

app
  .use(handle(i18next))
  .get('/some-route', function (req, res) {
    res.json({
      lang: req.language,
    })
  })

Let's get it:

curl https://example.test/some-route?lng=kz
{
  "lang": "en"      # must be 'ru'!
}

Expected behavior

lng=kz must fallback to 'ru', since we specified this rule. Unfortunately it follows only the default rule.

Of course, this code:
https://github.com/i18next/i18next-http-middleware/blob/master/lib/LanguageDetector.js#L88
can't work as documented here: https://www.i18next.com/principles/fallback#fallback-language
(if the fallbackLng option here came from init() options and not modified somewhere else).

Your Environment

  • runtime version: node v16.3.0
  • i18next version: 20.3.3
  • os: Linux (Docker)
adrai commented

the fallback language is for the key resolution... it's not saved here: req.language...
maybe req.i18n.languages suits better for you... https://www.i18next.com/overview/api#languages

Hi @adrai
Thanks for the answer.

Unfortunately it doesn't. req.i18n.languages contains just ['en'] array for ?lng=kz, although it should be resolved to ru in our example.

adrai commented

Does it make a difference if you put kz to the supportedLngs?

Nope, then it simply returns 'kz' as is.

adrai commented

I just modified this example: https://github.com/i18next/i18next-http-middleware/tree/master/example/basic
image

And requesting: http://localhost:8080/?lng=kz results to:

{
  "req.language": "kz",
  "req.i18n.language": "kz",
  "req.i18n.languages": [
    "kz",
    "fr"
  ],
  "req.i18n.languages[0]": "kz",
  "req.t(\"home.title\")": "Bonjour le monde!"
}

as you can see the used language is correct: it uses the fr language resource: "Bonjour le monde!"
And req.i18n.languages contains all resolving languages... so also my defined fallback fr

Thank you for your answer, @adrai!
Okay, I get the logic.

Then response's content-language header will be 'kz' although we do not want to provide such localization, we just want to "redirect" kz language (as well as some other languages) to 'ru' (instead of 'en', for example) since this would be very reasonable behavior.

Would it be strategically more correct for this library to really set the actual fallback language as a req.language attribute (etc., including 'content-language' header)? For the case when we do not directly support some language (it's not presented in supportedLngs), but it is specified in fallbackLng object as a key.

If not, we can simply close this issue.

adrai commented

fallback does not mean redirect...
falback is for language resolution per key...

I mean "redirect" not literally.

Okay, let's close it. Thanks!