#Using astro-i18next with React

26 messages · Page 1 of 1 (latest)

sweet coyote
#

So I have been getting into astro-i18next for localizing my Astro project.
Though I ran into some issues when trying to use the localization functionality in React (tsx) components.
I am not sure if everything what I am trying to do is even supposed to work, but I’d really like the i18n to work in my react components, which are nested within astro components, as well.
Especially for things like localizePath().

I have correctly set up react-i18next as a plugin for astro-i18next and the init and the useTranslation() hook with the t() function work correctly.
Though both the LanguageSelector (as it’s an Astro component, which thus cannot be nested within a framework / react component), as well as the localizePath() function don’t seem to work in any react environment.

So, I am not really sure how to link to any internal pages / routes in my react components.
Either I’d have to drop React or astro-i18next, which really is a pity.

So any help or suggestions for workarounds on this matter are welcomed with open arms 🙂

turbid nova
#

Have you tried using the client side components from react-i18next in your React component instead of the Astro ones? I have never used i18next before so I am not exactly sure how it all fits together but my assumption is that astro-i18n handles more of the Astro side and maybe react-i18n handles more of the client side

#

Another option is to pass the Astro components into your react component as a slot

sweet coyote
sweet coyote
sweet coyote
#

this kind of defeats the principle of encapsulating all Header component logic and making it only dependent on itself

#

The only thing I could think of atm is having an Astro component, which wraps the React Header component and passes in the LanguageSelector, without revealing it to anything which actually uses the Header component

turbid nova
#

Ya I would wrap it in an Astro component

#

For localizePath you might have to pass the values using props

sweet coyote
#

The other option I thought of was to generate an object containing all links in all language variants at the beginning and then revealing that to all components which are lower in the hierarchy

#

Though all this really starts to sounds dirty, even more so than the LanguageSelector solution

#

I’d be interested what the creator’s take on this would be, though I think there is no chance he’ll see this

turbid nova
#

Ya I am curious what the "correct" pattern for this is too. The best thing I can think of is like you said, have a separate file/module that exports a pre generated object of all your links that you can then split up and pass into client side components, but like you also mentioned it just seems messy. You could try creating an issue on the github page but idk how active the project is anymore

sweet coyote
sweet coyote
sweet coyote
#

@turbid nova as it turns out localizePath and translations actually work in React component, though they somehow prevent the components from changing state.
Everywhere I use either a localized path or a translated text (e.g. in my navigation menu), the state stays the same, no matter what I do. I tried debugging state changes using a useEffect, and it only triggers once on mount, even though I have a menu toggle, which technically changes / should change the open state of the navigation menu.

sweet coyote
#

this is so frustrating, I am ngl

swift owl
#

We're having a similar issue, so lmk if you figure this out

sweet coyote
#

@here I think I got a solution working.
In case you are interested how, let me give you a quick heads up:
I have a localizedPaths.ts module, which exports a method, taking in the current language, and then returning all localized routes there are based on that language:

import { localizePath } from 'astro-i18next';

const PATHS = {
  home: '/',
  imprint: '/imprint',
  contact: '/contact',
  privacyPolicy: '/privacy-policy',
};

type LocalizedPaths = typeof PATHS;

function getLocalizedPaths(language: string) {
  return <LocalizedPaths>Object.entries(PATHS).reduce(
    (localizedPaths, [key, value]) => ({
      [key]: localizePath(value, language),
      ...localizedPaths,
    }),
    {},
  );
}

export default getLocalizedPaths;
export type { LocalizedPaths };

Then in my Layout.astro I am accessing the localized routes of that module, like so:

const { language: currentLanguage } = i18next;

const localizedPaths = getLocalizedPaths(currentLanguage);

And finally those localized routes can be passed down from the Layout to my React components all the way down the tree, without the components having to worry how the localized routes were generated (as they are just strings at that point):

interface Props {
  localizedPaths: LocalizedPaths;
}

function MyReactComponent({ localizedPaths }: Props) {
  // ...
}

Hope this helps anyone out, who sees this thread, struggling as well 🙂

#

I could even enhance this using nano-stores, to not have to pass the localized routes down to all components, but just access the store when needed I guess.

#

And the localizedPaths.ts module is probably not the most elegant as it is, just wanted to mock this up really quickly.
Open for any improvement suggestions 🙂

#

Then, to get your LanguageSelector working, you'd have to build it in an Astro component and pass it into your actual React component using an Astro <slot />.

swift owl
#

Hmm. Our app mostly uses Astro for SSG but all of the components are in React. So we need a solution that can allow serverside localization within the React components.
I'm thinking that a custom Rollup/Vite plugin may be required to transform the React components and create separate versions for each localization route during build.