adobe / react-spectrum

A collection of libraries and tools that help you build adaptive, accessible, and robust user experiences.
https://react-spectrum.adobe.com
Apache License 2.0
12.62k stars 1.09k forks source link

DatePicker - Internationalization server client mismatch [NextJS 14.1.0 App Router] #6216

Open thomaswanhpls opened 5 months ago

thomaswanhpls commented 5 months ago

Provide a general summary of the issue here

NextJS 14.1.0 using App Router When using DatePicker as instructed in documentation server client mismatch occurs.

To mitigate a rerender on client (adapting language) for some of the components we need to provide language information on server

I've followed the steps provided here

datepicker

๐Ÿค” Expected Behavior?

The component should get correct language on SSR and not need to correct it on client.

๐Ÿ˜ฏ Current Behavior

The component doesn't render correct language on SSR, corrects on client resulting in a server client mismatch

๐Ÿ’ Possible Solution

No response

๐Ÿ”ฆ Context

No response

๐Ÿ–ฅ๏ธ Steps to Reproduce

https://stackblitz.com/edit/nextjs-arbvzx?file=components%2FDatePicker.tsx

Version

react-aria-components 1.1.1

What browsers are you seeing the problem on?

Chrome

If other, please specify.

No response

What operating system are you using?

Windows 10

๐Ÿงข Your Company/Team

No response

๐Ÿ•ท Tracking Issue

No response

LFDanLu commented 4 months ago

I can't seem to get your stackblitz to work, but I noticed you don't have a wrapping I18nProvider, does that help?

thomaswanhpls commented 4 months ago

Thanks for taking the time @LFDanLu. Did you add routing locale? eg "en-US". I'm using /sv (swedish). And there's a string in the datesegment component resulting in "app-index.js:35 Warning: Prop aria-valuetext did not match. Server: "Empty" Client: "Tomt""

I can't set the text manually either. That would work for me. Not sure if I would stumble into more strings that needs translation though. As for wrapping the app with I18nProvider - Since I'm using NextJS Im following the NextJS specific docs:

 // app/[lang]/layout.tsx
import {LocalizedStringProvider} from 'react-aria-components/i18n';
export default function RootLayout(
  {children, params: {lang}}:
  {children: React.ReactNode, params: {lang: string}}
) {
  return (
    <html lang={lang}>
      <body>
        <LocalizedStringProvider locale={lang} />
        {children}
      </body>
    </html>
  );
}
LFDanLu commented 4 months ago

I might be having a brain fart, but when I open the stackblitz it just 404's after the packages are installed and next dev finishes. My understanding here is that you still need to have a wrapping i18nProvider with the locale set to whatever locale will be used on the client so that localized strings like the aria-valuetext will match between server and client. I do see what you are referring to in the docs here where it states

Render React Aria's LocalizedStringProvider component at the root of your app. This includes the strings for the user's language in the initial HTML so that the client can access them. It also passes the locale to the client, so an I18nProvider is not needed.

but looking at the code it doesn't look like LocalizedStringProvider does this in time, it sets a localeSymbol on the window which doesn't exist on the server if I'm not mistaken hence why the i18nProvider is still necessary.

thomaswanhpls commented 4 months ago

stackblitz_demo You need to add the locale in the url. In my case I'm adding "/sv" (swedish). NextJS router gets the params in the RootLayout and provides the locale to html tag and LocalizedStringProvider on the server.

As for wrapping the app in i18nProvider I'm not convinced it's the right approach when it comes to NextJS but I might be missing something. I've tried to apply it in the code but I can't really figure out where I would put it.

LFDanLu commented 4 months ago

Yeah, the setup required isn't ideal here (probably a bug tbh), we'll probably want to change LocalizedStringProvider on our end to handle this for you. For now you'd have to make a client component to render the i18nProvider like so: https://stackblitz.com/edit/nextjs-tep8sy?file=app%2F[lang]%2Flayout.tsx,app%2F[lang]%2FLocaleProvider.tsx,app%2F[lang]%2Fpage.tsx

some docs in NextJS about this: https://nextjs.org/docs/app/building-your-application/rendering/composition-patterns#using-context-providers

thomaswanhpls commented 4 months ago

Thank you for sharing your thoughts about this! ๐Ÿ™Œ @LFDanLu