1

I'm having trouble with the useTranslation hook from the next-translate package in my Next.js application. While all my languages are being recognized, I encounter a hydration error whenever I change the language and refresh the page.

Here's the setup I have in my i18n.js file located at the root:

module.exports = {
  locales: ["ar", "en","es"],
  defaultLocale: "en",
  pages: {
    "*": ["common"],
  },
};

I'm using useTranslation in my components as follows:

import useTranslation from "next-translate/useTranslation";

const ComponentName = () => {
  const { t } = useTranslation("common");
  // rest of the component
}

I've placed all my translations inside the public folder. When I change the language, I store the new language in local storage.

The issue arises when I change the language and then refresh the page. I get a hydration error because the server side language is detected as English, while the client has the custom language I had selected and stored in local storage.

Is there a way to solve this problem such that the server side recognizes the selected language upon refreshing? I have tried all the ways. Any help or guidance is greatly appreciated. https://drive.google.com/file/d/1WSBKdXKTpOlQv6g2v1c2KpnZaZjecHhf/view?usp=sharing - here is my folder strucutre

I implemented multi-language support using the next-translate/useTranslation hook in my Next.js application. I stored the selected language in local storage when changing languages. I expected the application to maintain the selected language even after a page refresh, seamlessly translating the page to the chosen language.On refreshing the page after changing the language, I encountered a hydration error. The server side detected English (the default language) while the client had the custom language I selected, causing a mismatch.

juliomalves
  • 42,130
  • 20
  • 150
  • 146
Sushanth
  • 21
  • 2
  • Can you show the code where you are reading from local storage? and when is it called – Tushar Shahi Jun 10 '23 at 04:15
  • import i18n from "i18next"; import { initReactI18next } from "react-i18next"; import { en } from "./en"; import { es } from "./es"; let defaultLanguage = "en" if(typeof window !== undefined) defaultLanguage = window.localStorage.getItem("defaultLang") || "en" i18n.use(initReactI18next).init({ resources: { en: { translation: en, }, es: { translation: es, }, ar: { translation: ar, }, }, lng: defaultLanguage, fallbackLng: defaultLanguage, interpolation: { escapeValue: false, }, }); export default i18n; – Sushanth Jun 11 '23 at 12:45

1 Answers1

0

If you want the initial page load to be the correct language, you'll need to store the language preference in a way that is shared with the server. Like in the URL example.com/es or example.com?lang=es or in the cookies. Then you should initialise the language based on that value, even on the server.


If you set it in the cookies, you'll also have to respond with a Vary header that indicates that page content can vary depending on the cookie, which could be kinda bad if you have other stuff that changes a lot from one user to the next in the cookie...

On the server, you could also read the Accept-Language header to have a better chance of serving the page in the correct language the first time (and if you do, respond with a Vary header that indicates content might change based on Accept-Language).


If you decide to use the URL instead, the usual choice (for aesthetics) is example.com/es/page-name. So then you need a few redirections:

  • an internal rewrite that transforms /es/page-name into /page-name?lang=fr so that internally it hits the correct Next page code, just with a language param. This rewrite should be invisible to the user, I know this can be done with next middlewares
  • a client redirection, if you want, that could take someone who's accessing example.com but already has a preference set for another language to example.com/es

Those were ways to actually generate a different language on the server, but if all you want is to avoid the hydration error, just initialize the language on the client with the language that was set by the server, and then immediately change it (in a useEffect that will be executed after first render).

Sheraff
  • 5,730
  • 3
  • 28
  • 53