apps/docs/guides/internationalization/react-i18next.mdx
React Email supports react-i18next for internationalization.
This guide shows how to convert an English React Email template to support multiple locales.
To get the most out of this guide, you’ll need to:
<CodeGroup> ```bash npm npm i -S react-i18next i18next i18next-resources-to-backend ```bun add react-i18next i18next i18next-resources-to-backend
yarn add react-i18next i18next i18next-resources-to-backend
pnpm add react-i18next i18next i18next-resources-to-backend
This guide will use the following email template as a base.
export default function WelcomeEmail({ name }) {
return (
<Html>
<Head />
<Preview>Welcome to Acme</Preview>
<Tailwind>
<Body className="bg-gray-100 font-sans">
<Container className="mx-auto py-10 px-5">
<Section className="bg-white rounded-lg p-8">
<Heading className="text-2xl font-bold text-gray-900 m-0 mb-6">
Welcome to Acme
</Heading>
<Text className="text-base leading-6 text-gray-600 m-0 mb-4">
Hi {name}
</Text>
<Text className="text-base leading-6 text-gray-600 m-0 mb-4">
Thanks for signing up! We're excited to have you on board.
</Text>
<Button
href="https://example.com/dashboard"
className="bg-indigo-600 rounded-md text-white text-base font-semibold no-underline text-center block py-3 px-6 my-6"
>
Get Started
</Button>
<Hr className="border-gray-200 my-6" />
<Text className="text-sm text-gray-400 m-0">
If you have any questions, reply to this email. We're here to help!
</Text>
</Section>
</Container>
</Body>
</Tailwind>
</Html>
);
}
WelcomeEmail.PreviewProps = {
name: 'John Lennon',
};
react-i18next is a library for internationalization and localization that provides a way to format messages in different languages.
For each locale, create a new JSON file containing the content of the email in that locale.
<CodeGroup>{
"header": "Welcome to Acme",
"hi": "Hi",
"thanks": "Thanks for signing up! We're excited to have you on board.",
"get-started": "Get Started",
"questions": "If you have any questions, reply to this email. We're here to help!"
}
{
"header": "Bienvenido a Acme",
"hi": "Hola",
"thanks": "Gracias por registrarte! Estamos emocionados de tenerte en la plataforma.",
"get-started": "Comenzar",
"questions": "Si tienes alguna pregunta, responde a este correo electrónico. Estamos aquí para ayudarte!"
}
{
"header": "Bem-vindo ao Acme",
"hi": "Olá",
"thanks": "Obrigado por se inscrever! Estamos ansiosos para te receber na plataforma.",
"get-started": "Começar",
"questions": "Se você tiver alguma dúvida, responda a este e-mail. Estamos aqui para ajudar!"
}
Add the locale prop to the email template, interface, and test data.
// [!code --]
export default function WelcomeEmail({ name }) {
// [!code ++]
export default function WelcomeEmail({ name, locale }) {
return (
...
);
}
WelcomeEmail.PreviewProps = {
name: 'John Lennon',
// [!code ++]
locale: 'en',
};
If you don't already, go ahead and create a getT helper meant for getting translations on the server:
import { i18next } from './i18n';
export async function getT(namespace, locale) {
if (locale && i18next.resolvedLanguage !== locale) {
await i18next.changeLanguage(locale)
}
if (namespace && !i18next.hasLoadedNamespace(namespace)) {
await i18next.loadNamespaces(namespace)
}
return {
t: i18next.getFixedT(
locale ?? i18next.resolvedLanguage,
Array.isArray(namespace) ? namespace[0] : namespace,
),
i18n: i18next
}
}
Where ./i18n is where you would have setup your i18next, for example:
import i18next, { loadNamespaces } from 'i18next';
import resourcesToBackend from 'i18next-resources-to-backend';
import { initReactI18next } from 'react-i18next';
i18next
.use(initReactI18next)
.use(resourcesToBackend((language, namespace) => import(`messages/${language}/${namespace}.json`)))
.init({
supportedLngs: ['en', 'es', 'pt'],
fallbackLng: 'en',
lng: undefined,
detection: {
order: ['path', 'htmlTag', 'cookie', 'navigator']
},
preload: typeof window === 'undefined' ? ['en', 'es', 'pt'] : [],
});
export { i18next };
In the email template, remove the hardcoded content and use getT's t to format the email message strings.
// [!code ++]
import { getT } from '../get-t';
export default async function WelcomeEmail({ name, locale }) {
// [!code ++]
const { t } = await getT('welcome-email', locale);
return (
<Html>
<Head />
// [!code --]
<Preview>Welcome to Acme</Preview>
// [!code ++]
<Preview>{t('header')}</Preview>
<Tailwind>
<Body className="bg-gray-100 font-sans">
<Container className="mx-auto py-10 px-5">
<Section className="bg-white rounded-lg p-8">
<Heading className="text-2xl font-bold text-gray-900 m-0 mb-6">
// [!code --]
Welcome to Acme
// [!code ++]
{t('header')}
</Heading>
<Text className="text-base leading-6 text-gray-600 m-0 mb-4">
// [!code --]
Hi {name}
// [!code ++]
{t('hi')} {name}
</Text>
<Text className="text-base leading-6 text-gray-600 m-0 mb-4">
// [!code --]
Thanks for signing up! We're excited to have you on board.
// [!code ++]
{t('thanks')}
</Text>
<Button
href="https://example.com/dashboard"
className="bg-indigo-600 rounded-md text-white text-base font-semibold no-underline text-center block py-3 px-6 my-6"
>
// [!code --]
Get Started
// [!code ++]
{t('get-started')}
</Button>
<Hr className="border-gray-200 my-6" />
<Text className="text-sm text-gray-400 m-0">
// [!code --]
If you have any questions, reply to this email. We're here to help!
// [!code ++]
{t('questions')}
</Text>
</Section>
</Container>
</Body>
</Tailwind>
</Html>
);
}
WelcomeEmail.PreviewProps = {
name: 'John Lennon',
locale: 'en',
};
When calling the email template, pass the locale prop to the email component.