Lingo.dev 的 CLI 和 本地化 API 支持两种邮件本地化方式:一种是在构建阶段翻译模板文件,产出按语言区域区分的模板;另一种是在发送前于运行时翻译内容。两种方式都会经过已配置的 本地化引擎,并自动套用术语表规则、品牌语气和模型选择。
选择适合你的方案#
| 方案 | 适用场景 | 工作方式 |
|---|---|---|
| 构建阶段(CLI) | 模板文件 - react-email JSON 字符串 | 翻译仓库中的文件,并部署按语言区域区分的模板 |
| 运行时(API) | 动态内容、由 ESP 渲染的模板 | 发送前调用 本地化 API,再将翻译后的内容传给你的邮件服务提供商 |
该怎么选?
如果可翻译的邮件文案以资源文件形式存放在代码仓库中,请使用构建时方案;如果邮件内容是动态生成的,或存放在邮件服务提供商中,请使用运行时方案。
前置条件#
每次翻译都会经过一个本地化引擎——这项配置决定要采用哪种 LLM 模型、术语表、品牌语调和规则。先在 Lingo.dev 控制台中创建一个,再安装并完成 CLI 身份验证:
npm install -g @lingo.dev/cli
lingo loginCLI 需要 Node 22+。在 CI 中,请设置 LINGO_API_KEY,不要运行 lingo login。
构建阶段本地化#
CLI 会基于 JSON 资源文件翻译邮件内容。把可翻译文案提取到 JSON 中,让 CLI 指向这些文件,即可在源文件旁生成各个语言环境的文件。
react-email 模板本质上是可渲染为 HTML 的 React 组件。你可以借助 react-i18next 等 i18n 库,将可翻译字符串提取到 JSON 资源文件中,再用 CLI 翻译这些 JSON 文件。
运行 lingo init 生成配置,再运行 lingo link 关联你的组织和引擎。生成的 .lingo/config.json 如下所示:
{
"orgId": "org_abc123",
"engineId": "eng_abc123",
"sourceLocale": "en",
"targetLocales": ["es", "fr", "de", "ja"],
"files": [{ "pattern": "emails/locales/en.json" }]
}语言环境体现在路径中:CLI 会将模式里的源语言环境替换为各个目标语言环境,因此 emails/locales/en.json 会生成 emails/locales/es.json、emails/locales/fr.json 等文件。请将 .lingo/config.json 提交到代码仓库中。
首次运行时翻译所有语言环境,后续只翻译发生变更的内容:
lingo push --backfill-missing # first run / new locale
lingo push # delta on later runs渲染时,将语言区域传入邮件组件并加载对应的 JSON 文件。react-email 的 render() 函数会生成可直接发送的对应语言区域 HTML。
如果你想随时获取上一次 push 运行的结果,请使用 lingo pull。如果你想在不写入变更的情况下验证翻译是否已是最新状态(例如在 CI 中),请使用 lingo check。
运行时本地化#
当邮件内容是动态的——例如个性化通知、用户生成内容摘要,或存储在 CMS 中的营销文案——应在发送前于运行时完成翻译。这一方案建立在 Translation API 指南 所介绍的模式之上。
async function sendLocalizedEmail(userId, templateId, content) {
const user = await db.users.findById(userId);
const response = await fetch("https://api.lingo.dev/process/localize", {
method: "POST",
headers: {
"X-API-Key": process.env.LINGODOTDEV_API_KEY,
"Content-Type": "application/json",
},
body: JSON.stringify({
engineId: "eng_abc123",
sourceLocale: "en",
targetLocale: user.locale,
data: {
subject: content.subject,
preheader: content.preheader,
body: content.body,
},
}),
});
const { data } = await response.json();
await emailProvider.send({
to: user.email,
subject: data.subject,
html: renderTemplate(templateId, data),
});
}最佳实践#
| 场景 | 建议 |
|---|---|
| 邮件主题 | 尽量控制在 50 个字符以内。使用 术语表 锁定品牌名称,避免被翻译。 |
| 预览文案 | 应与正文分开翻译——邮件客户端会单独展示这部分内容。 |
| 品牌语气 | 在本地化引擎中为 不同语言区域分别配置语气。例如,日语营销邮件所需的语域就与德语不同。 |
| RTL 语言 | 针对阿拉伯语、希伯来语和波斯语,请在邮件客户端中测试渲染结果。不同客户端对 HTML dir="rtl" 的处理方式并不一致。 |
| 键锁定 | 对于不应翻译的 URL、产品名称和法律标识符,请使用 锁定键。 |
