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

useTranslate() for component localization ? #70

Closed
gnaeus opened this issue Nov 14, 2018 · 2 comments
Closed

useTranslate() for component localization ? #70

gnaeus opened this issue Nov 14, 2018 · 2 comments

Comments

@gnaeus
Copy link

gnaeus commented Nov 14, 2018

An idea for lazy component localization with code splitting.

Suppose we want to localize component named UserProfile

// UserProfile.jsx
const UserProfile = ({ firstName, lastName }) => {
   return (
    <article>
      Hello, {firstName}!
      <div>First Name: {firstName}</div>
      <div>Last Name: {lastName}</div>
      <footer>
        Full Name: {firstName} {lastName}
      </footer>
    </article>
  );
};

At first we should define dynamically imported translations file per language:

// UserProfile.rus.jsx
export default {
  "First Name": "Имя",
  "Last Name": "Фамилия",
  "Hello, ${name}!": name => `Привет, ${name}!`,
  footer: (firstName, lastName) => (
    <footer>
      Полное Имя: {firstName} {lastName}
    </footer>
  )
};

Translation file is plain object, which values are strings or functions returning strings or even JSX markup.

Then we create React Context for locale LocaleContext = React.createContext() and new hook named useTranslate. It loads translations file on every context change and returns translation function to a component.

// UserProfile.jsx
const UserProfile = ({ firstName, lastName }) => {
  // translation function
  const tr = useTranslate(lang =>
    import(/* webpackChunkName: "i18n-" */ `./UserProfile.${lang}.jsx`)
  );

  return (
    <article>
      {tr`Hello, ${firstName}!`}
      <div>
        {tr`First Name`}: {firstName}
      </div>
      <div>
        {tr`Last Name`}: {lastName}
      </div>
      {tr("footer", firstName, lastName) || (
        <footer>
          Full Name: {firstName} {lastName}
        </footer>
      )}
    </article>
  );
};

Translation function can work in two modes:

  • As ES6 template tag it extracts key and arguments from passed template, and also returns raw ES6 template value as fallback if key is not found in translations object.
  • As regular function it uses first argument for key lookup and passes rest arguments to translation template.

Benefits:

  • We can localize each component independently.
  • Or we can create common resources and utilities and import them in each component translations file.
  • Or we can group translations in other ways.

Implementation can be found here: gist (about 100 SLOC).
If this is interesting, I can submit a PR.

@streamich
Copy link
Owner

Maybe use-t can be extended with some ideas from this?

@gnaeus
Copy link
Author

gnaeus commented Nov 15, 2018

The obvious way to do it — add optional argument to useT, withT and optional prop to <Trans>

useT(load?: (locale, namespace) => Object | Promise<Object>);
withT(load?: (locale, namespace) => Object | Promise<Object>);
interface TransProps {
  load?(locale, namespace): Object | Promise<Object>;
}

And use it:

const [t, state] = useT(locale => import `./UserProfile.${locale}.jsx`))

export default withT(locale => import `./UserProfile.${locale}.jsx`))(MyComponent)

<Trans load={locale => import `./Resources.${locale}.jsx`}></Trans>

@gnaeus gnaeus closed this as completed Nov 29, 2018
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

2 participants