i18n-email

Usage

Translate your first email with i18n-email.

Create a client

Call createI18nEmail once with your config and reuse the returned instance across your app.

import { createI18nEmail } from "i18n-email";

const i18nEmail = createI18nEmail({
  openaiApiKey: process.env.OPENAI_API_KEY!,
});

With a React Email component

Pass your React Email component to react. It will be rendered to HTML automatically before translation.

import { WelcomeEmail } from "./emails/welcome";

const { subject, html } = await i18nEmail.translate({
  locale: "fr",
  subject: "Welcome!",
  react: <WelcomeEmail name="Dan" />,
});

With raw HTML

If you already have an HTML string, pass it to html instead.

const { subject, html } = await i18nEmail.translate({
  locale: "de",
  subject: "Welcome!",
  html: "<h1>Welcome!</h1><p>Your account has been created.</p>",
});

react and html are mutually exclusive. Providing both will cause a TypeScript error.

Sending with Resend

translate returns { subject, html }, which you can spread directly into a Resend send call.

import { Resend } from "resend";

const resend = new Resend(process.env.RESEND_API_KEY);

await resend.emails.send({
  from: process.env.RESEND_FROM!,
  to: "user@example.com",
  ...(await i18nEmail.translate({
    locale: "pl",
    subject: "Welcome!",
    react: <WelcomeEmail name="Dan" />,
  })),
});

Same-locale detection

If the source email is already written in the target locale, the OpenAI response will indicate a matching detectedLocale. In that case, translate returns the original subject and html unchanged — no unnecessary edits are made to the content.

RTL locales

For right-to-left languages, dir="rtl" is injected on the root <html> element automatically. No extra configuration is needed.

Locale codeLanguage
arArabic
heHebrew
faPersian
urUrdu

Choosing a model

By default, gpt-4o is used with the OpenAI client. You can override this with the model option:

const i18nEmail = createI18nEmail({
  openaiApiKey: process.env.OPENAI_API_KEY!,
  model: "gpt-4o-mini",
});

With AI SDK

Pass any Vercel AI SDK model instance instead of a string. When you do, openaiApiKey is not required — the provider handles authentication.

import { createI18nEmail } from "i18n-email";
import { openai } from "@ai-sdk/openai";

const i18nEmail = createI18nEmail({
  model: openai("gpt-4o"),
});

Works with any provider:

import { anthropic } from "@ai-sdk/anthropic";

const i18nEmail = createI18nEmail({
  model: anthropic("claude-4-sonnet"),
});
import { google } from "@ai-sdk/google";

const i18nEmail = createI18nEmail({
  model: google("gemini-2.5-pro"),
});

With TanStack AI

Pass a TanStack AI adapter as adapter. Authentication is handled by the adapter itself — no openaiApiKey needed.

import { createI18nEmail } from "i18n-email";
import { createOpenaiChat } from "@tanstack/ai-openai";

const openai = createOpenaiChat("gpt-4o", process.env.OPENAI_API_KEY!);

const i18nEmail = createI18nEmail({ adapter: openai });

On this page