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

Hydrogen i18n example #1279

Open
wants to merge 14 commits into
base: main
Choose a base branch
from
Open

Conversation

juanpprieto
Copy link
Contributor

@juanpprieto juanpprieto commented Aug 25, 2023

For detailed information on this PR please read the included RFC.md

Screenshot 2023-08-25 at 9 52 36 AM

@juanpprieto juanpprieto requested a review from a team August 25, 2023 18:15
// Configure the i18n locale format. e.g this will match /fr-CA/ or /en-CA
export const subfolderLocaleParser = createSubfolderLocaleParser({
parser: ({COUNTRY, language, delimiter}) =>
`/${language}${delimiter['-']}${COUNTRY}`,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it be simpler to just make the parser be case insensitive? And the signature could also be {country, language, delimiter}?

const {i18n, i18nSfApi} = await getI18n<typeof DEFAULT_I18N>({
cache,
defaultI18n: DEFAULT_I18N,
prefixParser: subfolderLocaleParser,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not all i18n will use URL prefixes, would this be better to be just named parser?

isDefault: true,
country: defaultCountry,
language: defaultLanguage,
prefix: subfolderLocaleParser({
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What would this be if i18n was in the domain?

mode: process.env.NODE_ENV,
getLoadContext: () => ({
cart,
i18n, // Step 5. pass i18n to the Remix context
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
i18n, // Step 5. pass i18n to the Remix context
i18n, // Step 6. pass i18n to the Remix context

// ...
return defer({
// return i18n so that it is available throughout the app
i18n: context.i18n,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this mean that the entire i18n json for every route is sent down?

<Links />
</head>
<body>
<Layout {...data} key={`${i18n.language.code}-${i18n.country.code}`}>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Curious why the Layout has the key passed in like this?

// Step 3. use localized content for the account a login CTA's
const loginLabel = isLoggedIn
? t('layout.header.ctas.account')
: t('layout.header.ctas.login');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We talked about this before, but I'd like to start a discussion about somehow offering translation type safety.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have you considered using a library like react-i18next for the example? I think many people will want use advanced features that these kind of libs offer and type safety for the TFunction is really easy with it.

examples/i18n/RFC.md Outdated Show resolved Hide resolved
Copy link
Contributor

@frandiox frandiox left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it be possible to just make the JSON files available to existing i18n libraries instead of implementing our own t(...) functionality? I think that's a huge rabbit hole with hidden features like pluralization etc. that we should avoid 🙈

@magnattic
Copy link

Would it be possible to just make the JSON files available to existing i18n libraries instead of implementing our own t(...) functionality? I think that's a huge rabbit hole with hidden features like pluralization etc. that we should avoid 🙈

It's definitely possible. I just did this for our project by combining the data fetching logic from this PR (getOxygenAssetsUrl etc) with react-i18next. Works like a charm so far. The readme of https://github.com/sergiodxa/remix-i18next gives a few pointers in their setup for what needs to be done, specifically <I18NextProvider> setup in entry.client and entry.server and then also some static way to access translations in loaders and actions.

@carstensbix
Copy link

carstensbix commented Sep 29, 2023

Would it be possible to just make the JSON files available to existing i18n libraries instead of implementing our own t(...) functionality? I think that's a huge rabbit hole with hidden features like pluralization etc. that we should avoid 🙈

It's definitely possible. I just did this for our project by combining the data fetching logic from this PR (getOxygenAssetsUrl etc) with react-i18next. Works like a charm so far. The readme of https://github.com/sergiodxa/remix-i18next gives a few pointers in their setup for what needs to be done, specifically <I18NextProvider> setup in entry.client and entry.server and then also some static way to access translations in loaders and actions.

@magnattic Can you share you're code? I am having trouble setting it up.

@magnattic
Copy link

Can you share you're code? I am having trouble setting it up.

It's in a private repo of one of my customers, so I can't share it directly. I could try to set up an example repo but that would take me some time which is in short supply right now. Maybe this PR is not the best place to discuss this, but if you let me know what's not working I could try to give you some pointers.

@carstensbix
Copy link

carstensbix commented Oct 1, 2023

It's in a private repo of one of my customers, so I can't share it directly. I could try to set up an example repo but that would take me some time which is in short supply right now. Maybe this PR is not the best place to discuss this, but if you let me know what's not working I could try to give you some pointers.

@magnattic Where do you use getOxygenAssetsUrl (please show content of that file)? And how does your "i18next.server.ts" look with i18next-fetch-backend. If you could show that file it would definitely solve my problem.

So the file "i18next.server.ts" would be very appreciated :)

Would really appreciate just a very basic repo with the changes that made it working nothing else.

If you send discord we can discuss it there instead :), then i can delete these messages in this PR.

@hydropik
Copy link

hydropik commented Jan 4, 2024

Hello,

Would be great if we could have an exemple with i18next :)

Thank you.

@jmdalmasso
Copy link

jmdalmasso commented Jan 9, 2024

Any update on this PR? An example on how to setup i18n would be very helpful. This PR looks like it rewrites a lot of i18n functionality which is a little strange. Curious to hear why.

@chrisvltn
Copy link

One thing I don't see addressed here is the support for plural translations.

For example, in the cart I'd expect to see a text saying 4 items in your cart or something similar, and items would need to be different depending on the number.

Depending on the language, you might also have 2+ different plural variants for items that depend on how amount of items you have.

Here there are a few examples on different cases of plural: https://www.i18next.com/translation-function/plurals

Maybe here makes sense to use an external library to handle that? Otherwise it might be too much code rewriting inside Hydrogen itself.

@michenly michenly added the Blocked Progress on this issue is blocked by something outside of our control label May 29, 2024
@dominikx96
Copy link

Hey, what is the status of i18n in Hydrogen? What is the recommended approach at this moment?

@jamalsoueidan
Copy link
Contributor

I use metaobject (key, value) in shopify, so store owner can change the translations values
image

and then just load them using @incontext language, create a react-hook

const t = useCallback(
    (key: string, options: Record<string, any> = {}) => {
      const value = data[key];
      if (!value) {
        console.log(`missing_${key}`, data);
        return `missing_${key}`;
      }
      return interpolateText(value, options);
    },
    [data, interpolateText],
  );

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Blocked Progress on this issue is blocked by something outside of our control
Projects
None yet
Development

Successfully merging this pull request may close these issues.