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

Recipe: Migrating from i18n-js to react-i18next #177

Merged
merged 11 commits into from
Oct 29, 2024
Merged

Conversation

fpena
Copy link
Contributor

@fpena fpena commented Sep 25, 2024

Description

This PR adds a recipe to migrate from i18n-js to react-i18next library.

Related PRs:

CleanShot 2024-10-28 at 21 23 53

Open Source License Notice for Contributors

If you are contributing a recipe to this repository, you agree to license your contribution under the terms of the CC BY-SA 4.0 license.

If you have any questions, please reference the CONTRIBUTING.md or LICENSE.md file for more information.

Thank you for your contribution!

@fpena fpena changed the title Add initial content for recipe Recipe: Migrating from i18n-js to react-i18next Sep 25, 2024
@fpena fpena marked this pull request as ready for review September 25, 2024 14:30
Copy link
Contributor

@frankcalise frankcalise left a comment

Choose a reason for hiding this comment

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

Looks good. It does slightly differ some of the setup you've done in v10, but if you're OK with this and this is more of a shortcut in terms of making the minimum amount of work to switch, I'm fine with that.

One observation is to just make a note about which file the edits will be located in for the main setup after the dependency step


### Update translation initialization

Modify your translation initialization logic to use the `initReactI18next` from `i18next`.
Copy link
Contributor

Choose a reason for hiding this comment

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

I'd point the user in the direction of which file it is they should be modifying here (at least in terms of standard previous ignite builds), app/i18n/i18n.ts

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@frankcalise added

@fpena
Copy link
Contributor Author

fpena commented Sep 25, 2024

Looks good. It does slightly differ some of the setup you've done in v10, but if you're OK with this and this is more of a shortcut in terms of making the minimum amount of work to switch, I'm fine with that.

One observation is to just make a note about which file the edits will be located in for the main setup after the dependency step

Thanks @frankcalise! It was meant to be minimal, but let me recheck my PR to add another important steps or suggestions.

Copy link

@mazenchami mazenchami left a comment

Choose a reason for hiding this comment

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

two points to mention. I would recommend we put all translations in their own TS files and also add typesafety. happy to pair on this if needed

@fpena
Copy link
Contributor Author

fpena commented Sep 25, 2024

two points to mention. I would recommend we put all translations in their own TS files and also add typesafety. happy to pair on this if needed

Thanks @mazenchami. I think I'm assuming here that whoever is reading is, did generate a RN app from Ignite, which already should have translations in each file with type safety. Let me know if that's a good assumption.

@mazenchami
Copy link

two points to mention. I would recommend we put all translations in their own TS files and also add typesafety. happy to pair on this if needed

Thanks @mazenchami. I think I'm assuming here that whoever is reading is, did generate a RN app from Ignite, which already should have translations in each file with type safety. Let me know if that's a good assumption.

Yes, good call. this looks good to me!

Copy link

@mazenchami mazenchami left a comment

Choose a reason for hiding this comment

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

LGTM!

});
```

In a project generated by Ignite, this can be found in the app/i18n/i18n.ts file.

Choose a reason for hiding this comment

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

Suggested change
In a project generated by Ignite, this can be found in the app/i18n/i18n.ts file.
In a project generated by Ignite, this can be found in the `app/i18n/i18n.ts` file.

Copy link

@mazenchami mazenchami left a comment

Choose a reason for hiding this comment

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

LGTM! 🎉 🚀

Copy link
Contributor

@frankcalise frankcalise left a comment

Choose a reason for hiding this comment

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

Thanks for writing this up. I followed along and I ran into several issues (quite understandable since we kind of changed the direction of this recipe and it's across two PRs now).

I left lots of comments/suggestions, depending on the direction you want to take here.

My process for following was spinning up an Ignite 9 application and trying to work through the steps.

Definitely some of the things I mentioned don't hvae to be so exact, but I do feel like a few of these things so get mentioned, whether or not the syntax is exactly correct (because of course people change their projects too).

Use your best judgement if you don't think all of them belong, but I think I uncovered most of the items here.

Comment on lines 28 to 29
yarn remove i18n-js
yarn remove @types/i18n-js
Copy link
Contributor

Choose a reason for hiding this comment

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

These can be combined into one command yarn remove i18n-js @types/i18n-js

docs/recipes/MigratingToI18Next.md Show resolved Hide resolved
docs/recipes/MigratingToI18Next.md Show resolved Hide resolved
Add the two new dependencies:

```bash
yarn add react-i18nex i18next
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
yarn add react-i18nex i18next
yarn add react-i18next i18next


import * as i18next from "i18next"

const initI18n = async () => {
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
const initI18n = async () => {
export const initI18n = async () => {


## Step 6: Update translation keys from dots (.) to colons (:)

`react-i18next` uses different types of separators for translation keys. Colons (:) are used for first-level translations within an object, while dots (.) are used for nested translations. As a result, you’ll need to update all translation keys in your app accordingly. For example:
Copy link
Contributor

Choose a reason for hiding this comment

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

In doing this dot notation to colon notation, you will receive errors on any tx prop until you update the types in i18n.ts to

type RecursiveKeyOf<TObj extends object> = {
  [TKey in keyof TObj & (string | number)]: RecursiveKeyOfHandleValue<TObj[TKey], `${TKey}`, true>
}[keyof TObj & (string | number)]

type RecursiveKeyOfInner<TObj extends object> = {
  [TKey in keyof TObj & (string | number)]: RecursiveKeyOfHandleValue<TObj[TKey], `${TKey}`, false>
}[keyof TObj & (string | number)]

type RecursiveKeyOfHandleValue<
  TValue,
  Text extends string,
  IsFirstLevel extends boolean,
> = TValue extends any[]
  ? Text
  : TValue extends object
    ? IsFirstLevel extends true
      ? Text | `${Text}:${RecursiveKeyOfInner<TValue>}`
      : Text | `${Text}.${RecursiveKeyOfInner<TValue>}`
    : Text

Copy link
Contributor

Choose a reason for hiding this comment

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

So after showing this change, I'd probably show an example of changing some props as you did with the translate function below (but we generally don't use that one as much in the boilerplate). Maybe an example from the <WelcomeScreen /> since it's pretty straight forward, for example:

  useHeader(
    {
      rightTx: "common:logOut",
      onRightPress: logout,
    },
    [logout],
  )
return (
  <View style={$container}>
    <View style={$topContainer}>
      <Image style={$welcomeLogo} source={welcomeLogo} resizeMode="contain" />
      <Text
        testID="welcome-heading"
        style={$welcomeHeading}
        tx="welcomeScreen:readyForLaunch"
        preset="heading"
      />
      <Text tx="welcomeScreen:exciting" preset="subheading" />
      <Image style={$welcomeFace} source={welcomeFace} resizeMode="contain" />
    </View>

    <View style={[$bottomContainer, $bottomContainerInsets]}>
      <Text tx="welcomeScreen:postscript" size="md" />

      <Button
        testID="next-screen-button"
        preset="reversed"
        tx="welcomeScreen:letsGo"
        onPress={goNext}
      />
    </View>
  </View>
)
})

Copy link
Contributor

Choose a reason for hiding this comment

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

you will receive errors on any tx prop until you update the types in i18n.ts to

I never looked into this, but I was wondering why we kept types that were defined when using the previous library. I would've expected we'd be able to use types defined by the new library.

// error-line
const locale = i18n.locale.split("-")[0]
// success-line
const locale = i18n.language.split("-")[0]
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
const locale = i18n.language.split("-")[0]
const locale = i18next.language.split("-")[0]

also needs import of
import i18next from "i18next" which would have been in place of import { i18n } from "app/i18n"

const initI18n = async () => {
await i18n.use(initReactI18next).init({
resources,
lng: pickSupportedLocale()?.languageTag || fallbackLocale,
Copy link
Contributor

Choose a reason for hiding this comment

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

pickSupportedLocale and the helper that gets used for it via @lindboe's PR did not seem to make it in here


Finally, the steps outlined in this guide, are based on the changes outlined in the following two PRs:
* [Swap out i18n-js for react-18next](https://github.com/infinitered/ignite/pull/2770)
* [Fix language switching and update date-fns to v4](https://github.com/infinitered/ignite/pull/2778)
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
* [Fix language switching and update date-fns to v4](https://github.com/infinitered/ignite/pull/2778)
* [Fix language switching and update date-fns to v4](https://github.com/infinitered/ignite/pull/2788)

For detailed code changes, including initialization updates, translation function updates, and testing, refer to the following PRs on the Ignite Github repo:

* [Swap out i18n-js for react-18next](https://github.com/infinitered/ignite/pull/2770)
* [Fix language switching and update date-fns to v4](https://github.com/infinitered/ignite/pull/2778)
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
* [Fix language switching and update date-fns to v4](https://github.com/infinitered/ignite/pull/2778)
* [Fix language switching and update date-fns to v4](https://github.com/infinitered/ignite/pull/2788)

@fpena
Copy link
Contributor Author

fpena commented Oct 7, 2024

Thanks for writing this up. I followed along and I ran into several issues (quite understandable since we kind of changed the direction of this recipe and it's across two PRs now).

I left lots of comments/suggestions, depending on the direction you want to take here.

My process for following was spinning up an Ignite 9 application and trying to work through the steps.

Definitely some of the things I mentioned don't hvae to be so exact, but I do feel like a few of these things so get mentioned, whether or not the syntax is exactly correct (because of course people change their projects too).

Use your best judgement if you don't think all of them belong, but I think I uncovered most of the items here.

Hello @frankcalise !

Based on my previous understanding, we wanted a guide to point out key places to update the i18n implementation. Your comments sound like we want the exact difference and changes compared to a fresh Ignite installation.

We can go that way too! If we feel devs won't be updating the i18n Ignite implementation too much, then we might just as well provide the full detail.

Let me know what do you think.

@fpena
Copy link
Contributor Author

fpena commented Oct 29, 2024

Thanks for writing this up. I followed along and I ran into several issues (quite understandable since we kind of changed the direction of this recipe and it's across two PRs now).

I left lots of comments/suggestions, depending on the direction you want to take here.

My process for following was spinning up an Ignite 9 application and trying to work through the steps.

Definitely some of the things I mentioned don't hvae to be so exact, but I do feel like a few of these things so get mentioned, whether or not the syntax is exactly correct (because of course people change their projects too).

Use your best judgement if you don't think all of them belong, but I think I uncovered most of the items here.

Hey @frankcalise! Improved the PR based on your feedback. Please give it another peek. Thanks!

Copy link
Contributor

@frankcalise frankcalise left a comment

Choose a reason for hiding this comment

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

Great work!

@fpena fpena merged commit ceb925c into main Oct 29, 2024
1 check passed
@fpena fpena deleted the fp/add-i18n-migration branch October 29, 2024 22:54
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

Successfully merging this pull request may close these issues.

4 participants