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 code | Language |
|---|---|
ar | Arabic |
he | Hebrew |
fa | Persian |
ur | Urdu |
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 });