MJML
AI-перевод шаблонов писем MJML с помощью Lingo.dev CLI
Что такое MJML?
MJML (Mailjet Markup Language) — это фреймворк для создания адаптивных email-шаблонов. Он использует семантический синтаксис, который упрощает разработку адаптивных писем, и компилируется в стандартный HTML, поддерживаемый всеми основными почтовыми клиентами.
Что такое Lingo.dev CLI?
Lingo.dev CLI — это бесплатный open-source CLI для перевода приложений и контента с помощью ИИ. Он создан, чтобы заменить традиционные системы управления переводами и легко интегрируется в существующие пайплайны.
Подробнее см. в разделе Обзор.
О данном руководстве
В этом гайде рассказывается, как переводить email-шаблоны MJML с помощью Lingo.dev CLI.
Вы узнаете, как:
- Создать проект с нуля
- Настроить пайплайн перевода
- Генерировать переводы с помощью ИИ
Необходимые условия
Для работы с 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. Настройте исходную локаль
Исходная локаль — это оригинальный язык и регион, на которых был написан ваш контент. Чтобы настроить исходную локаль, укажите свойство locale.source в файле i18n.json:
{
"$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(контент аккордеона)
- HTML-элементы внутри MJML:
p,h1-h6,li - Значения атрибутов, включая:
- атрибуты
altиtitleуmj-image - атрибуты
titleиaria-labelуmj-button - атрибуты
titleиaltуmj-social-element - атрибуты
altиtitleу HTML-элементовimgиa
- атрибуты
Как обрабатывается встроенный 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добавьте объект"mjml"в объектbuckets:{ "$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") - могут использовать звёздочки как wildcard-плейсхолдеры (например,
"[locale]/*.mjml")
Рекурсивные glob-паттерны (например,
**/*.mjml) не поддерживаются. - должны содержать
Шаг 6. Настройте LLM
Lingo.dev CLI использует большие языковые модели (LLM) для перевода контента с помощью ИИ. Чтобы использовать одну из этих моделей, вам нужен 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