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

No i18n object while server rendering #1668

Closed
gritaliana opened this issue Feb 4, 2022 · 19 comments
Closed

No i18n object while server rendering #1668

gritaliana opened this issue Feb 4, 2022 · 19 comments

Comments

@gritaliana
Copy link

gritaliana commented Feb 4, 2022

Describe the bug

In a component which has a locale selector I am using import { i18n } from 'next-i18next'.
And in render method I am using i18n.language. But while server rendering there is no i18n object.

Therefore a component is producing a TypeError: Cannot read properties of null (reading 'language').

But in your migration doc it is said:

The object i18n which was imported directly from i18n.js in next-i18next@<8 suppored only client-side-rendering. Now in the v8 the i18n object also supports server-side rendering. So you can use the i18n.language for server-side rendered elements.

How should I access to i18n object?
Because I also have utils files, or use translation strings in mobx stores. How should I access the t function though?

Occurs in next-i18next version

The latest next-i18next package - 10.2.0, along with Next updating to v.12

Steps to reproduce

I have migrated configuration due to the docs:

next-i18next.config.js

module.exports = {
  i18n: {
    defaultLocale: 'en',
    locales: ['en', 'pt-BR', 'de'],
  },
  defaultNS: 'common',
  fallbackLng: 'en',
  localeDetection: false,
  reloadOnPrerender: isLocalEnv,
  saveMissing: true,
  serializeConfig: false,
  use: [i18nextMiddleware.LanguageDetector],
  detection: {
    caches: ['cookie'],
    lookupCookie: 'i18next',
    order: ['cookie', 'path', 'header'],
  },
}

next.config.js


const { i18n } = require('./next-i18next.config')
module.exports = { i18n }

Then I wrap the _app.js component, need to handle config due to unserialisable config:

export default appWithTranslation(withMobx(getStores)(MyApp), nextI18NextConfig)

And in index.js page provide new syntax with serverSideTranslations also with next config as the second param.
I can use import { useTranslation } from 'next-i18next' - it works.

But no access to i18n object.

OS (please complete the following information)

  • Device: macOS
  • Browser: Chrome
@neverether
Copy link

neverether commented Feb 7, 2022

+1

I noticed this issue for the first time upgrading from nextjs 12.0.7 to 12.0.9.

Unlike the OP we were previously able to access the i18n object from the useTranslation() hook by doing:

const { i18n } = useTranslation("ns")

Upon updating we were getting the same type error as OP: language would be returned as undefined.

We had stored a users' language in localStorage for another feature so we bypassed this issue by leveraging the localstorage value instead of i18n.language but we're less able to react to language changes because of it.

@isaachinman
Copy link
Contributor

@gritaliana Please see an answer to the global i18n client question here. In general it will be null at time of import, but should be initialised very quickly at runtime, including during SSR/SSG.

@neverether That's interesting, and @gritaliana has also mentioned using NextJs v12, although they didn't mention the specific version. Have you been able to track this down to a single version (or even better, a canary)?

Anecdotally I have seen a lot of issues with NextJs v12 across the board.

@gritaliana
Copy link
Author

I see, yes - the i18n object is initialised quickly at runtime. Thank you for your answer!

@isaachinman Although I have another question. Maybe you could give an idea for solution. It is said on Next docs that custom Error page do not accept new Data Fetching functions and only work with old getInitialProps.

Caveats
Error does not currently support Next.js Data Fetching methods like getStaticProps or getServerSideProps.

Here is the question: how then should I provide a translation in custom _error.js? If your library do not work with getInitiailProps anymore?

@isaachinman
Copy link
Contributor

Regarding the 404/error page, there have been several previous discussions: #1058, #1235. Check the note:

Screenshot 2022-02-10 at 11 23 16

@gritaliana
Copy link
Author

This is not exactly what I needed. We are using Error page for other errors, not 404 or 500. To show custom message for unauthorised error, for example.

And as it is described in #1058 is not working.
getStaticProps in _error.js gives an error.

@isaachinman
Copy link
Contributor

@gritaliana That is a separate issue, and can be handled separately.

@MailboxArsonist
Copy link

MailboxArsonist commented Apr 5, 2022

Regarding the 404/error page, there have been several previous discussions: #1058, #1235. Check the note:

Screenshot 2022-02-10 at 11 23 16

@isaachinman
This seems to be the case regarding the 404 page but the docs state that getServerSideProps and getStaticProps aren't supported on custom error pages. What would be the recommended approach to load translations in this case?

https://nextjs.org/docs/advanced-features/custom-error-page#:~:text=Error%20does%20not,%60src%60%20Directory

Thanks

@isaachinman
Copy link
Contributor

@MailboxArsonist One option would be to use this functionality.

@iDVB
Copy link

iDVB commented Apr 28, 2023

I see, yes - the i18n object is initialised quickly at runtime. Thank you for your answer!

Sorry to reopen the original OP issue, but I think I missed what the fix was?
We also have export default appWithTranslation(MyApp)

and in our page layout Layout.js we're doing the below but language is undefined only on the server. On the client it works fine. So we are getting a hydration error about them not matching.

const Layout = ({ children }) => {
  const { i18n } = useTranslation()
  const language = i18n.language

  console.log({ language })

  return (
    <Page className={`lang-${language}`}>
      <SkipToContentBar />
      <Header siteTitle={siteMetadata.title} />
      <Main id="main-content">{children}</Main>
      <Footer divider={false} noLocalPage={['contact']} />
      <AccessibilityDialog />
    </Page>
  )
}

@adrai
Copy link
Member

adrai commented Apr 28, 2023

@iDVB make sure you called serverSideTranslations...

@iDVB
Copy link

iDVB commented Apr 28, 2023

Thanks @adrai .... but I think I'm still confused.
Are we then not supposed to ever get the current language this way?

import { useTranslation } from 'next-i18next'
...
const { i18n } = useTranslation()
const { language, changeLanguage } = i18n

getStaticProps + serverSideTranslations seems to allow us to pass locale into the page. But what about any other component (especially deeply nested ones) that would normally just get the current language using context?
Does this mean we have to either prop-drill that local from the page OR setup a whole new context just for this?
Both seem excessive.

@adrai
Copy link
Member

adrai commented Apr 28, 2023

@iDVB
Copy link

iDVB commented Apr 28, 2023

Sorry @adrai , what I'm seeing when implemented is not what I understood from your guidence above.
It appears that we do not need to prop-drill that locale prop.

Simply doing this...

export async function getStaticProps({ locale }) {
  return {
    props: {
      ...(await serverSideTranslations(locale)),
    },
  }
}

is fixing that issue where any component nested at any level below to HAVE a value for i18n.language

  const { i18n } = useTranslation()
  const { language, changeLanguage } = i18n

where as this used to be undefined. I guess I don't understand what is happening under the covers to make this true.

@adrai
Copy link
Member

adrai commented Apr 28, 2023

serverSideTranslations is just needed on page level

@iDVB
Copy link

iDVB commented Apr 28, 2023

Thanks @adrai
Still seeing unexpected results though.
Can I just ask a few direct questions...

Are we supposed to use i18n.language and i18n.changeLanguage('some locale') at any nest level and it should work?

  const { i18n } = useTranslation()
  const { language, changeLanguage } = i18n

I'm seeing the initial default language coming through language now that I've added serverSideTranslations to the page. However, changeLanguage() doesn't seem to do anything. It does not cause a re-render and language of course then stays the same.

@adrai
Copy link
Member

adrai commented Apr 28, 2023

For next.js projects I never use changeLanguage... I always use a route redirect....
like this:

<Link href="/second-page">

or like this:
router.push({ pathname, query }, asPath, { locale: newLocale })

using changeLanguage() would nevertheless only work on client side... btw. I would always recommend to use i18n.resolvedLanguage in that case: https://www.i18next.com/overview/api#resolvedlanguage

In general, if you have an issue with next-i18next... create a minimal reproducible example and open a new issue... and to ask general questions you may ask at stackoverflow...

@iDVB
Copy link

iDVB commented Apr 28, 2023

Thanks, yes what we have now works in GatsbyJS with raw react-i18n it's just gettting the same to work with next-i18n that seems to be a bit of a task.

We indeed need to be able to change the language as we are doing so in a language picker component.
Thus, this only ever needs to work on the client.

Not sure what you are meaning in using i18n.resolvedLanguage?

The docs sound similar to me between resolvedLanguage and language

If you need the primary used language depending on your configuration (supportedLngs, load) you will prefer using
i18next.resolvedLanguage or i18next.languages[0].

additionally, I don't see any mention of how to change the language in the next-i18n docs. Would be great to understand how we are supposed to adapt our code that currently works fine with changeLanguage and react-i18n. I'd be happy to submit a PR to update the docs for the details once I understand them.

@adrai
Copy link
Member

adrai commented Apr 28, 2023

This may help to understand: 6ddb2d0

Please compare your code with this example: https://github.com/i18next/next-i18next/tree/master/examples/simple

@iDVB
Copy link

iDVB commented Apr 28, 2023

Got it!
Sorry @adrai , I missed those examples but now looking at them in detail I see this other method and it does appear to work for our use-case. Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants