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

How to implement i18n React example on SSR? #715

Closed
Daniela0106 opened this issue Feb 6, 2019 · 15 comments
Closed

How to implement i18n React example on SSR? #715

Daniela0106 opened this issue Feb 6, 2019 · 15 comments

Comments

@Daniela0106
Copy link

Daniela0106 commented Feb 6, 2019

Question about react-i18next

Hi. The following React i18n example:
https://github.com/i18next/react-i18next/tree/master/example/react
works well by itself, I mean when ran locally using the given steps, but since Suspense is not yet supported by ReactDOMServer on server-side-rendering I was wondering if anyone had any ideas on how this same example would look like if is intended to be SSR, since it is failing on that condition?

image
Source: https://reactjs.org/docs/code-splitting.html

@jamuhl
Copy link
Member

jamuhl commented Feb 6, 2019

On serverside most implementations will use a proper setup using i18next-express-middleware configured to load all languages, namespaces upfront -> therefore not run into the useTranslation, withTranslation run into throwing a Promise to trigger a Suspense

@Daniela0106
Copy link
Author

Thanks @jamuhl , I'm trying i18next-express-middleware out on my project, however I'm getting the following issue:

image

I think perhaps it is because of the latest version I installed using npm ("i18next-express-middleware": "^1.7.1",), that is different from the one used on the examples of i18next-express-middleware ("i18next-express-middleware": "1.0.5", );

@jamuhl
Copy link
Member

jamuhl commented Feb 7, 2019

you're using this on client?!? if i see the last bit of the printscreen right - "webpack plugin"

the express-middleware is a serverside node.js package...

---> consider using: https://github.com/isaachinman/next-i18next

@Daniela0106
Copy link
Author

Daniela0106 commented Feb 7, 2019

you're using this on client?!? if i see the last bit of the printscreen right - "webpack plugin"

the express-middleware is a serverside node.js package...

---> consider using: https://github.com/isaachinman/next-i18next

Ok, I'll give it a try, thanks @jamuhl ! :) Since I wasn't involved too deep on the server-side rendering process we're using now, I think probably should've gone for the client side package since the beggining

@nicksrandall
Copy link

I also don't understand how this could work? withTranslation and useTranslation both throw to Suspense if translations are loading but Suspense isn't supported for SSR yet (react-dom/server will throw error if you try to renderToString with a <Suspense /> component in tree). Am I to understand that v10 of this library no longer supports SSR until react supports Suspense with SSR?

@jamuhl
Copy link
Member

jamuhl commented Feb 9, 2019

@nicksrandall Suspense will be only triggered when you render the serverside JSX tree and not all translation files (namespaces) are loaded. If you run into that situation on the server - i would suggest preloading all translations on serverside using preload: ['lng1', 'lng2'] containing all supported languages and ns: ['ns1', 'ns2'] containing all namespaces...

Preloading all translations on serverside is not a bad thing...we do not create a empty i18n instance on request but a clone sharing the translations with the main instance -> so no memory pressure.

@odensc
Copy link

odensc commented Feb 15, 2019

Do you have any guidance on how to implement SSR without using express? I used to be able to use loadNamespaces but according to the docs the only way now is to set the i18n instance using i18next-express-middleware?

@jamuhl
Copy link
Member

jamuhl commented Feb 15, 2019

@odensc there now is a suspense free mode

#735 (comment)

not yet had time to document that. sorry

@jamuhl jamuhl closed this as completed Mar 4, 2019
@4lph4-Ph4un
Copy link

Do you have any guidance on how to implement SSR without using express? I used to be able to use loadNamespaces but according to the docs the only way now is to set the i18n instance using i18next-express-middleware?

Hi @odensc! Currently having same thing on my mind. Did you find any solutions?

@odensc
Copy link

odensc commented Jun 28, 2019

@4lph4-Ph4un

  1. I enabled suspense-free mode on the SSR side:
react: {
    useSuspense: false
}
  1. On every request, I cloned the i18next instance and set the language to the user's.
const i18n = baseI18n.cloneInstance();
i18n.language = getPreferredLanguage(req);
  1. I wrapped my app in an I18nextProvider using that cloned instance:
<I18nextProvider i18n={i18n}>
    [...]
</I18nextProvider>
  1. I provided the props in the response:
const i18nState = await getInitialProps(i18n);

[...]

<script
    defer
    dangerouslySetInnerHTML={{
        __html: `window.__I18N_STATE__=${serialize(i18nState)}`
    }}
/>
  1. Lastly, I just followed the docs for the client-side.

I had some issues with getInitialProps not working with the XHR backend (because it was synchronous). So, I wrote my own version of it! Along with getPreferredLanguage that the Express backend would normally do for you: https://gist.github.com/odensc/216288159aaa2cb41fc924774fce5859 (TypeScript)

@4lph4-Ph4un
Copy link

Nice! I'll have a look along that kind of path! :) Seems doable! Thank you very much!

@bitttttten
Copy link

bitttttten commented Jul 18, 2019

Thanks for the code @odensc . I found i18next-node-fs-backend, and I am using that.

Although I am struggling getting the initial data out of my store. Maybe it's not initialised correctly, or maybe I can't get it out. Which version of i18next are you using? As for me i18n.reportNamespaces does not exist on my i18n object, or in the types.

I even tried simply copying the code here, and this didn't work either. Although I think there is something wrong with my config:

i18next
    // pass the i18n instance to react-i18next.
    .use(initReactI18next)
    // use node-fs instead of xhr backend
    .use(nodeFsBackend)
    .init({
        keySeparator: '__KEY__',
        defaultNS: 'translation',
        interpolation: {
            // react is already safe from xss
            escapeValue: false,
        },
        backend: {
            loadPath: path.resolve(__dirname, `/locales/{{lng}}/{{ns}}`),
            parse: (data: any) => data,
        },
        react: {
            useSuspense: false,
        },
    })

Then in my controller I do something like this:

    const lang = detectLanguageFromUser(req)
    const i18n = i18next.cloneInstance()
    i18n.language = lang
    await i18n.loadLanguages(lang)

And I am stuck here :D

@odensc
Copy link

odensc commented Jul 21, 2019

Hi @bitttttten, I'm not quite sure how to solve your issue. I'm using v17.0.6 and reportNamespaces exists on my i18n instance.

@bitttttten
Copy link

It's just the types that are out of date.. if I use your code with (i18n as any).reportNamespaces.getUsedNamespaces() it works, otherwise TS complains with "Property 'reportNamespaces' does not exist on type 'i18n'.".

Thanks!

@eseQ
Copy link

eseQ commented Feb 21, 2020

I just tell about my case:

  1. One of module translate has been skiped on node
  2. When some translates are missing react-i18next use suspense.
  3. React DOM can`t use suspense and build tree on server
  4. For some components I pass translates by a component like <T name="mycomponent.title" />
  5. Some components did mount only on client and this was no error but another do crash on server

Just load all i18n resource on server =)

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

No branches or pull requests

7 participants