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

Not able to use next-intl's createTranslator with Tailwind component #1244

Open
Robin-Ln opened this issue Jan 25, 2024 · 25 comments
Open

Not able to use next-intl's createTranslator with Tailwind component #1244

Robin-Ln opened this issue Jan 25, 2024 · 25 comments

Comments

@Robin-Ln
Copy link

Robin-Ln commented Jan 25, 2024

Describe the Bug

i have this template :

export const MagicLinkEmail: FC<MagicLinkEmailProps> = ({ magicLink }) => {
  const t = createTranslator({
    locale: defaultLocale,
    messages,
    namespace: 'MagicLinkEmail'
  });

  return (
    <Tailwind>
      <Html>
        <Head />
        <Body>{t('preview')}</Body>
      </Html>
    </Tailwind>
  );
};

export default MagicLinkEmail;

in preview mode i have this error :

TypeError: extendStatics is not a function
 at <unknown> (/Users/rlouarn/git/programme-tz-2023/src/emails/magic-link-email.tsx:27:2)
 at __extends (/Users/rlouarn/git/programme-tz-2023/src/emails/magic-link-email.tsx:27:2)
 at <unknown> (/Users/rlouarn/git/programme-tz-2023/src/emails/magic-link-email.tsx:84536:2)
 at <unknown> (/Users/rlouarn/git/programme-tz-2023/src/emails/magic-link-email.tsx:84542:2)
 at Script.runInContext (node:vm:133:12)
 at Script.runInNewContext (node:vm:138:17)
 at Object.runInNewContext (node:vm:296:38)
 at getEmailComponent (webpack-internal:///(rsc)/./src/utils/get-email-component.ts:84:56)
 at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
 at async renderEmailBySlug (webpack-internal:///(rsc)/./src/actions/render-email-by-slug.tsx:31:20)
 at async Page (webpack-internal:///(rsc)/./src/app/preview/[slug]/page.tsx:27:34)


Capture d’écran 2024-01-25 à 13 10 09

when i remove Tailwind it s work correctly :

export const MagicLinkEmail: FC<MagicLinkEmailProps> = ({ magicLink }) => {
  const t = createTranslator({
    locale: defaultLocale,
    messages,
    namespace: 'MagicLinkEmail'
  });

  return (
    <Html>
      <Head />
      <Body>{t('preview')}</Body>
    </Html>
  );
};

export default MagicLinkEmail;

Capture d’écran 2024-01-25 à 13 11 04

Which package is affected (leave empty if unsure)

No response

Link to the code that reproduces this issue

https://gitlab.com/robin.louarn/programme-tz-2023

To Reproduce

nvm use
pnpm install
pnpm email:dev

Expected Behavior

see a preview of email

What's your node version? (if relevant)

20.11.0

@Robin-Ln Robin-Ln added the Type: Bug Confirmed bug label Jan 25, 2024
@gabrielmfern gabrielmfern changed the title Tailwind error on preview app : TypeError: extendStatics is not a function Not able to use next-intl's createTranslator with Tailwind component Jan 27, 2024
@antoinerousseau
Copy link

antoinerousseau commented Jan 27, 2024

Same error with createIntl from @formatjs/intl when using <Tailwind>

@gabrielmfern
Copy link
Collaborator

@antoinerousseau Is it the same exact error or just a similar error?

@gabrielmfern gabrielmfern linked a pull request Jan 28, 2024 that will close this issue
@ababol
Copy link

ababol commented Jan 28, 2024

@antoinerousseau Is it the same exact error or just a similar error?

(working with @antoinerousseau here 👋 )
=> Same error
Screenshot 2024-01-28 at 18 07 57

@gabrielmfern
Copy link
Collaborator

After digging around a lot this should be fixed by #1124 which I have tested myself. Not sure how this is caused but some of the polyfills we have currently on tailwind are causing this—something to do with tslib. @ababol @antoinerousseau lmk if you are blocked by not using intl here cuz I can make a patch for you from #1124.


Also, the error overlay is just not helping here so I'm opening up a new PR #1264 to improve it to show something more accurate. Here's the actual stack trace:

image

@antoinerousseau
Copy link

antoinerousseau commented Jan 29, 2024

Thanks @gabrielmfern! But no worries it's not urgent, meanwhile we developed our own minimalist preview that uses RSC and next-intl :)
I'll retry when your fix is out

@ababol
Copy link

ababol commented Jan 30, 2024

Thanks @gabrielmfern!
Btw, we face another issue when using tailwind with media queries

Error: Tailwind: To use responsive styles you must have a element as a direct child of the Tailwind component.

#666 (comment) (see details)

It works perfectly in dev mode but not when we actually build the web app (next build / next start).
This happen when running renderAsync(<Component />) (@react-email/render)
Do you know if your PR actually fix this issue?

@gabrielmfern
Copy link
Collaborator

It works perfectly in dev mode but not when we actually build the web app (next build / next start).
Do you know if your PR actually fix this issue?

Nope, that's something else, someone also had this #1112

@mmachatschek
Copy link

After digging around a lot this should be fixed by #1124 which I have tested myself. Not sure how this is caused but some of the polyfills we have currently on tailwind are causing this—something to do with tslib. ababol antoinerousseau lmk if you are blocked by not using intl here cuz I can make a patch for you from #1124.

@gabrielmfern ist there any possibility to get a patch for this so we can test this? we also seem to run into this exact error.

@gabrielmfern
Copy link
Collaborator

gabrielmfern commented Jan 31, 2024

@mmachatschek Sure, no problem.
Here's a gist of the patch for it

And here is a quick guide of how to apply it if you have any trouble

lmk if it works out for you

@mmachatschek
Copy link

@gabrielmfern the patch didn't solve the issue for me (we are not using the next-intl library but cloudinary-build-url. I do some further debugging of the exact reason.

@justinnais
Copy link

@gabrielmfern patch failed for me also. Using react-intl with the Tailwind component.

@gabrielmfern
Copy link
Collaborator

@mmachatschek @justinnais Could one of you give a reproduction for this? Seems like your issue is something else here 🤔

@gabrielmfern
Copy link
Collaborator

gabrielmfern commented Feb 5, 2024

Also, were you not able to apply the patch or did it apply successfully but still fail when running?

I tried applying it myself and wasn't able to, so I've updated it and it should apply properly now

@justinnais
Copy link

Failed to apply. I'll retry the patch. What's the best way to provide you a repro @gabrielmfern?

@mmachatschek
Copy link

mmachatschek commented Feb 6, 2024

Also, were you not able to apply the patch or did it apply successfully but still fail when running?

I tried applying it myself and wasn't able to, so I've updated it and it should apply properly now

@gabrielmfern for me the patch applied correctly with pnpm

I'll provide a repro asap

@mmachatschek
Copy link

@gabrielmfern this is the reproduction repo: https://github.com/mmachatschek/react-email-repro-issue-1244

check the vercel-invite-user mail

@gabrielmfern
Copy link
Collaborator

@mmachatschek Thank you so much for providing the reproduction here, I applied the patch I sent before and the error wasn't gone. I then realized I sent the wrong patch here, I properly got the diff and swapped the patch with the proper one and it seems to be working fine even with your repro.
I just updated the gist and it should now work just fine. Sorry for the confusion here. cc @justinnais


Also from what I saw you had an issue applying the patch @justinnais; if you were using patch-package for it, you will need to make some changes to the patch which would be quite hard as it is kind of massive atm. I can look into making one specific to patch-package if you want to though, so lmk.

If you used pnpm I also had a few issues applying when copying it from the gist and pasting, maybe you can download and move it to your patches folder and it should work. 🤔

@mmachatschek
Copy link

@gabrielmfern I can confirm that the provided patch is working now 👍

@gijsmin
Copy link

gijsmin commented Mar 12, 2024

When trying to apply your patch, I get the following error:

 ERR_PNPM_PATCH_FAILED  Could not apply patch /Users/user/project/email/patches/[email protected] to Users/user/project/email/node_modules/.pnpm/[email protected]_patch_hash=64x3xoqklzdoazybctmgozwdum_@[email protected][email protected]/node_modules/react-email

Any idea?

@gabrielmfern
Copy link
Collaborator

@gijsmin You need to apply the patch to @react-email/tailwind not to the react-email package.

@tianyingchun
Copy link

what's plan of this PR

@Raphaww
Copy link

Raphaww commented Apr 25, 2024

a specific to patch-package patch would be appreciated since I cannot apply the patch even after modifying it, probably im doing something wrong but can't tell what.
Also, any news on the official release of this patch?
Thank you

@angelhodar
Copy link

Just in case anyone is interesed, after watching this issue I decided to try using the i18next library and its working perfectly. I am using a simple nodejs backend app to send my emails, so you first need to install the libraries:

npm install i18next i18next-fs-backend

Then I have created some simple translations in spanish and english for my email data:

const esMessages = {
  notifications: {
    templates: {
      common: {
        welcome: 'Hola {{name}}',
      },
      forgotPassword: {
        email: {
          preview: "Restablece tu contraseña en Fuel",
          text: 'Parece que has olvidado tu contraseña, pulsa en el botón para poder cambiarla.',
          button: 'CAMBIAR',
          warning: 'Si no has solicitado reestablecer tu contraseña, ignora este mensaje o ponte en contacto con nosotros',
        },
      },
    },
  },
};

export default esMessages;
const enMessages = {
  notifications: {
    templates: {
      common: {
        welcome: 'Hello {{name}}',
      },
      forgotPassword: {
        email: {
          text: 'It looks like you have forgotten your password, click the button to change it.',
          button: 'CHANGE',
          warning: 'If you did not request to reset your password, ignore this message or contact us',
        },
      },
    },
  },
};

export default enMessages;

Now create a i18next instance per locale for performance reasons and just export a function to select the proper locale:

import i18next from 'i18next';
import Backend from 'i18next-fs-backend';
import esMessages from './locales/es';
import enMessages from './locales/en';

const resources = {
  es: { translation: esMessages },
  en: { translation: ptMessages },
};

const createI18nInstance = (locale: string) => {
  const instance = i18next.createInstance();

  instance.use(Backend).init({
    lng: locale,
    fallbackLng: 'es',
    resources,
  });

  return instance;
};

const i18n_es = createI18nInstance('es');
const i18n_en = createI18nInstance('en');

export const getIntl = (locale: string) => {
  return locale === 'en' ? i18n_en : i18n_es;
};

And then just import the getIntl function and use it:

import { Html, Head, Text, Heading, Preview, Section } from '@react-email/components';
import { Container, Header, Footer, FooterText, FooterLinks, Button, Image } from '../components';
import { getIntl } from '../../../../intl';

interface PasswordResetEmailProps {
  name: string;
  resetLink: string;
  locale: string;
}

const PasswordResetEmail = ({ name, resetLink, locale }: PasswordResetEmailProps) => {
  const intl = getIntl(locale);

  return (
    <Html lang={locale}>
      <Head />
      <Preview>{intl.t('notifications.templates.forgotPassword.email.preview')}</Preview>
      <Container>
        <Header />
        <Section className="text-center">
          <Image src="people.jpg" width="200" />
          <Heading className="text-xl text-gray-800 text-center mt-6">
            {intl.t('notifications.templates.common.welcome', { name })}
          </Heading>
          <Text className="text-base text-gray-800 text-center mt-4">
            {intl.t('notifications.templates.forgotPassword.email.text')}
          </Text>
          <Button href={resetLink}>{intl.t('notifications.templates.forgotPassword.email.button')}</Button>
          <Text className="text-base text-gray-800 text-center mt-4">
            {intl.t('notifications.templates.forgotPassword.email.warning')}
          </Text>
        </Section>
        <Footer>
          <FooterLinks />
        </Footer>
      </Container>
    </Html>
  );
};

PasswordResetEmail.PreviewProps = {
  name: 'Nombre',
  resetLink: 'https://example.com/reset-password',
  locale: 'pt',
} as PasswordResetEmailProps;

export default PasswordResetEmail;

I have tested in the dev environment and with a script rendering the component and sending it, both environments working fine! I hope this helps someone

@Pra3t0r5
Copy link

Akin to the solution posted by @angelhodar, i went for a more scriptey solution (previously posted at #431 ):

I have been working on this enhancement to the boilerplate to include internationalization, feel free to use it while i learn how to upgrade the resend's react-email starter:
Screenshot 2024-07-19 at 10 33 31 PM

https://github.com/Pra3t0r5/react-email-intl-starter

It relies on a script to compile email variants based on available internationalization variants. If you don't take into account some standard utils to handle the files, it doesn't add any dependencies.

This code does not includes localization, since we are handling that from our backend data (by knowing the preferred language of each of our users).

As far i know, that is not a goal of react-email either, since you have to handle locales server-side, before actually sending the email.

Feel free to thinker with it to include that feature. I will do it eventually.

@tianyingchun
Copy link

https://github.com/hyperse-io/translator

it can works for react-email i18n , also support react-email dev HMR

import * as React from 'react';
import { createTranslator } from '@hyperse/translator';
import { Button, Html } from '@react-email/components';

const messages = {
 es: {
   PREVIEW: 'Haz click aquí para iniciar sesión con este enlace mágico',
 },
 en: {
   PREVIEW: 'Click here to login with this magic link',
 },
};

export default function Email(props) {
 const { url, languageCode = 'en' } = props;

 const t = createTranslator({
   locale: languageCode,
   messages,
   namespace: languageCode as 'en',
 });

 return (
   <Html lang="en">
     <p>{t('PREVIEW')}</p>
     <Button href={url}>email-address-change</Button>
   </Html>
 );
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.