Preventing creation of history entry when changing language in Next.js

147 views Asked by At

I'm working on a Next.js project where we have a language dropdown for users to select their preferred language. The current implementation uses the router.push method from next/router to update the language and redirect to the current page without reloading. However, this creates a new entry in the browser history.

Here's the relevant code:

import { useRouter } from 'next/router';
import setLanguage from 'next-translate/setLanguage';


export const LanguageDropdown = () => {
  const { locales, locale } = useRouter();

  const updateLanguage = async (language: string) => {
    window.localStorage.setItem('language-selected', language.toLowerCase());
    // Assuming setLanguage is a function that updates the language in your app
    await setLanguage(language.toLowerCase());
  };

  return (
    <select onChange={(e) => updateLanguage(e.target.value)} value={locale}>
      {locales?.map((lang) => (
        <option key={lang} value={lang}>
          {lang.toUpperCase()}
        </option>
      ))}
    </select>
  );
};

The problem is that when a user changes the language, a new entry is created in the history. If the user then navigates back, they land on the previously set language and are then redirected to the new language. I would like to prevent this behavior and not create a new history entry when the language is changed.

Any suggestions on how to achieve this would be greatly appreciated.

2

There are 2 answers

2
Drew Reese On BEST ANSWER

Based on the current setLanguage function's implementation it doesn't appear this is possible as it uses router.push to PUSH a new entry onto the history stack.

import Router from 'next/router'

export default async function setLanguage(
  locale: string,
  scroll = true
): Promise<boolean> {
  return await Router.push(
    {
      pathname: Router.pathname,
      query: Router.query,
    },
    Router.asPath,
    { locale, scroll }
  )
}

But this hook is simple enough you could create your own that allows for PUSH or REPLACE navigation actions.

Example:

import Router from 'next/router';

export default async function setLanguage(
  locale: string,
  { scroll = true, replace = false } = { scroll: true, replace: false },
): Promise<boolean> {
  return await Router[replace ? "replace" : "push"](
    {
      pathname: Router.pathname,
      query: Router.query,
    },
    Router.asPath,
    { locale, scroll }
  )
}
import { useRouter } from 'next/router';
import setLanguage from '../path/to/setLanguage';


export const LanguageDropdown = () => {
  const { locales, locale } = useRouter();

  const updateLanguage = async (language: string) => {
    const selectedLanguage = language.toLowerCase();
    window.localStorage.setItem('language-selected', selectedLanguage);

    // Set language and redirect
    await setLanguage(selectedLanguage, { replace: true });
  };

  return (
    <select onChange={(e) => updateLanguage(e.target.value)} value={locale}>
      {locales?.map((lang) => (
        <option key={lang} value={lang}>
          {lang.toUpperCase()}
        </option>
      ))}
    </select>
  );
};
1
AudioBubble On

Instead of router.push. How about window.location.reload() ?

async function setLanguage(language) {
  // Some code to set language
  window.location.reload()
}

After the page is reloaded, it will check in the localStorage, see which language is selected.