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

An official way of integrating with nextjs #1339

Closed
timofei-iatsenko opened this issue Jan 14, 2023 · 7 comments
Closed

An official way of integrating with nextjs #1339

timofei-iatsenko opened this issue Jan 14, 2023 · 7 comments

Comments

@timofei-iatsenko
Copy link
Collaborator

@Martin005 please have a look at example i've created here https://github.com/lingui/swc-plugin/tree/main/examples/nextjs-13

I was not able to make it in a clean way because issues came from different sides.
Nextjs is quite popular framework, and we should provide a seamless way to integrate LinguiJs with it.

Problems i encountered:

  1. Current example in main lingui monorepo is wrong, it doesn't work with SSR because it calls i18n.activate in useEffect hook.
  2. NextJS does not provide a way to await something on client side before react starts render component tree. So if you await loading catalog on backend and will not have this catalog synchronously on frontend you will get hydration mismatch.
  3. I loaded catalog on SSR and passed it with props of each page (it's so annoying to do on each page!!), to have a catalog synchrnously on client side
  4. But even when we have catalog synchronously, we also need to call i18n.load + i18n.activate to allow Provider to render content. And again, nextjs doesn't provide any hook which you can use to call this function before reacts starts render. The only place is in the _app.js, but when you do that you will get another error. Both of this i18n methods emits change event and trigger rendering inside Provider while another component (App) is still in render.

So the only way i've found to make it work is using private properties of i18n object. That's not how it should be.

Please review the example, and let's discuss how we can make this integration simpler.

@andrii-bodnar FYI

@timofei-iatsenko
Copy link
Collaborator Author

timofei-iatsenko commented Jan 17, 2023

Related #1194

I also tried solutions proposed in this thread and setup like this:

// _app.tsx
  // i18n._messages[router.locale as string] = pageProps.i18n;
  // i18n._locale = router.locale as string;

  const locale = router.locale as string;

  const [i18n] = useState(() =>
    setupI18n({
      messages: {
        [locale]: { ...pageProps.i18n },
      },
      localeData: {
        en: { plurals: en },
        cs: { plurals: cs },
      },
      locale,
    }),
  );

But this way get hydration mismatch because global i18n doesn't configured properly and on server i've got one result on client another.

@Martin005 Martin005 assigned Martin005 and unassigned Martin005 Jan 18, 2023
@dmitryshelomanov
Copy link

dmitryshelomanov commented Jan 23, 2023

@thekip you no need to use global i18, only with const {i18n} = useLingui()

global i18 only with setup

@crazyyi
Copy link

crazyyi commented Mar 8, 2023

@dmitryshelomanov
But useLingui needs to be used inside I18nProvider right?

The setup would be in _app.tsx which is not inside an I18nProvider.

@thekip
Which is a better way to setup? I saw in your example you are not using activate and using private API. Is it still at the experimental stage?
When you said you get new error when you tried to load and activate the locale in _app.js what error do you mean?
I am getting an error saying "TypeError: Cannot assign to read only property '0' of object '[object String]'" in i18n.load("en"). It hasn't even reached activate

@timofei-iatsenko
Copy link
Collaborator Author

timofei-iatsenko commented Mar 8, 2023

@crazyyi no, i had another error. Look at this example repo https://github.com/thekip/nextjs-translation-demo/tree/update-for-latest-lingui there is other approach to setup messages in _app.tsx which seems to work.

useLingui is needed in components wrapped in React.memo if you use t macro in them.

@crazyyi
Copy link

crazyyi commented Mar 8, 2023

@crazyyi no, i had another error. Look at this example repo https://github.com/thekip/nextjs-translation-demo/tree/update-for-latest-lingui there is other approach to setup messages in _app.tsx which seems to work.

useLingui is needed in components wrapped in React.memo if you use t macro in them.

@thekip
Thanks this example works great.
There is still one problem though. If I try to put a <Trans> tag around texts inside a title element in the header, it would give me this warning:

   Warning: A title element received a React element for children. In the browser title Elements can only have Text Nodes as 
   children. If the children being rendered output more than a single text node in aggregate the browser will display markup 
   and comments as text in the title and hydration will likely fail and fall back to client rendering
   at title
   at head
   at Head (webpack-internal:///../../node_modules/next/dist/pages/_document.js:279:1)
   at html
   at Html (webpack-internal:///../../node_modules/next/dist/pages/_document.js:678:104)
   at Document (webpack-internal:///../../node_modules/next/dist/pages/_document.js:14:1)
   Error: useLingui hook was used without I18nProvider.
   at useLingui (file:///Users/.../node_modules/@lingui/react/build/esm/index.js:9:13)
   at Trans (file:///Users/.../node_modules/@lingui/react/build/esm/index.js:185:7)

Is there any solution to remove this warning?

@timofei-iatsenko
Copy link
Collaborator Author

Use t`` instead of Trans in Title element

<Title>{t`My Awecome Page`}</Title>

@timofei-iatsenko
Copy link
Collaborator Author

new examples added to the repo #1550

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants