Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

react-i18next:: i18n.languages were undefined or empty undefined #374

Closed
mehmetnyarar opened this issue Jul 2, 2019 · 74 comments · Fixed by #461 or #541
Closed

react-i18next:: i18n.languages were undefined or empty undefined #374

mehmetnyarar opened this issue Jul 2, 2019 · 74 comments · Fixed by #461 or #541
Labels
bug Something isn't working help wanted Extra attention is needed

Comments

@mehmetnyarar
Copy link

Describe the bug

I get the the following error:

[ wait ]  compiling ...
react-i18next:: i18n.languages were undefined or empty undefined

which appears only on the server (I mean in the output of the terminal, it doesn’t appear on the browser console).

Occurs in next-i18next version

"next": "^8.1.0",
"i18next": "^17.0.6",
"next-i18next": "^0.44.0",

Steps to reproduce

I followed every step described in the readme except keySeparator (because I have keys like Status.ONGOING)

Below is my configuration:

import NextI18Next from 'next-i18next'

const instance = new NextI18Next({
  defaultLanguage: 'en',
  otherLanguages: ['ru'],
  keySeparator: false
})

export default instance

Expected behaviour

This doesn’t look like a critical error, though I’m wondering the cause.

Screenshots

OS (please complete the following information)

  • Device: MacBook Pro (Retina, 13-inch, Late 2013)
  • Browser: Chrome Canary Version 77.0.3838.0 (Official Build) canary (64-bit)

Additional context

  • I’m working on a monorepo (yarn workspaces)
  • I use TypeScript
@isaachinman
Copy link
Contributor

Are you sure keySeparator: false is a valid config option? Regardless, if I add that single line to the simple example, I do not see this error.

Please provide reproducible repo.

@JeremieLeblanc
Copy link

I believe I'm getting the same error when using i18n.language for a select value. The value is undefined on the server and correct on the client, so it flickers on load.

@isaachinman
Copy link
Contributor

Does anyone have a reproducible example?

@shaomingwei
Copy link

I have the same problem,Have you solved it?

@mehmetnyarar
Copy link
Author

mehmetnyarar commented Jul 5, 2019

@isaachinman Here is the repo.

You’ll see a warning initially

You have not declared a namespacesRequired array on your page-level component: ErrorPage. This will cause all namespaces to be sent down to the client, possibly negatively impacting the performance of your app. For more info, see: https://github.com/isaachinman/next-i18next#4-declaring-namespace-dependencies

And then

react-i18next:: i18n.languages were undefined or empty undefined

I also added pages/—ERROR—, which when you rename to _error.tsx, will create a custom error page. When it exists, the error goes away.

In my actually project, I have error page and namespacesRequired is set in getInitialProps in every pages, yet error is still there.

@isaachinman
Copy link
Contributor

@mehmetnyarar I have cloned your repo and run it. I do see the namespacesRequired warning, but that is expected.

I do not see the i18n.languages were undefined warning.

Does anyone have a reproducible example?

@deemaagog
Copy link

Does anyone have a reproducible example?

I'm getting this warning when just running simple example (build & start)

"next": "^8.1.0",
"i18next": "^17.0.6",
"next-i18next": "^0.45.0"

@isaachinman
Copy link
Contributor

@deemaagog I cannot reproduce that either. Can you zip your directory, including node_modules, and send it to me?

@mslepcevic
Copy link

mslepcevic commented Jul 5, 2019

I also have this error in a ts project with a custom server, but only in this case:

  1. dev server started with a watch service to reload on code changes to .ts files, with hot reload for .tsx files
  2. a page is open in the browser
  3. save a change to a .tsx file which triggers a recompile
  4. during the recompile, a request for the hot reload module comes in (at least it looks like it does, not entirely sure how that works), results in a 404, which triggers the compilation of the _error page (makes no difference if it's a custom or default.one)
  5. the missing lang message is shown, and common.missing.json gets generated with the error page translations in it (the custom error page is exported and used with the translation wrapper function, and works in 6 below)
  6. when producing a real 404 error by visiting a non-existing page in the browser (both with SSR, and client side navigation), everything works normally

Sometimes, the recompile finishes before the hot module request, and the error page doesn't get generated, and everything is ok, but that might be a 1 out of 10 occurrence.

Using next 8.1.0 and ni18n 0.44.0

@isaachinman
Copy link
Contributor

@mslepcevic Thanks for that information.

@mehmetnyarar Is this a dev-only error, or are you experiencing problems in production? Sounds like this could be a userland dev setup issue.

@mslepcevic
Copy link

@isaachinman
Just to add that everything worked ok with my setup with next-i18next v0.41.0.

And the HMR request comes in because of the page that's opened in the browser and wants to reload upon saving a file.

@WardVH
Copy link
Contributor

WardVH commented Jul 8, 2019

I'm also experiencing the same issue, even in production.
It happens on server and browser.

I haven't had the time yet to create a reproducible repository tho.
I found this: i18next/i18next#948

I can recall that i've only seen the warning when using the following setup to determine the language:

const currentLanguage = typeof req === "undefined" ? i18n.language : req.language; (in _app.js && _document.js).

Could it be that it's sometimes not waiting for the response and thus triggers the warning?

@deemaagog
Copy link

@deemaagog I cannot reproduce that either. Can you zip your directory, including node_modules, and send it to me?

Here is a zip

@isaachinman
Copy link
Contributor

Thanks @deemaagog I've finally seen this reproduced. It's coming from react-i18next's hasLoadedNamespace function.

I will dig into this now, but it looks like a harmless warning, unless I'm mistaken.

@isaachinman
Copy link
Contributor

So although I saw the error one time, I cannot reproduce it reliably and have not seen it since then. If this is a race condition, I'm not sure where it is.

It seems like this would be caused by a call to useTranslation before the i18next express middleware has set up i18n.languages.

@urielscola
Copy link

@isaachinman first of all, thanks for the plugin :)
I had the same problem described here, here is the repo
Hope it helps to debug

@isaachinman
Copy link
Contributor

@urielscola Multiple problems with your repo which are unrelated:

  1. You're using next start instead of a custom server, which is a requirement
  2. You're not pointing your build script to your src dir

That said, even if I run yarn dev, the server never comes online.

@urielscola
Copy link

@isaachinman thanks, you were absolutely right. I fixed those problems and now it is working

@ilhammeidi
Copy link

ilhammeidi commented Jul 12, 2019

I got the same issue because I just use footer:description only, but I called both common and footer,

<Typography variant="h5" align="center" color="textSecondary" paragraph> {t('footer:description')} </Typography>

export default withTranslation(['footer', 'common'])(Landing);

I tried to remove 'common. But the issue still happen. I'm not sure why the 'common' translation is a must.
So I added another text with translation:common in my page.

<Typography component="h1" variant="h2" align="center" color="textPrimary" gutterBottom> {t('common:h1')} </Typography>

Then the issue is resolved.

@isaachinman
Copy link
Contributor

@ilhammeidi Can you please provide a reproducible repository?

@ilhammeidi
Copy link

@ilhammeidi Can you please provide a reproducible repository?

Here's my file and repo https://github.com/ilhammeidi/luxi-react-starter/blob/master/pages/index.js

I'm still testing about "react-i18next:: i18n.languages were undefined or empty undefined" message that sometime show in console. After ctrl+shit+r in chrome and restart server, it's gone already.

@isaachinman
Copy link
Contributor

Okay, please let me know if you discover a reliable way to reproduce it.

@qlaffont
Copy link

Hi,
Same error for me. I don't understand why :/. Zip : http://s000.tinyupload.com/index.php?file_id=28449173765932552030

@ricardo-cantu
Copy link

I see 2 possible issues

  • i18next returns a promise and has a callback that need to be respected when init is called, but is not taken in a count with current pattern of use
  • An extra instance is created during SSR phase even though it's not used in hoc because it picks the instance in req, this extra instance might be giving a harmless warning

@isaachinman
Copy link
Contributor

@ricardo-cantu Thanks for your input. Indeed it'd be good if we can await the promise returned by init, but that could end up being a bit tricky - I would appreciate any/all suggestions in regards to that.

Can you explain your second point in more detail? The mysterious i18n.languages were undefined error is coming specifically from react-i18next.

@ricardo-cantu
Copy link

@isaachinman Thanks for the awesome work you've done with this library. I wrote my own implementation in typescript based on your work (I left out several things I didn't need)

  • I solved the i18n promise problem with the following pattern:
    nextApp.prepare().then(async () => { const server = express() ... await i18n.initServerInstance() server.use(i18nextMiddleware(i18n.i18nextInstance)) ...
  • In the SSR server bundle you will always end up with an i18n instance that is never used due to the pattern of always importing './18n', but on the server you always use the one from req.i18n. I didn't know if that unused instance maybe was making react-18next give that warning in some harmless way. It was just a thought

@isaachinman
Copy link
Contributor

nextApp.prepare()

I'm hesitant to go down this road, as we are really trying to get closer to serverless support.

As for the second point, req.i18n is actually a clone of your main i18n instance. This is the expected pattern with the i18next express middleware.

@ricardo-cantu
Copy link

ricardo-cantu commented Jul 17, 2019

You can simply show an example of wrapping the application with a top level function. There's already an example of index.ts -> server.ts somewhere in next.js examples.

import {application} from './app.ts'  
  
application();  
  
app.ts  
async () => {  
}

When you say serverless, do you mean no node server like express?

@gtolarc
Copy link

gtolarc commented Jul 18, 2019

@isaachinman I have the same problem.
The current flow seems to have the problem that defaultLanguage is not assigned to initialLanguage in the first appWithTranslation-getInitialProps server rendering.
I have confirmed that warning is not generated in react-i18next when hard-coding the initialLanguage value.

@isaachinman
Copy link
Contributor

@gtolarc That's very helpful, thank you! If I set initialLanguage to null manually, I see this error on the client side, however I do not see it in SSR. Do you have a way of reproducing on the server side?

@isaachinman
Copy link
Contributor

@oteka21 Please see the source.

@rdewolff
Copy link

Same issue here with latest versions. Site seems to render with:

lng: 'en',

as @truongtx9 proposed above. What's this ? Is this a bug or a non documented feature ?

@isaachinman
Copy link
Contributor

@rdewolff As stated previously, that will break language detection.

@sebaseek
Copy link

Facing the same issue, there is a way to solve this without breaking the language detection?

@harmvandendorpel
Copy link

+1

@isaachinman
Copy link
Contributor

there is a way to solve this without breaking the language detection?

Yes, either await the promise returned by the i18next init call, or use the callback.

@StarpTech
Copy link
Contributor

@isaachinman

Yes, either await the promise returned by the i18next init call, or use the callback.

so do you know a solution or what is the state here? How can I help?

@isaachinman
Copy link
Contributor

@StarpTech The working assumption is that it's a race condition on startup. The only way we can arrive at a non-breaking-change solution is if we can find a way to initialise an i18next instance synchronously.

@bethrezen
Copy link

bethrezen commented Aug 29, 2019

If that helps, let me describe my solution to the problem.
In my case I've seen such errors when there were requests to non existing URLS(404) on /static/.
And here's the logic:

  1. We have our next-i18next/middleware
  2. next-i18next/middleware adds another middleware i18next-express-middleware
  3. i18next-express-middleware checks ignoreRoutes option
  4. /static/ is ignored, so i18next-express-middleware is not running at all - it just calls next() function argument, so express.js server continues
  5. Then next.js can't find static file and tries to show Error page (_error.js)
  6. In my case _error.js has namespacesRequired, but it is rendered within a Document that has react components that need translations
  7. But we can't render them because i18next-express-middleware didn't provide anything because /static/ is ignored route.

So here is solution in my case - change ignoreRoutes to empty array:

const NextI18Next = require('next-i18next').default;

const { localeSubpaths } = require('next/config').default().publicRuntimeConfig;

const localeSubpathVariations = {
  none: {},
  foreign: {
    fr: 'fr',
    en: 'en',
  },
  all: {
    en: 'en',
    fr: 'fr',
  },
};

module.exports = new NextI18Next({
  defaultLanguage: 'ru',
  otherLanguages: ['fr', 'en'],
  localeSubpaths: localeSubpathVariations[localeSubpaths],
  debug: true,
  // initImmediate: true,
  // load: 'all',
  ignoreRoutes: [],
});

@isaachinman not sure if there's any race condition in i18next-express-middleware(cuz there's no async and loadLanguages calls next() only on callback), but please check my solution if it closes this issue

@isaachinman
Copy link
Contributor

Setting ignoreRoutes to an empty array is not a solution. That config option is there for a reason. For any users that use localeSubpaths, their static and _next traffic would be erroneously redirected, breaking the entire app.

For anyone wishing to help on this issue: please take a deep dive before bumping or offering suggestions!

@MelleB
Copy link

MelleB commented Aug 29, 2019

@isaachinman Not sure if it is of any help, but for me the problem seems to occur when I'm having a custom route, e.g.:

custom route:

  router.get('/password-renew/:passwordResetSlug', helmet.noCache(), (req, res) => {
    const actualPage = '/password-renew';
    const queryParams = { ...req.query, passwordResetSlug: req.params.passwordResetSlug }
    return app.render(req, res, actualPage, queryParams);
  })

page:

class RenewPasswordPage extends Component {
  static async getInitialProps(ctx) {
    const namespacesRequired = ['public']
    const passwordResetSlug = ctx.query.passwordResetSlug
    return { namespacesRequired, passwordResetSlug }
  }

  render() {
    // ...
  }
}

export default withTranslation('public')(RenewPasswordPage)

@qd-qd
Copy link

qd-qd commented Aug 29, 2019

Not sure if I'm helping but I caught this error from my side too and I temporary fix it by adding languages propriety to i18n object.

const languages = ['fr-FR', 'en-GB'];

const options = {
  defaultLanguage: 'fr-FR',
  otherLanguages: ['en-GB'],
  ...
};

const NextI18NextInstance = new NextI18Next(options);

NextI18NextInstance.i18n.languages = languages;

module.exports = NextI18NextInstance;

@MelleB
Copy link

MelleB commented Aug 29, 2019

Using @jonathangiamp worked after adding the fallbackLng config property.

@StarpTech
Copy link
Contributor

Correct me if I'm wrong but if the root issue is really the way how we bootstrap i18n then we should release a breaking change to fix that correctly.

@isaachinman
Copy link
Contributor

@StarpTech If and when it is determined that we cannot initialise an i18next instance synchronously, then yes, we'd need to release a breaking change.

This is a very good example of a use case where we definitely want to init an instance synchronously, as our application cannot serve any requests until it's ready.

@jamuhl Any ideas about what we might be doing wrong here? Any opinion about construction/initialisation? Funny that this issue has become so popular.

@StarpTech
Copy link
Contributor

@isaachinman please add "bug" label

@isaachinman isaachinman added bug Something isn't working help wanted Extra attention is needed labels Aug 31, 2019
@jamuhl
Copy link
Member

jamuhl commented Aug 31, 2019

@isaachinman would be happy to help with this...but I do not get the issue

  • init call can't really be synchronous - because loading via xhr, fs, ... all those operations are asynchronous by design

but why is that a problem in production...a server starts up and things will be ready on first request...or even delay start of server and start it inside the init callback...

for serverless add a middleware that asserts init is done before calling next should do the trick (just use the initialized event and flag on i18next.)

@ricardo-cantu
Copy link

Looks like this might happen more often when you have a custom _error that uses t() or the hoc. Next will compile a _error page with no req, thus no i18n object that has the correct lang detected. I removed the custom _error in another project I’m working on and I have not seen the warning again.

@isaachinman
Copy link
Contributor

Finally took some time to dig into this. The issue of awaiting the initialisation of the i18next instance is a very trivial one, and I can provide an easy, non-breaking way for users to do that if they want to. However, I think that that race condition is causing a very low percentage of the error reports we are seeing here.

The main problem is indeed with 404s, primarily in development. This is because a browser makes a request for a dev resource which used to exist, but now has been cleared by HMR. Eg:

http://localhost:3000/_next/static/webpack/f15dd305991bb90f87e1.hot-update.json

This request goes through the next-i18next middleware first, and as far as we are concerned, this is a request for a static resource and has a statusCode of 200 (has not been modified yet). The default behaviour here is to exclude static resources from i18next-express-middleware, thus req.i18n shouldn't exist on this request.

The request then gets passed to NextJs:

const handle = app.getRequestHandler()
server.get('*', (req, res) => handle(req, res))

At this point the request is determined to be a 404, and the status code is changed. At that point in time, NextJs wants to render an error page, but does so without a redirect (naturally), so the next-i18next middleware never gets called again, and we do not have a chance to populate the i18n instance.

That NextJs logic can be found here.

(It's noteworthy that this code path is different than "normal", non-resource, 404s which next-i18next handles just fine.)

The curious part is how react-i18next ever gets to the point of calling hasLoadedNamespace, as i18n.isInitialized is a precondition of that call, and i18n shouldn't exist on that req at all. Still not sure about this, but it's relatively unimportant.

In general this is a bit of a chicken-and-egg problem to solve. The easy thing to do is to remove the passing of ignoreRoutes to i18next-express-middleware, seen here.

The actual redirect logic is protected by isI18nRoute which uses the exact same
ignoreRoutes array, so we actually don't have to worry about static resources being redirected when users have enabled localeSubpaths.

However, this solution would mean that we are processing all our static resource requests through the i18next middleware, just on the off chance that one of them results in a 404. Perhaps this is actually the right thing to do? No idea if this has perf implications, but it probably does.

On a side note, I have no idea why the NextJs team have decided to return an HTML doc for a 404 on a JSON resource - that doesn't seem right to me. Not sure if that's configurable.

Apologies for a long post, but that's the entire story. We have all the information necessary to work on this, it's just a matter of discussing amongst ourselves what makes the most sense.

Open for discussion.

@pdandradeb
Copy link

Thanks to OP and @isaachinman for taking time to check this issue.

Finally took some time to dig into this. The issue of awaiting the initialisation of the i18next instance is a very trivial one, and I can provide an easy, non-breaking way for users to do that if they want to. However, I think that that race condition is causing a very low percentage of the error reports we are seeing here.

What would be the quick-fix?

Thanks

@isaachinman
Copy link
Contributor

There is no "quick-fix" in user land, it needs to happen within the source code.

@GraxMonzo
Copy link

GraxMonzo commented Oct 24, 2019

I get this problem when I use public/static path instead of static/locales. Removing public folder and setting up localePath to default value fixes the problem

My locales folder:

.
└── public
    └── static
        └── locales
            ├── ru
            |   └── common.json
            └── kk
                └── common.json

Instance:

const NextI18NextInstance = new NextI18Next({
  localePath: 'public/static/locales',
  preload: ['ru'],
  defaultLanguage: 'ru',
  otherLanguages: ['kk'],
  localeSubpaths: {
    ru: 'ru',
    kk: 'kk'
  }
});

@mercteil
Copy link

mercteil commented Oct 25, 2019

@GraxMonzo

localePath: typeof window === 'undefined' ? 'public/static/locales' : 'static/locales'

@i18next i18next locked as resolved and limited conversation to collaborators Oct 25, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
bug Something isn't working help wanted Extra attention is needed
Projects
None yet