I'm experiencing the react-i18next Hydration Error when refreshing or redirecting to pages between language toggles.
Hydration failed because the server rendered text didn't match the client.
As a result this tree will be regenerated on the client. This can happen if a SSR-ed Client Component used:
However, the recommended solution of upgrading to next-18next doesn't work for me. It requires the appWithTranslation(App) enclosure which we're unable to provide due to our layout.tsx approach.
Per Google,
The appWithTranslation HOC is not compatible with the App Router's layout.tsx because Server Components do not support HOCs in the same way. Instead, next-i18next (v16+) or libraries like next-intl use a different pattern.
Due to the Layout-based layout.tsx approach, our App component looks like
const App = (props: {page: string}) => { .. }
rather than
const App = ({ Component, pageProps }: AppProps) => { .. }
and this creates errors with appWithTranslation.
Is there a way to get rid of this error without upgrading to next-18next?
Current code: initTranslations hook:
export default async function initTranslations(
locale: any,
namespaces: string[],
i18nInstance?: any,
) {
i18nInstance = i18nInstance || createInstance();
i18nInstance.use(initReactI18next);
i18nInstance.use(LanguageDetector);
await i18nInstance.init({
lng: locale,
detection: options,
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
};
Then we have a TranslationsProvider component:
export default function TranslationsProvider({
children,
locale,
namespaces,
}: Readonly<{
children: React.ReactNode;
locale: string;
namespaces: string[];
}>) {
const i18n = createInstance();
initTranslations(locale, namespaces, i18n);
return {children} ;
}
and e.g. the Home Page uses it as follows:
export default function Home() {
const params = useParams<{ locale: string}>();
return (
);
}