MJML
使用 Lingo.dev CLI 对 MJML 邮件模板进行 AI 翻译
什么是 MJML?
MJML(Mailjet Markup Language)是一套响应式邮件框架,可帮助开发者轻松创建响应式邮件模板。它采用语义化语法,简化了响应式邮件的开发流程,并可编译为兼容所有主流邮件客户端的标准 HTML。
什么是 Lingo.dev CLI?
Lingo.dev CLI 是一款免费、开源的命令行工具,支持通过 AI 翻译应用和内容。它旨在取代传统的翻译管理软件,并可集成到现有的开发流水线中。
如需了解更多,请参阅 概述。
关于本指南
本指南将介绍如何使用 Lingo.dev CLI 翻译 MJML 邮件模板。
你将学到如何:
- 从零创建项目
- 配置翻译流水线
- 使用 AI 生成翻译内容
前置条件
要使用 Lingo.dev CLI,请确保已安装 Node.js v18 及以上版本:
❯ node -v
v22.17.0
第 1 步:创建项目
在你的项目目录下,创建一个 i18n.json 文件:
{
"$schema": "https://lingo.dev/schema/i18n.json",
"version": "1.10",
"locale": {
"source": "en",
"targets": ["es"]
},
"buckets": {}
}
该文件用于定义翻译流水线的行为,包括需要翻译的语言以及本地化内容在文件系统中的位置。
如需了解可用属性,请参阅 i18n.json。
第 2 步:配置源语言环境
源语言环境 指内容最初编写时所用的语言和地区。要配置源语言环境,请在 i18n.json 文件中设置 locale.source 属性:
{
"$schema": "https://lingo.dev/schema/i18n.json",
"version": "1.10",
"locale": {
"source": "en",
"targets": ["es"]
},
"buckets": {}
}
源语言环境必须采用 BCP 47 语言标签 格式。
如需查看 Lingo.dev CLI 支持的全部语言环境代码,请参阅 支持的语言环境代码。
第 3 步:配置目标语言环境
目标语言环境 指的是您希望将内容翻译成的语言和地区。要配置目标语言环境,请在 locale.targets 属性中设置 i18n.json 文件:
{
"$schema": "https://lingo.dev/schema/i18n.json",
"version": "1.10",
"locale": {
"source": "en",
"targets": ["es"]
},
"buckets": {}
}
第 4 步:创建源内容
如果尚未创建,请新建一个或多个包含待翻译内容的 MJML 模板文件。这些文件的路径中必须包含源语言环境(例如,作为目录名 en/,或作为文件名的一部分 example_en.mjml)。
对于 MJML 模板,可翻译内容包括:
- MJML 组件中的文本内容:
mj-text(正文)mj-button(按钮标签)mj-title(预览中的邮件标题)mj-preview(预览文本)mj-navbar-link(导航链接)mj-accordion-title(手风琴标题)mj-accordion-text(手风琴内容)
- MJML 中的 HTML 元素:
p、h1-h6、li - 属性值,包括:
alt和title属性(在mj-image上)title和aria-label属性(在mj-button上)title和alt属性(在mj-social-element上)- HTML
img和a元素上的alt和title属性
内联 HTML 的处理方式:
当文本包含内联 HTML 元素(如 <strong>、<span>、<em>、<a> 等)时,整个文本块会作为一个完整单元进行翻译。这可以保留上下文信息,提高翻译质量,并保持内联格式。
例如:
<mj-text>
<p>Welcome to <strong>our platform</strong>!</p>
</mj-text>
整个段落 "Welcome to <strong>our platform</strong>!" 会作为一个整体进行翻译,并保留 <strong> 标签。这样可以确保 AI 翻译器拥有完整上下文,并在翻译中保留内联格式。
模板变量(如 Razor 变量 @Model.UserName)在翻译过程中会被保留。
步骤 5. 创建 bucket
-
在
i18n.json文件中,向buckets对象添加一个"mjml"对象:{ "$schema": "https://lingo.dev/schema/i18n.json", "version": "1.10", "locale": { "source": "en", "targets": ["es"] }, "buckets": { "mjml": {} } } -
在
"mjml"对象中,定义一个包含一个或多个include模式的数组:{ "$schema": "https://lingo.dev/schema/i18n.json", "version": "1.10", "locale": { "source": "en", "targets": ["es"] }, "buckets": { "mjml": { "include": ["./[locale]/example.mjml"] } } }这些模式用于定义需要翻译的文件。
模式本身:
- 必须包含
[locale]作为已配置语言区域的占位符 - 可以指向文件路径(如
"[locale]/example.mjml") - 可以使用星号作为通配符(如
"[locale]/*.mjml")
不支持递归 glob 模式(如
**/*.mjml)。 - 必须包含
步骤 6. 配置 LLM
Lingo.dev CLI 使用大型语言模型(LLM)通过 AI 翻译内容。要使用这些模型之一,您需要从支持的服务商获取 API 密钥。
为了尽快开始使用,我们推荐使用 Lingo.dev Engine:
-
运行以下命令:
npx lingo.dev@latest login这将打开您的默认浏览器,并要求您进行身份验证。
-
按照提示操作。
步骤 7. 生成翻译内容
在包含 i18n.json 文件的目录下,运行以下命令:
npx lingo.dev@latest run
该命令将:
- 读取
i18n.json文件。 - 查找需要翻译的文件。
- 从文件中提取可翻译内容。
- 使用已配置的 LLM 翻译提取的内容。
- 将翻译后的内容写回文件系统。
首次生成翻译时,会创建一个 i18n.lock 文件。该文件用于记录已翻译的内容,防止后续运行时重复翻译。
示例
en/example.mjml
<?xml version="1.0" encoding="UTF-8"?>
<mjml>
<mj-head>
<mj-title>Welcome to Our Service</mj-title>
<mj-preview>Get started with your new account today</mj-preview>
<mj-attributes>
<mj-all font-family="Arial, sans-serif" />
</mj-attributes>
</mj-head>
<mj-body>
<mj-section background-color="#f0f0f0">
<mj-column>
<mj-image
src="https://example.com/logo.png"
alt="Company Logo"
width="150px"
/>
</mj-column>
</mj-section>
<mj-section background-color="#ffffff" padding="20px">
<mj-column>
<mj-text font-size="24px" color="#333333" font-weight="bold">
Welcome to Our Platform!
</mj-text>
<mj-text font-size="16px" color="#555555" line-height="24px">
Thank you for signing up. We're excited to have you on board.
</mj-text>
<mj-text font-size="16px" color="#555555" line-height="24px">
To get started, please verify your email address by clicking the
button below.
</mj-text>
</mj-column>
</mj-section>
<mj-section background-color="#ffffff" padding="20px">
<mj-column>
<mj-button
background-color="#007bff"
color="#ffffff"
href="https://example.com/verify"
title="Verify your email address"
aria-label="Verify email"
>
Verify Email Address!
</mj-button>
</mj-column>
</mj-section>
<mj-section background-color="#ffffff" padding="20px">
<mj-column>
<mj-text font-size="14px" color="#666666">
If you didn't create an account, you can safely ignore this email.
</mj-text>
<mj-text font-size="14px" color="#666666">
Need help? Contact our support team.
</mj-text>
</mj-column>
</mj-section>
<mj-section background-color="#f8f9fa" padding="20px">
<mj-column>
<mj-social mode="horizontal">
<mj-social-element
name="facebook"
href="https://facebook.com/example"
title="Follow us on Facebook"
alt="Facebook"
/>
<mj-social-element
name="twitter"
href="https://twitter.com/example"
title="Follow us on Twitter"
alt="Twitter"
/>
<mj-social-element
name="instagram"
href="https://instagram.com/example"
title="Follow us on Instagram"
alt="Instagram"
/>
</mj-social>
<mj-text font-size="12px" color="#999999" align="center">
© 2024 Example Company. All rights reserved.
</mj-text>
</mj-column>
</mj-section>
</mj-body>
</mjml>
es/example.mjml
<?xml version="1.0" encoding="UTF-8"?>
<mjml>
<mj-head>
<mj-title>Bienvenido a nuestro servicio</mj-title>
<mj-preview>Comienza con tu nueva cuenta hoy</mj-preview>
<mj-attributes>
<mj-all font-family="Arial, sans-serif" />
</mj-attributes>
</mj-head>
<mj-body>
<mj-section background-color="#f0f0f0">
<mj-column>
<mj-image
src="https://example.com/logo.png"
alt="Logo de la empresa"
width="150px"
/>
</mj-column>
</mj-section>
<mj-section background-color="#ffffff" padding="20px">
<mj-column>
<mj-text font-size="24px" color="#333333" font-weight="bold">
¡Bienvenido a nuestra plataforma!
</mj-text>
<mj-text font-size="16px" color="#555555" line-height="24px">
Gracias por registrarte. Estamos encantados de tenerte con nosotros.
</mj-text>
<mj-text font-size="16px" color="#555555" line-height="24px">
Para comenzar, por favor verifica tu dirección de correo electrónico
haciendo clic en el botón de abajo.
</mj-text>
</mj-column>
</mj-section>
<mj-section background-color="#ffffff" padding="20px">
<mj-column>
<mj-button
background-color="#007bff"
color="#ffffff"
href="https://example.com/verify"
title="Verifica tu dirección de correo electrónico"
aria-label="Verificar correo"
>
¡Verificar dirección de correo!
</mj-button>
</mj-column>
</mj-section>
<mj-section background-color="#ffffff" padding="20px">
<mj-column>
<mj-text font-size="14px" color="#666666">
Si no creaste una cuenta, puedes ignorar este correo electrónico.
</mj-text>
<mj-text font-size="14px" color="#666666">
¿Necesitas ayuda? Contacta a nuestro equipo de soporte.
</mj-text>
</mj-column>
</mj-section>
<mj-section background-color="#f8f9fa" padding="20px">
<mj-column>
<mj-social mode="horizontal">
<mj-social-element
name="facebook"
href="https://facebook.com/example"
title="Síguenos en Facebook"
alt="Facebook"
/>
<mj-social-element
name="twitter"
href="https://twitter.com/example"
title="Síguenos en Twitter"
alt="Twitter"
/>
<mj-social-element
name="instagram"
href="https://instagram.com/example"
title="Síguenos en Instagram"
alt="Instagram"
/>
</mj-social>
<mj-text font-size="12px" color="#999999" align="center">
© 2024 Example Company. Todos los derechos reservados.
</mj-text>
</mj-column>
</mj-section>
</mj-body>
</mjml>
i18n.json
{
"$schema": "https://lingo.dev/schema/i18n.json",
"version": "1.10",
"locale": {
"source": "en",
"targets": ["es"]
},
"buckets": {
"mjml": {
"include": ["./[locale]/example.mjml"]
}
}
}
i18n.lock
version: 1
checksums:
c1acde0589961652d4caf8a39d080857:
mjml/mj-head/0/mj-title/0: c514a686b50f7158b2dd08ea65d3bc8a
mjml/mj-head/0/mj-preview/0: 4ce14f6062c814cbdcdf8b0a3cb094d3
mjml/mj-body/0/mj-section/0/mj-column/0/mj-image/0#alt: 82d5c0d5994508210ee02d684819f4b8
mjml/mj-body/0/mj-section/1/mj-column/0/mj-text/0: b320b02942617a70dcbd1beac61da11a
mjml/mj-body/0/mj-section/1/mj-column/0/mj-text/1: 028311348a5aeefea365fdf422a3fb21
mjml/mj-body/0/mj-section/1/mj-column/0/mj-text/2: 0dfdc9b80ee70fcc2b28d0e81e03fabc
mjml/mj-body/0/mj-section/2/mj-column/0/mj-button/0#title: 5c96f738bd6153ee07b72094cdfd2b98
mjml/mj-body/0/mj-section/2/mj-column/0/mj-button/0#aria-label: 42dcab68d931f9145d9b6d76740a5c66
mjml/mj-body/0/mj-section/2/mj-column/0/mj-button/0: dc8001d5c58294d22fe0b0e6118dbfb7
mjml/mj-body/0/mj-section/3/mj-column/0/mj-text/0: a18f14ab69467cbdbe467df6255cfda7
mjml/mj-body/0/mj-section/3/mj-column/0/mj-text/1: e83236e98aad1937bc99a47cff159caa
mjml/mj-body/0/mj-section/4/mj-column/0/mj-social/0/mj-social-element/0#title: 180bd8aa700f6cedf65e0a2079503cea
mjml/mj-body/0/mj-section/4/mj-column/0/mj-social/0/mj-social-element/0#alt: ac8afe226a7424849c247e6a9d566f64
mjml/mj-body/0/mj-section/4/mj-column/0/mj-social/0/mj-social-element/1#title: ea4c2a7a9a60cbb0f8f9632222a46abe
mjml/mj-body/0/mj-section/4/mj-column/0/mj-social/0/mj-social-element/1#alt: ba3d4aed69a50759b53a0b7c319a3ad9
mjml/mj-body/0/mj-section/4/mj-column/0/mj-social/0/mj-social-element/2#title: 754efa5f98f51c510ff268e217877d8b
mjml/mj-body/0/mj-section/4/mj-column/0/mj-social/0/mj-social-element/2#alt: c9555810826c30d571ffae869a236494
mjml/mj-body/0/mj-section/4/mj-column/0/mj-text/0: 9ac6c625c7af33d70634846c8c9d11b0