i18next / next-i18next

The easiest way to translate your NextJs apps.
https://next.i18next.com
MIT License
5.5k stars 761 forks source link

You are passing a wrong module! Please check the object you are passing to i18next.use() #1319

Closed Mar-he closed 3 years ago

Mar-he commented 3 years ago

I've tried copying over my working proof of concept into a real world app and encountered the following error:

You are passing a wrong module! Please check the object you are passing to i18next.use()

next-i18next-config.js:

const HttpBackend = require('i18next-http-backend')
module.exports = {
    i18n: {
        defaultLocale: 'de',
        locales: ['de', 'en'],
        backend: {
            loadPath: `${process.env.NEXT_PUBLIC_API_URI}/api/locales/{{lng}}/{{ns}}`
        },
    },
    debug: true,
    ns: ["common"],
    serializeConfig: false,
    use: [HttpBackend],
}

_app.tsx

import type { AppProps } from 'next/app'
import { MsalProvider } from "@azure/msal-react"
import { msalApp } from '../auth/authProvider'
import PageLayout from './layout'

/*i18n */
import { appWithTranslation } from 'next-i18next'
import nexti18nextConfig from '../../next-i18next.config'

const MyApp = ({ Component, pageProps }: AppProps) => {

  return (
    <>
      <MsalProvider instance={msalApp}>
        <PageLayout>
          <Component {...pageProps} />
        </PageLayout>
      </MsalProvider>
    </>
  )
}

export default appWithTranslation(MyApp, nexti18nextConfig)

employees.tsx

[import { useTranslation } from 'next-i18next';

import { serverSideTranslations } from 'next-i18next/serverSideTranslations'

export default function Home(props) {
  const { t } = useTranslation('common')
  return (
    <>
      <Head>
        <title>{t('Startseite')}</title>
        <link rel="icon" href="/favicon.ico" />
      </Head>
      <Space direction="vertical" style={{ width: "100%" }}>
        <EmployeeContextProvider>
          <Search />
          <NewEmployee ></NewEmployee>
          <EmployeeTable />
        </EmployeeContextProvider>
      </Space>
    </>
  )
}

export async function getStaticProps({ locale }) {
  return {
    props: {
      ...(await serverSideTranslations(locale, ['common'])),
      // Will be passed to the page component as props
    },
  };
}]

looking at the debug view I can see, that the resources are acutally loaded from the api:

i18next::backendConnector: loaded namespace common for language de { 'Startseite': 'Startseite (api, de)' }
i18next::backendConnector: loaded namespace common for language en { 'Startseite': 'Homepage (api, en)' }

If I remove the backend configuration, it retrieves the key-value-pairs from the locale json file at /public/locales/de/common.json, but with the http backend in place it fires off the error.

Any help is greatly appreciated.

Update it looks like this is due to a custom webpack configuration. If I go with the default next.config.js and just do

module.exports = {
    i18n,
}

it simply works. But since we need less support, we are still on the old withCSS / withLess hacks and fallback to webpack4:

module.exports = withCSS({
  i18n,
  cssModules: true,
  cssLoaderOptions: {
    importLoaders: 1,
    localIdentName: "[local]___[hash:base64:5]",
  },
  ...withLess(
    {
      lessLoaderOptions: {
        javascriptEnabled: true,
      },

      webpack: (config, { isServer }) => {
        if (isServer) {
          const antStyles = /antd\/.*?\/style.*?/;
          const origExternals = [...config.externals];
          config.externals = [
            (context, request, callback) => {
              if (request.match(antStyles)) return callback();
              if (typeof origExternals[0] === "function") {
                origExternals[0](context, request, callback);

              } else {
                callback();
              }
            },
            ...(typeof origExternals[0] === "function" ? [] : origExternals)
          ];

          config.module.rules.unshift({
            test: antStyles,
            use: "null-loader"
          });
        }
        return config;
      }
    }
  ),
});

and with this config, the error can be reliably reproduced.

adrai commented 3 years ago

import i18next-http-backend like this:

const HttpBackend = require('i18next-http-backend/cjs')

Mar-he commented 3 years ago

Would you please explain why? I have a working minimal example, that imports it without /cjs. Why would I now import it like this and what is the difference?

adrai commented 3 years ago

I don't know the exact reason, but next.js seems to import certain esm modules in a strange way... with /cjs it forces to load the commonjs export.

Mar-he commented 3 years ago

I currently have a workaround in place, that explicitly sets the type as backend:

const HttpBackend = require('i18next-http-backend')
HttpBackend.type = 'backend'

I don't know why this works, as the static property on the Backend is set explicitly in the sourcecode of the plugin already, but it convinces next-i18next to successfully load it. I'll try your suggestion tomorrow and report back.

adrai commented 3 years ago

I don't think this will really work... it will just supress the warning...

Mar-he commented 3 years ago

Oh, it did work - but I like your solution more. Thank you for the clarification and help!

hey-jk commented 1 year ago

@adrai what a surprise!! Thank you so much!