Next.JS 14 app router i18next
Unanswered
Tonkinese posted this in #help-forum
TonkineseOP
I have this next.js 14 project that i am working on, and i want to add internalization.It works great when i go to the domain name page,without my routes , for example :
localhost:3000/en
localhost:300/sr
but when i go lets say to locahost:3000/sr/about-us ,it works well, but when i reload the page, it doesnt recognize my translations ,it gives me this in client console :
-------------------------------------------------------------------------------------------
Error: Text content does not match server-rendered HTML.
Warning: Text content did not match. Server: "HOME" Client: "header:menuHome"
See more info here: https://nextjs.org/docs/messages/react-hydration-error
-------------------------------------------------------------------------------------------
and in terminal i got this :
-------------------------------------------------------------------------------------------
react-i18next:: You will need to pass in an i18next instance by using initReactI18next
-------------------------------------------------------------------------------------------
These are my components (About-us route,and page.tsx main file,see the images):
Do i need to add Translation providers to every route also?
localhost:3000/en
localhost:300/sr
but when i go lets say to locahost:3000/sr/about-us ,it works well, but when i reload the page, it doesnt recognize my translations ,it gives me this in client console :
-------------------------------------------------------------------------------------------
Error: Text content does not match server-rendered HTML.
Warning: Text content did not match. Server: "HOME" Client: "header:menuHome"
See more info here: https://nextjs.org/docs/messages/react-hydration-error
-------------------------------------------------------------------------------------------
and in terminal i got this :
-------------------------------------------------------------------------------------------
react-i18next:: You will need to pass in an i18next instance by using initReactI18next
-------------------------------------------------------------------------------------------
These are my components (About-us route,and page.tsx main file,see the images):
Do i need to add Translation providers to every route also?
23 Replies
Komondor
can you show us the About component too
TonkineseOP
Komondor
You don't have any translations in that file?
TonkineseOP
No, i dont know how to set it up, when i use this :
import { useTranslation } from 'react-i18next';
along with this :
const { t } = useTranslation();
it gives me error!
Do i need to add this :
import initTranslations from '../i18n'
import { useTranslation } from 'react-i18next';
along with this :
const { t } = useTranslation();
it gives me error!
Do i need to add this :
import initTranslations from '../i18n'
I am not sure wether i need to initialize new i18next instance for each route with this :
const {t,resources} =await initTranslations(locale,i18NameSpaces)
const {t,resources} =await initTranslations(locale,i18NameSpaces)
It works all perfectly for page.tsx, but not for other routes
TonkineseOP
This is the error when i add useTranslation to AboutPage compnent
TonkineseOP
Now when i did add initTranslations from i18n file , now i do see the translation but still got hydration error :
here is the video output :
here is the video output :
Also this is when i reload the home page(page.tsx file) and when i reload the other routes (ex. about-us route):
Komondor
In my provider set up, I"m not using params.i18nNamespaces, instead I'm doing this
const i18nNamespaces = ['*'];
const i18nNamespaces = ['*'];
because my config looks like this:
import { createInstance } from 'i18next';
import { initReactI18next } from 'react-i18next/initReactI18next';
import resourcesToBackend from 'i18next-resources-to-backend';
import i18nConfig from '@/i18nConfig';
export default async function initTranslations(
locale,
namespaces,
i18nInstance = null,
resources = null
) {
i18nInstance = i18nInstance || createInstance();
i18nInstance.use(initReactI18next);
if (!resources) {
i18nInstance.use(
resourcesToBackend(
(language: string, namespace: string) =>
import(`@/src/dictionaries/${language}.json`)
)
);
}
await i18nInstance.init({
lng: locale,
resources,
fallbackLng: i18nConfig.defaultLocale,
supportedLngs: i18nConfig.locales,
defaultNS: namespaces[0],
fallbackNS: namespaces[0],
ns: namespaces,
preload: resources ? [] : i18nConfig.locales
});
return {
i18n: i18nInstance,
resources: i18nInstance.services.resourceStore.data,
t: i18nInstance.t
};
}^ that's my i18n.ts file
here is my i18nConfig.js file
const i18nConfig = {
locales: ['en', 'es'],
defaultLocale: 'en'
};
module.exports = i18nConfig;TonkineseOP
import { createInstance } from 'i18next';
import { initReactI18next } from 'react-i18next/initReactI18next';
import resourcesToBackend from 'i18next-resources-to-backend';
import i18nConfig from '../../i18nConfig'
export default async function initTranslations(
locale,
namespaces,
i18nInstance,
resources
) {
i18nInstance = i18nInstance || createInstance();
i18nInstance.use(initReactI18next);
if (!resources) {
i18nInstance.use(
resourcesToBackend(
(language, namespace) =>
import(`../../locales/${language}/${namespace}.json`)
)
);
}
await i18nInstance.init({
lng: locale,
resources,
fallbackLng: i18nConfig.defaultLocale,
supportedLngs: i18nConfig.locales,
defaultNS: namespaces[0],
fallbackNS: namespaces[0],
ns: namespaces,
preload: resources ? [] : i18nConfig.locales
});
return {
i18n: i18nInstance,
resources: i18nInstance.services.resourceStore.data,
t: i18nInstance.t
};
}This is my code
**And we have the same i18nConfig.js file!
TonkineseOP
This is my TranslationsProvider:
'use client';
import { I18nextProvider } from 'react-i18next';
import initTranslations from '@/app/i18n';
import { createInstance } from 'i18next';
export default function TranslationsProvider({
children,
locale,
namespaces,
resources
}) {
const i18n = createInstance();
initTranslations(locale, namespaces, i18n, resources);
return <I18nextProvider i18n={i18n}>{children}</I18nextProvider>;
}TonkineseOP
let me ask you this!:
Do i need to wrap each page in Translations Provider ? and how do we pass in i18next instance to all routes
Do i need to wrap each page in Translations Provider ? and how do we pass in i18next instance to all routes
Komondor
no you only need the translations provider in the root layout.
You instantiate the i18next instance when you need it.
Example on server component:
You instantiate the i18next instance when you need it.
Example on server component:
import initTranslations from 'i18n';
export default async function Page({params}: {params: {locale: string}}) {
const { t } = await initTranslations(params.locale, ['*']);example on client component:
import { useTranslation } from 'react-i18next';
export default function SomeComponent(props: Props) {
const searchParams = useSearchParams();
const { t } = useTranslation();example root layout
import 'i18n';
import TranslationsProvider from 'src/components/TranslationsProvider';
import initTranslations from '@/i18n';
export default async function RootLayout({ children, params }: { children: React.ReactNode, params: {locale: string} }) {
const i18nNamespaces = ['*'];
const { t, resources } = await initTranslations(params.locale, i18nNamespaces);
return (
<html lang={params.locale}>
<head>
<Script async src="https://js.stripe.com/v3/pricing-table.js" />
<ColorSchemeScript />
<meta
name="description"
content="Services in your area"
key="desc"
/>
</head>
<body>
<NextAuthProvider>
<MantineProvider theme={theme}>
<TranslationsProvider
namespaces={i18nNamespaces}
locale={params.locale}
resources={resources}
>
{children}
</TranslationsProvider>
</MantineProvider>
</NextAuthProvider>
</body>
</html>
);
}TonkineseOP
Thank you ,i will look into this ,tomorrow ..💚