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

With LocalePrefix: 'never' locale switches to previous choice on navigating app pages #786

Open
elensky opened this issue Jan 18, 2024 · 15 comments · Fixed by #790
Open
Labels
bug Something isn't working upstream-issue This issue is caused by an upstream dependency (e.g. Next.js)

Comments

@elensky
Copy link

elensky commented Jan 18, 2024

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:

  1. Open link and download sources
  2. Install dependencies (npm install) and run dev server (npm run dev)
  3. Open http://localhost:3000/ in browser - it opens /home page
  4. Click on the Page link - it opens '/page' page
  5. Click Switch to German link
  6. Click on the 'Home' link - page should be in German
  7. Click on the Page link - 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 occurred and 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

@elensky elensky added bug Something isn't working unconfirmed Needs triage. labels Jan 18, 2024
@amannn
Copy link
Owner

amannn commented Jan 18, 2024

Hey, thanks for the report!

I tried reproducing it but no luck unfortunately yet:

Kapture.2024-01-18.at.09.05.40.mp4

Am I doing something wrong here?

@amannn
Copy link
Owner

amannn commented Jan 18, 2024

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.

IMG_9249

@elensky
Copy link
Author

elensky commented Jan 18, 2024

Looks like you are doing the same, but for me it reproduces every time.

Issue.mov

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.

@elensky
Copy link
Author

elensky commented Jan 18, 2024

My local package-lock:
Screenshot 2024-01-18 at 10 41 39

@amannn
Copy link
Owner

amannn commented Jan 18, 2024

Interesting, not sure why you're seeing a different result.

There is however something related I saw recently that could explain this bug.

Reproduction:

  1. Go to https://next-intl-example-next-13.vercel.app/en (NEXT_LOCALE cookie is set to en)
  2. 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-cookie header for NEXT_LOCALE
  3. 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 353c49d.

(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.

@amannn
Copy link
Owner

amannn commented Jan 18, 2024

I made some progress in regard to this in #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!

@amannn amannn added upstream-issue This issue is caused by an upstream dependency (e.g. Next.js) and removed unconfirmed Needs triage. labels Jan 18, 2024
amannn added a commit that referenced this issue Jan 19, 2024
…Cache is used (#790)

Fixes #786

If you frequently change the locale, Next.js will at some point use the
Router Cache to return a previous response immediately, not making a
request to the server. This has the side effect that no `set-cookie`
response header is returned that will update the locale cookie.

To address this, `next-intl` navigation APIs will now manually keep the
cookie in sync.

Note that a related issue described in #786 was addressed in Next.js
14.1, so upgrading both `next` and `next-intl` is recommended.
@amannn
Copy link
Owner

amannn commented Jan 19, 2024

So it turns out just a few hours after my comment Next.js 14.1 was released—which seems to fix the issue :).

#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!

@elensky
Copy link
Author

elensky commented Jan 19, 2024

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!

@bim-oulabi
Copy link

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'

@amannn
Copy link
Owner

amannn commented Mar 21, 2024

@bim-oulabi Can you open a new issue with a reproduction?

@bim-oulabi
Copy link

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

@mxmzb
Copy link

mxmzb commented May 7, 2024

Adding prefetch={false} to the links that change the locale fixed this for me (on latest Next.js 14 hosted on Vercel)

@beelzick
Copy link

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

@amannn
Copy link
Owner

amannn commented May 13, 2024

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 #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)

@3li7u
Copy link

3li7u commented May 13, 2024

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
    });
  };

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working upstream-issue This issue is caused by an upstream dependency (e.g. Next.js)
Projects
None yet
Development

Successfully merging a pull request may close this issue.

6 participants