martinkr/next-export-i18n

Support for Trans Component

leandro-silva-me opened this issue · 4 comments

Trans component from i18next allows listing the custom component.

This would be really useful and facilitate migrating from next-translate or react-i18next to next-export-i18n.

Example:

<Trans
  i18nKey="description"
  components={{
    privacyPolicyLink: (
      <PrivacyLink lang={lang} type={'privacy-policy'} />
    ),
    generalTermsLink: (
      <PrivacyLink lang={lang} type={'general-terms'} />
    ),
    cookiePolicyLink: (
      <PrivacyLink lang={lang} type={'cookie-policy'} />
    )
  }}
/>

Hi leandro-silva-me,

thank you for taking the time to contribute.

From the documentation:

While gives you a lot of power by letting you interpolate or translate complex React elements, the truth is: in most cases you don't even need it.
As long you have no React/HTML nodes integrated into a cohesive sentence (text formatting like strong, em, link components, maybe others), you won't need it - most of the times you will be using the good old t function.

next-export-i18n supports the translation of strings with HTML nodes through Moustache templates.
The Trans component is fairly complex, it is about ~335 lines of code and another ~1000 lines of tests.
Unfortunately, recreating this functionality is out scope for me. If you want to fork and contribute this functionality to next-export-i18n I will happily support you.

I don't know your exact use case, but maybe combining the t() function with Moustache templates could be something you can leverage?

Cheers,

Martin

Unfortunately, in my case, I won't be able to use Moustache templates since they won't work for React Elements. However, I will try to fork the Trans on this project. Thanks!

Did you start to look into this? I'm trying to see if this library can replace next-i18next for us and enable building via next export

flathub-infra/frontend#217

@razzeee not yet. I made a custom component on my project that gets w/e inside a mustache template and replaces it with a React Element.

Example:
translations.json

{
    "textExample": "This Text should have custom elements {{custom1}} and {{custom2}}." 
    "custom1": "here",
    "custom2": "also here",
}

CustomComponent.ts

const renderText = (text: string) => {
  const { t } = useTranslation();
  const parts: (string | Element)[] = text.split(/{{\s*[\w\.]+\s*}}/g);
  let cont = 0;
  for (let i = 1; i < parts.length; i += 2) {
    const matches = text.match(/{{\s*[\w\.]+\s*}}/g);
    if (matches) {
      const textMatch = matches[cont];
      if (textMatch) {
        const mustacheMatch = textMatch.match(/[\w\.]+/);
        if (mustacheMatch) {
          const innerText = mustacheMatch[0];
          parts.splice(
            i,
            0,
            (<MyComponent type={innerText}>{t(innerText)}</MyComponent >) as any
          );
        }
      }
    }
    cont++;
  }
  return parts;
};


const CustomComponent: React.FC = () => {
  const { t } = useTranslation();
  const newText = renderText(t('textExample'));
  return <>{newText}</>;
};

This solution is temporary but works for what I need for now.