next-i18next: getInitialProps is not called unless _app.js extends next/app

Describe the bug

getInitialProps is not called unless _app.js extends App from next/app. This prevents namespace splitting from working. This is a bug with next-i18next because next doesn’t require App to be extended; next will call getInitialProps even when using a function component for _app.js. There examples use a function: https://nextjs.org/docs/advanced-features/custom-app

Occurs in next-i18next version

v4.0.0

Steps to reproduce

export a function component from _app.js instead of a class component that extends next/app.

Expected behaviour

I recognize that the docs for next-i18next use a class component, but it’s not obvious that doing so is required, and perhaps it shouldn’t be required since next doesn’t require it.

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Reactions: 2
  • Comments: 19 (4 by maintainers)

Most upvoted comments

So, I looked into this a bit. While there may indeed be issues ahead with hoisting, the main problem here is with the existence of getInitialProps on the _app component.

The example in this repo works, because extending next/app will add in a getIntialProps that then calls the actual page-level getInitialProps.

In fact, if you follow the second example in the exact NextJs docs that you linked to, you’ll find that everything works as expected:

import React from 'react'
import App from 'next/app'
import { appWithTranslation } from '../i18n'

function MyApp({ Component, pageProps }) {
  return <Component {...pageProps} />
}

MyApp.getInitialProps = async (appContext) => {
  const appProps = await App.getInitialProps(appContext)
  return { ...appProps }
}

export default appWithTranslation(MyApp)

@isaachinman Is there a way to inject it in a lower-level component but not _app, because when wrapping _app with appWithTranslation it opted-out of Automatic Static Optimization. (Mind that I have tried to use it in a Main component which its a wrapper for navbar and pages, but did not work, it gives me the error http://localhost:5000/src/server/locales/ru/common.json 404 (Not Found))

Modifying _app.js solved the issue I was having with trying to integrate next-i18next with next-with-apollo. Lucky I found this thread!

import App from 'next/app';

const MyApp = ({ Component, pageProps, apollo }) => (
  <ApolloProvider client={apollo}>
    <Component {...pageProps} />
  </ApolloProvider>
);

MyApp.getInitialProps = async (appContext) => {
  const appProps = await App.getInitialProps(appContext);
  return { ...appProps };
};

export default withApollo(appWithTranslation(MyApp));

Works the same way with withTranslation inside a certain page:

export default withApollo(withTranslation()(Collections));

@orifmilod same question to community! How next.js docs (https://nextjs.org/docs/advanced-features/custom-app) say:

Only uncomment this method if you have blocking data requirements for // every single page in your application. This disables the ability to // perform automatic static optimization, causing every page in your app to // be server-side rendered. // MyApp.getInitialProps = async (appContext) => { // // calls page’s getInitialProps and fills appProps.pageProps // const appProps = await App.getInitialProps(appContext); // // return { …appProps } // }

Any ideas? Please!

So, I looked into this a bit. While there may indeed be issues ahead with hoisting, the main problem here is with the existence of getInitialProps on the _app component.

The example in this repo works, because extending next/app will add in a getIntialProps that then calls the actual page-level getInitialProps.

In fact, if you follow the second example in the exact NextJs docs that you linked to, you’ll find that everything works as expected:

import React from 'react'
import App from 'next/app'
import { appWithTranslation } from '../i18n'

function MyApp({ Component, pageProps }) {
  return <Component {...pageProps} />
}

MyApp.getInitialProps = async (appContext) => {
  const appProps = await App.getInitialProps(appContext)
  return { ...appProps }
}

export default appWithTranslation(MyApp)

Thank you! It works for me. My code:

type Props = {
  topMenu: TopNavigatorType[]
} & AppProps
function MyApp({ Component, pageProps, topMenu }: Props): JSX.Element {
  return (
    <>
      <AppProvider value={{ menu: topMenu }}>
        <Component {...pageProps} />
      </AppProvider>
      <script src="/lib/baidu.qiao.js" async defer />
    </>
  )
}

type Init = {
  topMenu: TopNavigatorType[]
} & AppInitialProps

MyApp.getInitialProps = async (appContext: AppContextType<Router>) => {
  const topMenu = await request.get(NAVIGATION)
  const appProps = await App.getInitialProps(appContext)
  const props: Init = { topMenu: topMenu.data, ...appProps }
  return { ...props }
}

export default MyApp

Not entirely sure, what I am facing here:

Screenshot 2020-12-01 at 10 12 45

Alrighty… I know what I did wrong here. Kept getting these errors, but again, as mentioned countless times over and over “Read the Docs carefully”.

First mistake in my case, looking at the 404.tsx file. I am importing withTranslation from next-i18next. This was done automatically by VSCode, so didn’t think more of it, but in reality, this should be fetched from your custom i18n.ts file. So it should actually read import { withTranslation } from '@/lib/i18n';.

Now - I would then realise I would face another issue, but that is solely due to Next.js. https://github.com/vercel/next.js/blob/master/errors/404-get-initial-props.md

Next.js does not permit getInitialProps for the custom 404.tsx file as this should serve 100% as a static file for fast delivery. Since I am not able to pass initial props to 404, then I would again get the missing namespacesRequired array warning in the console. I reckon we could either detect the filename and not display the warning as a condition thereof, or we should link to a solution on how to use the _error.tsx instead of having a static 404 file.