Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Switching between languages breaks and triggers infinite network calls when using useSuspense: true, and client-side-only translations #2095

Closed
danielmarcano opened this issue Feb 22, 2023 · 5 comments
Labels

Comments

@danielmarcano
Copy link

danielmarcano commented Feb 22, 2023

🐛 Bug Report

Switching between languages by using Next.js built-in internationalized routing is breaking and triggering infinite Network calls if:

  • We set { react: { useSuspense: true } } inside the next-i18next.config.js file's configuration object
  • We load our translations on the client-side by following this guide, and set: backendOptions: [{ expirationTime: 0 }] (in development, to prevent caching translations if we are manipulating them while developing the app) inside the next-i18next.config.js file

To Reproduce

A codesandbox that reproduces the error

In short, we can reproduce this bug by:

  • Adding client-side-only translations by following this guide and adding all necessary packages
  • Adding { react: { useSuspense: true } } and backendOptions: [{ expirationTime: 0 }] to the next-i18next.config.js object
// next-i18next.config.js

const HttpBackend = require("i18next-http-backend/cjs");
const ChainedBackend = require("i18next-chained-backend").default;
const LocalStorageBackend = require("i18next-localstorage-backend").default;

const ONE_HOUR_IN_MILISECONDS = 60 * 60 * 1000;

module.exports = {
  backend: {
  backendOptions: [{ expirationTime: process.env.NODE_ENV === 'production' ? ONE_HOUR_IN_MILISECONDS : 0 }],
    backends:
      typeof window !== "undefined" ? [LocalStorageBackend, HttpBackend] : [],
  },
  serializeConfig: false,
  use: typeof window !== "undefined" ? [ChainedBackend] : [],
  i18n: {
    locales: ["en", "es"],
    defaultLocale: "en",
  },
  defaultNs: "common",
  react: {
    useSuspense: true,
  },
};
  • Passing such object to appWithTranslation inside the _app.tsx file
  • Wrapping our app with Suspense
import { Suspense } from "react";
import type { AppProps } from "next/app";
import { appWithTranslation, UserConfig } from "next-i18next";

import i18nConfig from "$/../next-i18next.config";

function App({ Component, pageProps }: AppProps) {
  return (
    <Suspense fallback="Loading...">{<Component {...pageProps} />}</Suspense>
  );
}

export default appWithTranslation(App, i18nConfig as UserConfig);
  • Trying to switch between languages from a page of our app that uses translations (without adding a getStaticProps nor a getServerSideProps function)
// src/views/HomeView.tsx

import Link from "next/link";
import { useTranslation } from "next-i18next";

export function HomeView() {
  const { t } = useTranslation("common");

  return (
    <div>
      <div>
        <Link href="/" locale="en">
          next/link: {t("changeLanguageToEnglish")}
        </Link>
      </div>
      <div>
        <Link href="/" locale="es">
          next/link: {t("changeLanguageToSpanish")}
        </Link>
      </div>
      <p>{t("mission")}</p>
    </div>
  );
}
// src/pages/index.tsx

import { HomeView } from "$/views/Home";
import { NextPage } from "next";

const Home: NextPage = () => {
  return <HomeView />;
};

export default Home;
  • When trying to switch to a language different than the one automatically detected by Next.js as explained here, we get infinite Network calls (we can only stop them by clicking on the language detected by Next.js, as shown in the video):
Grabacion.de.pantalla.2023-02-22.a.las.14.30.56.mov

Expected behavior

  • As far as I have understood, and being unable to find more information regarding this matter on the docs, it should be possible to set expirationTime to 0 in development, and not having the app break when switching between languages

Your Environment

  • runtime version: node v16.18.1, Chrome 110.0.5481.100
  • next-i18next version: "13.1.5"
  • i18next version: "22.4.10"
  • i18next-chained-backend version: "4.2.0"
  • i18next-http-backend version: "2.1.1"
  • i18next-localstorage-backend version: "4.1.0"
  • os: macOS 13.2

P.S. Thank you all for your great work!

Workaround

I have realized that by simply passing that ONE_HOUR_IN_MILISECONDS to the backendOptions.expirationTime regardless of the environment, the issue is solved.

// const ONE_HOUR_IN_MILISECONDS = 60 * 60 * 1000;

// ...
  backendOptions: [{ expirationTime: ONE_HOUR_IN_MILISECONDS }],
// ...

We were using it so that the development translations were always the most recent ones, so as to always have the latest translation changes while developing on localhost since caching the translations is not something that we want/need in this environment.

I wonder if, somehow, we can keep this functionality without breaking the app when switching between languages...

@danielmarcano danielmarcano changed the title Switching between languages breaks and triggers infinite network calls when using useSuspense: true and client-side-only translations Switching between languages breaks and triggers infinite network calls when using useSuspense: true, client-side-only translations, and an expirationTime of 0 Feb 22, 2023
@danielmarcano danielmarcano reopened this Feb 22, 2023
@danielmarcano danielmarcano changed the title Switching between languages breaks and triggers infinite network calls when using useSuspense: true, client-side-only translations, and an expirationTime of 0 Switching between languages breaks and triggers infinite network calls when using useSuspense: true, client-side-only translations, and a backendOptions.expirationTime of 0 Feb 22, 2023
@danielmarcano danielmarcano changed the title Switching between languages breaks and triggers infinite network calls when using useSuspense: true, client-side-only translations, and a backendOptions.expirationTime of 0 Switching between languages breaks and triggers infinite network calls when using useSuspense: true, and client-side-only translations Feb 22, 2023
@adrai
Copy link
Member

adrai commented Feb 22, 2023

Never use Suspense with next.js so far, seems like Next.js renders the page in the infinite loop in that case.
I would suggest you use the lazy-reload approach instead of the pure client-loading approach (even better in newer Next.js versions): i18next/i18next-http-backend@efb1aba

@danielmarcano
Copy link
Author

Thanks for the information, @adrai! I will try that other approach.

@loristns
Copy link

loristns commented Feb 27, 2023

I also noticed that the infinite loop occurred with the same settings when switching from a page with server-rendered translation to a client-side rendered page.

Never use Suspense with next.js so far, seems like Next.js renders the page in the infinite loop in that case. I would suggest you use the lazy-reload approach instead of the pure client-loading approach (even better in newer Next.js versions): i18next/i18next-http-backend@efb1aba

AFAIK, if you want to keep some pages rendered entirely client-side, you may not be able to use the lazy-load approach as it requires calling getServerSideProps, getStaticProps (and getAllPaths if the route is dynamic). In such cases, pure client-side loading seems preferable.

@adrai
Copy link
Member

adrai commented Feb 27, 2023

If someone knows of how that infinite loop could be prevented... (basically prevent Next.js to render that page infinitely)... feel free to contribute... it might also be a bug in Next.js?

@stale
Copy link

stale bot commented Mar 18, 2023

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

@stale stale bot added the stale label Mar 18, 2023
@stale stale bot closed this as completed Apr 2, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants