next-intl
next-intl copied to clipboard
With LocalePrefix: 'never' locale switches to previous choice on navigating app pages
Description
While I used LocalePrefix: 'never' configuration I faced strange behaviour - if I navigate to any page of my app then change locale I see that locale was changed to previous choice when I navigate to other pages. I created CodeSandbox example of the issue, but looks like LocalePrefix: 'never' is not working there (I added a link to show this), you can download sources to run it locally.
Addition to this issue (it might be helpful): If I change locale several times on the third time it stops changing NEXT_LOCALE cookie value, but it works well only with LocalePrefix: 'always'
Mandatory reproduction URL (CodeSandbox or GitHub repository)
https://codesandbox.io/p/devbox/next-intl-bug-template-app-forked-r7cscn
Reproduction description
Steps to reproduce:
- Open link and download sources
- Install dependencies (npm install) and run dev server (npm run dev)
- Open http://localhost:3000/ in browser - it opens
/homepage - Click on the
Pagelink - it opens '/page' page - Click
Switch to Germanlink - Click on the 'Home' link - page should be in German
- Click on the
Pagelink - there are two unexpected results: page will be in English or application crashes with text on the screen:Application error: a client-side exception has occurredand in console there is this log:
Warning: Cannot update a component (`HotReload`) while rendering a different component (`Router`). To locate the bad setState() call inside `Router`, follow the stack trace as described in https://reactjs.org/link/setstate-in-render
...
Uncaught Error: SEGMENT MISMATCH
...
The above error occurred in the <Router> component:
...
Expected behaviour
Locale and translations should stay in German
Hey, thanks for the report!
I tried reproducing it but no luck unfortunately yet:
https://github.com/amannn/next-intl/assets/4038316/c1743dac-9dfb-479d-973c-634f1f2c9cba
Am I doing something wrong here?
Btw. in the lockfile of your repro is a slightly outdated version of next-intl. I couldn’t reproduce the issue after updating, but maybe you want to upgrade nonetheless in case your app is on an older version currently.
Looks like you are doing the same, but for me it reproduces every time.
https://github.com/amannn/next-intl/assets/8483591/293880d3-ec68-472b-9acd-f4109bdcc045
I've tried to use different versions and firstly face this behaviour with latest version, I experimented that why maybe it has old version in package lock. My idea was that it can work on old version because when I run it with version 3.0.1 first time it seems worked as on your video, but after I tried find a version it start working so on all the version I've tried including 3.0.1.
I even tried to use different node version and next version. Issue is still there.
My local package-lock:
Interesting, not sure why you're seeing a different result.
There is however something related I saw recently that could explain this bug.
Reproduction:
- Go to https://next-intl-example-next-13.vercel.app/en (
NEXT_LOCALEcookie is set toen) - Switch to German using the locale switcher in the top right corner: Vercel potentially returns a cached response from the CDN that lacks the
set-cookieheader forNEXT_LOCALE - Switch back to English: Next.js doesn't even make a request due to the router cache, therefore the cookie value isn't touched (it will coincidentally match in this very case)
(2) is a problem specific to Vercel. It also affects new visits, so e.g. if you have NEXT_LOCALE=en and you request /de, Vercel will potentially return a cached response for /de that doesn't include set-cookie for NEXT_LOCALE=en. This is less problematic when using a locale prefix, but would for example break an app that relies on cookies being accurate (such as when you use localePrefix: 'never'). It's interesting though that the Vercel docs state that a set-cookie header will cause a response to not be cached. Cloudflare has similar rules (haven't tried it yet). Edit: I've improved the docs in regard to this in https://github.com/amannn/next-intl/commit/353c49df3f119631cedd2f9a8b7ef8cee9230fe7.
(3) is a problem specific to Next.js. Opting out of the router cache for navigations that change the locale would be ideal, but maybe we can update the cookie manually by writing to document.cookie when the locale is changed via next-intl navigation APIs (i.e. <Link locale={…} />, useRouter().push(…, {locale: …}), useRouter().replace(…, {locale: …}).
I think addressing (3) could help with your use case.
I made some progress in regard to this in https://github.com/amannn/next-intl/pull/790. After hitting a blocker, I wanted to submit a bug report to Next.js, but found that the latest canary version of Next.js seems to improve the story here.
You can see my reproduction here: https://github.com/amannn/nextjs-bug-router-cache. After upgrading to the latest canary the buggy behavior was gone.
I think we should wait for the next stable release of Next.js and then continue looking into this.
Thanks again for the report!
So it turns out just a few hours after my comment Next.js 14.1 was released—which seems to fix the issue :).
https://github.com/amannn/next-intl/pull/790 furthermore includes a relevant fix for you. Updating both next and next-intl to the latest version should fix the error you were seeing!
Thanks again for the report!
Great thanks for your support and all work you are doing! I've checked - version 14.1 solved the issue. I am happy. Haven't expected that it will be solved so fast. Thanks again and good luck!
May I say that the issue of having wrong cookie under NEXT_LOCALE is still happening even after updating
for example if you visit '/en' the NEXT_LOCALE will be the previous one and so on
without having localePrefix sat to 'never'
@bim-oulabi Can you open a new issue with a reproduction?
I want to apologize as the issue was not because of next-intl,
To put it here in case anyone faced the issue in the future,
If you are using custom next/link to change locale
Disable prefetching by using prefetch={false}
As prefetch will override the locale cookie with the new locale
Or diasble default link behavior by using preventDefault()
And navigate using hooks
Adding prefetch={false} to the links that change the locale fixed this for me (on latest Next.js 14 hosted on Vercel)
Newest Next.js version 14.2.3 breaks it down again, downgraded to Next.js 14.1.4 (with next-inl 3.13.0) and it works
Newest Next.js version 14.2.3 breaks it down again, downgraded to Next.js 14.1.4 (with next-inl 3.13.0) and it works
Seems like, there was a new report about this in https://github.com/amannn/next-intl/issues/1066. I'll reopen this for the time being until this is fixed on the Next.js side.
Does anyone know if there's an upstream bug report? If not, it might be a good idea to create one, maybe for the Next.js team to create a regression test.
Maybe as a workaround, you could call router.refresh() after a locale is changed to invalidate the Router cache:
Calling router.refresh will invalidate the Router Cache and make a new request to the server for the current route.
(source)
Calling router.refresh will invalidate the Router Cache and make a new request to the server for the current route.
Calling router.refresh(); after changing the locale solves the problem for me.
const handleLocaleChange = (locale: string) => {
startTransition(() => {
router.replace(`${pathname}?${searchParams.toString()}`, { locale });
router.refresh(); // clear caching to make sure the locale cookie is set correctly
});
};
Seems to be broken again, and adding prefetch={false} does not help any more.
Same issue here with prefetch={false} as well.
I'll try other solutions, but I wouldn't want to remove prefetch, as it helps to have faster navigation between pages.
This is still an issue even with
experimental: {
staleTimes: {
static: 0,
dynamic: 0,
},
}
None of the mentioned workarounds worked.