[Fixed] NextJS+NextI18Next hydration error when trying to map through array: "Text content does not match server-rendered HTML" – Hydration

by
Ali Hasan
hydration next-i18next next.js13 react-i18next server-side-rendering

Quick Fix: Import useTranslation from next-i18next and wrap your entry component App with appWithTranslation to enable hydration of server-rendered data.

The Problem:

In a Next.js app using Next-i18next for localization, an array of objects is passed as props to a custom BannerCarousel component, and the component maps through the array to create its content. The data for the carousel items is loaded through t('home:banner-carousel', { returnObjects: true }) in the getServerSideProps function. However, when the page is rendered, the client-side content does not match the server-rendered HTML, resulting in the following error: Text content does not match server-rendered HTML. Despite attempts to address the issue, such as using a useEffect with a boolean flag to gate the rendering of the carousel or loading the array through a separate instance of i18n.t(), the problem persists.

The Solutions:

Solution 1: Import UseTranslation from Next-i18next and Wrap App with AppWithTranslation

Ensure you import useTranslation from next-i18next rather than react-i18next. serverSideTranslations returns a customized object that includes the _nextI18Next property, which is why this is necessary.

To enable client-side hydration of server-rendered data, including _nextI18Next, wrap your entry component App with the appWithTranslation higher-order component. Here’s how it should look like:

//App.tsx
import { appWithTranslation } from 'next-i18next';

const App = () => {
  return <Home />;
};
export default appWithTranslation(App);

Q&A

Why do I get a hydration error when mapping an array using Next I18Next?

Ensure useTranslation is imported from next-i18next and wrap App with appWithTranslation.

What is the difference between i18n.useTranslation() and next-i18next.useTranslation()?

i18next.useTranslation() is not aware of _nextI18Next while next-i18next.useTranslation() is.