next-i18next icon indicating copy to clipboard operation
next-i18next copied to clipboard

react-i18next:: You will need to pass in an i18next instance by using initReactI18next when running build when there is translation in top level layout

Open bryanprimus opened this issue 2 years ago • 39 comments

🐛 Bug Report

image

This is only happening when I run build script and my layout call useTranslation hook

To Reproduce

A small repo to reproduce

  • clone the repo, install deps
  • run pnmp run build you'll see the warning

This is the only place I call useTranslation hook

// My _app.tsx
import "../styles/globals.css";
import type { AppProps } from "next/app";
import { appWithTranslation, useTranslation } from "next-i18next";
import React from "react";

function MyApp({ Component, pageProps }: AppProps) {
  return (
    <Layout>
      <Component {...pageProps} />
    </Layout>
  );
}

const Layout: React.FC<{ children: React.ReactNode }> = ({ children }) => {
  const { t } = useTranslation();

  return (
    <div>
      <div>{t("hello-world")}</div>
      {children}
    </div>
  );
};

export default appWithTranslation(MyApp);

my only page is pages/index.tsx

and I already called the serverSideTranslation

export async function getStaticProps({ locale }: any) {
  return {
    props: {
      ...(await serverSideTranslations(locale, ["common"])),
    },
  };
}

the translation is working, and I believe as mentioned here https://github.com/i18next/next-i18next/issues/1840#issuecomment-1145614232 image

the only issue is that there are warnings happen when running build

Expected behavior

There's no warning that says react-i18next:: You will need to pass in an i18next instance by using initReactI18next when running build script

Your Environment

  • runtime version: node v16.13.2,
  • next-i18next version: v11.3.0
  • os: Windows
  • next: latest

bryanprimus avatar Jul 24 '22 13:07 bryanprimus

Try to move the Layout component to a different file.

adrai avatar Jul 24 '22 13:07 adrai

serverSideTranslations should be in the same file where useTranslation is used, isn't it?

adrai avatar Jul 24 '22 13:07 adrai

Try to move the Layout component to a different file.

I used it in a different file when the warning happens. I moved it to _app.tsx just to make it easier to visualize, and I'm not sure there's a difference, it's just a component definition.

serverSideTranslations should be in the same file where useTranslation is used, isn't it?

not necessarily I think https://github.com/i18next/next-i18next/issues/1840#issuecomment-1145614232 since nextjs layout can't call serverSideTranslations in its own file

how next handle layout https://nextjs.org/docs/basic-features/layouts

bryanprimus avatar Jul 24 '22 13:07 bryanprimus

Then probably we have to live with that warning... The problem is, during build, the Layout component is rendered also if i18next is not initialized yet and not ready...

If you do this, you'll see what I mean. But I honestly have no idea how to prevent this in next.js, sorry.

const { t, ready } = useTranslation()
console.log(ready)
console.log(t('hello-world'))

adrai avatar Jul 24 '22 15:07 adrai

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

stale[bot] avatar Aug 12 '22 00:08 stale[bot]

Did you resolve this problem?

yuuk avatar Aug 19 '22 02:08 yuuk

not stale

bryanprimus avatar Aug 19 '22 03:08 bryanprimus

@yuuk I didn't

bryanprimus avatar Aug 19 '22 03:08 bryanprimus

I'm experiencing the same thing. For me it seems like an issue with bundling (by debugging stack traces) where the useTranslate context loses its reference. In this scenario, the provider is created in the environment of the Node.js process (non-bundle) and some translation attempts made afterwards are successful within that same environment. Suddenly, React tries to render a bundled version of the module and the knowledge about the context is lost.

I happen to have layout components (in which this problem occurs) in a separate package and I think it's simply a Webpack misconfiguration on my end.

edit: I upgraded Next.js from 10 to 12 and that resolved it for me. I now use Webpack 5 as well.

martinjlowm avatar Aug 26 '22 23:08 martinjlowm

Figured out why. It's because react-i18next is listed as a regular dependency and not a peer dependency. Using pnpm/yarn 2/3 introduces this issue. I can see from previous issues that it seems to be intended, but I would disagree. Forking the project for now to fix it in my case.

martinjlowm avatar Sep 01 '22 14:09 martinjlowm

Maybe just defining react-i18next in your dependencies will work for you? Then there's no need for a fork.

adrai avatar Sep 01 '22 14:09 adrai

Already have, however, the module resolution in a symlink setup does not function well in this case.

diff --git a/package.json b/package.json
index 02388f7e443548dc6e428429719346293099412c..cc1169a110b2b1cb53e81d78837cfec7a69570a3 100644
--- a/package.json
+++ b/package.json
@@ -130,12 +130,12 @@
     "core-js": "^3",
     "hoist-non-react-statics": "^3.3.2",
     "i18next": "^21.9.1",
-    "i18next-fs-backend": "^1.1.5",
-    "react-i18next": "^11.18.4"
+    "i18next-fs-backend": "^1.1.5"
   },
   "peerDependencies": {
     "next": ">= 10.0.0",
-    "react": ">= 16.8.0"
+    "react": ">= 16.8.0",
+    "react-i18next": "^11.18.4"
   },
   "resolutions": {
     "i18next": ">=21.8.14",

Have this patch if anyone's facing the same problem.


Well, turns out I was too quick to come to a conclusion. Pretty sure it works in development, but production builds would still fail. The server-bundle still has next-i18next references and will therefore continue to reference a different instance of react-i18next. I'm not entirely sure about PNPM internals, but even with the patch above and using https://pnpm.io/cli/patch, react-i18next would still be linked in the dependencies.

My workaround now is to transpile next-i18next and use resolve alias to force the same module instance:

const withNextTranspileModules = require('next-transpile-modules')(['next-i18next'], {
  resolveSymlinks: true,
  debug: false,
});

and

config.resolve.alias = config.resolve.alias || {};
config.resolve.alias['react-i18next'] = path.dirname(require.resolve('react-i18next/package.json'));

martinjlowm avatar Sep 01 '22 14:09 martinjlowm

I have the same problem but on a completely static next export project. I got the warning when running it and when building it, even though it works perfectly. I followed the SSG example and it works fine just with that error. It happens only on my header which is in my layout, exactly what happened to the OP. It obviously has to due to the fact that it is outside of <Component> but since you can't really getStaticProps on a regular component I guess that's it.

Haven't found a solution yet but not worrying for now since I don't see any bugs, but worried that something might happen in the future lol.

Using NextJS 12.2.5 and next-i18next on 12.0.0.

bojackhorseman0309 avatar Sep 02 '22 20:09 bojackhorseman0309

I think I'm getting the same problem, with Yarn 3 and PnP. My scenario is I have a NextJS app and a component library built with react-i18next and packaged separately - same as @martinjlowm. next-i18next works fine for NextJS pages, but components from my package don't seem to find the I18NextProvider and I get react-i18next:: You will need to pass in an i18next instance by using i18nextReactModule in my console.

Unfortunately I couldn't get @martinjlowm 's workaround to work for me, I got Critical dependency: the request of a dependency is an expression from i18next-node-fs-backend (maybe related https://github.com/i18next/i18next-node-fs-backend/issues/228)

rikkit avatar Sep 15 '22 14:09 rikkit

I think I'm getting the same problem, with Yarn 3 and PnP. My scenario is I have a NextJS app and a component library built with react-i18next and packaged separately - same as @martinjlowm. next-i18next works fine for NextJS pages, but components from my package don't seem to find the I18NextProvider and I get react-i18next:: You will need to pass in an i18next instance by using i18nextReactModule in my console.

Unfortunately I couldn't get @martinjlowm 's workaround to work for me, I got Critical dependency: the request of a dependency is an expression from i18next-node-fs-backend (maybe related i18next/i18next-node-fs-backend#228)

i18next-node-fs-backend is deprecated and replaced by i18next-fs-backend... make sure you have updated all i18next dependencies first

adrai avatar Sep 15 '22 14:09 adrai

I shouldn't have written that context in the message, it's distracting. The error came from the workaround.

@adrai can you comment on the workflow where second package uses react-i18next? How should that instance be initialised?

rikkit avatar Sep 15 '22 15:09 rikkit

I shouldn't have written that context in the message, it's distracting. The error came from the workaround.

@adrai can you comment on the workflow where second package uses react-i18next? How should that instance be initialised?

Can you create a minimal reproducible example that really differs from the one above?

adrai avatar Sep 15 '22 15:09 adrai

It's the exact same as the original post, except that Layout is in a separate package, and using Yarn with PnP to install the package.

rikkit avatar Sep 15 '22 15:09 rikkit

It's the exact same as the original post, except that Layout is in a separate package, and using Yarn with PnP to install the package.

https://github.com/i18next/next-i18next/issues/1917#issuecomment-1193339399

adrai avatar Sep 15 '22 15:09 adrai

So I went ahead and forked the project, changed i18next and react-i18next to be peer dependencies, and published it: @rikkilt/next-i18next

react-l18next 's I18NextProvider is now initialised as expected and the components in my library are getting translated.

It seems in order to support Yarn PnP, i18next and react-i18next need to be peer dependencies.

rikkit avatar Sep 15 '22 16:09 rikkit

So I went ahead and forked the project, changed i18next and react-i18next to be peer dependencies, and published it: @rikkilt/next-i18next

react-l18next 's I18NextProvider is now initialised as expected and the components in my library are getting translated.

It seems to support Yarn PnP that's what's required - move i18next and react-i18next to be peer dependencies.

If this is ok for all, and there is no other negative impact, I'm ready to accept a PR and create a new release.

Please let me know...

adrai avatar Sep 15 '22 16:09 adrai

The only downside I can see is that people will have to install react-i18next and i18next separately:

yarn add next-i18next react-i18next i18next 

Otherwise there should be no functional differences (for non PnP users)

I'll make a PR soon and see if there are any docs that need to be updated in the repo 👍

rikkit avatar Sep 15 '22 17:09 rikkit

The only downside I can see is that people will have to install react-i18next and i18next separately:


yarn add next-i18next react-i18next i18next 

Otherwise there should be no functional differences (for non PnP users)

I'll make a PR soon and see if there are any docs that need to be updated in the repo 👍

This will probably still be an issue in production: https://github.com/i18next/next-i18next/issues/1917#issuecomment-1234347869

adrai avatar Sep 15 '22 18:09 adrai

@adrai I've deployed my app with my forked package to Vercel ("production mode"), and it's working as expected. So I've sent a PR. 👍

I think the problem in the comment you linked relates to pnpm patching (which I don't know about).

rikkit avatar Sep 15 '22 23:09 rikkit

@martinjlowm @bryantobing12 can you confirm?

adrai avatar Sep 16 '22 05:09 adrai

also @kachkaev @capellini can you tell us your opinion, since https://github.com/i18next/next-i18next/issues/136 was already discussed in 2019

adrai avatar Sep 16 '22 05:09 adrai

Reading #136, I see this comment from @isaachinman

However, for advanced use cases, I believe that users may still need to use i18next

What cases? If there are situations where users need to install and import i18next directly, that probably means we've failed to > expose some part of the API.

The case is outlined above; using next-i18next and react-i18next in the same project with Yarn PnP.

I was thinking about it and an alternative solution could be to allow the user to provide the i18n instance, so that the instance created for react-i18next can be passed to next-i18next directly. I see there's a "global" i18n instance referred to in appWithTranslation - this function could be extended to allow passing in an i18n instance. I am not sure if I18nProvider would also need to be passed in, or if it's fine for one i18n to be shared between two separate providers.

rikkit avatar Sep 16 '22 10:09 rikkit

I decided to drop next-i18next altogether due to the lack of language detection support (pass on lng config on the client) and go with the custom solution I was using previously. However, it being a peer seems sane to me.

I think my findings from pnpm patching is that it's done after dependency installation, so the patch essentially doesn't do anything useful.

martinjlowm avatar Sep 18 '22 09:09 martinjlowm

I've run into a similar issue with the following projects structure:

- NextJS App (uses next-i18next)
- Create React App (uses react-i18next)
- Shared Components Package (uses react-i18next)

I want to be able to import the Shared Components Package in both the CRA and NextJS apps, but using useTranslation from react-i18next directly in a NextJS app does not work. The translations never become ready = true and the NextJS logs display the following error:

react-i18next:: You will need to pass in an i18next instance by using initReactI18next

matthewwolfe avatar Sep 20 '22 15:09 matthewwolfe

@adrai

Then probably we have to live with that warning... The problem is, during build, the Layout component is rendered also if i18next is not initialized yet and not ready...

If you do this, you'll see what I mean. But I honestly have no idea how to prevent this in next.js, sorry.

const { t, ready } = useTranslation()
console.log(ready)
console.log(t('hello-world'))

Because of the separate instance of react-i18next, ready never becomes true.

matthewwolfe avatar Sep 20 '22 15:09 matthewwolfe