MJML

Lingo.dev CLIを使用したMJMLメールテンプレートのAI翻訳

MJMLとは?

MJML(Mailjet Markup Language)は、レスポンシブなメールテンプレートを簡単に作成できるレスポンシブメールフレームワークです。セマンティックな構文を使用してレスポンシブメールの開発を簡素化し、すべての主要なメールクライアントで動作する標準HTMLにコンパイルされます。

Lingo.dev CLIとは?

Lingo.dev CLIは、AIを使用してアプリやコンテンツを翻訳するための無料のオープンソースCLIです。従来の翻訳管理ソフトウェアを置き換えながら、既存のパイプラインと統合できるように設計されています。

詳細については、概要を参照してください。

このガイドについて

このガイドでは、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. ターゲットロケールの設定

_ターゲットロケール_は、コンテンツを翻訳したい言語と地域です。ターゲットロケールを設定するには、i18n.jsonファイルのlocale.targetsプロパティを設定します。

{
  "$schema": "https://lingo.dev/schema/i18n.json",
  "version": "1.10",
  "locale": {
    "source": "en",
    "targets": ["es"]
  },
  "buckets": {}
}

ステップ4. ソースコンテンツの作成

まだ作成していない場合は、翻訳対象のコンテンツを含む1つ以上の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要素:ph1-h6li
  • 属性値には以下が含まれます:
    • mj-imagealtおよびtitle属性
    • mj-buttontitleおよびaria-label属性
    • mj-social-elementtitleおよびalt属性
    • HTMLimgおよびa要素のaltおよびtitle属性

インラインHTMLの処理方法:

テキストにインラインHTML要素(<strong><span><em><a>など)が含まれている場合、テキストブロック全体が1つの完全な単位として翻訳されます。これにより、翻訳品質を向上させるためのコンテキストが保持され、インライン書式が維持されます。

例:

<mj-text>
  <p>Welcome to <strong>our platform</strong>!</p>
</mj-text>

段落全体"Welcome to <strong>our platform</strong>!"が単一のブロックとして翻訳され、<strong>タグがそのまま保持されます。これにより、AI翻訳者が完全なコンテキストを持ち、翻訳でもインライン書式が保持されます。

テンプレート変数(Razor変数@Model.UserNameなど)は翻訳中も保持されます。

ステップ5. バケットを作成する

  1. i18n.jsonファイルに、bucketsオブジェクトへ"mjml"オブジェクトを追加します:

    {
      "$schema": "https://lingo.dev/schema/i18n.json",
      "version": "1.10",
      "locale": {
        "source": "en",
        "targets": ["es"]
      },
      "buckets": {
        "mjml": {}
      }
    }
    
  2. "mjml"オブジェクト内で、1つ以上の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の使用をお勧めします:

  1. Lingo.devアカウントにサインアップします。

  2. 次のコマンドを実行します:

    npx lingo.dev@latest login
    

    これによりデフォルトのブラウザが開き、認証を求められます。

  3. プロンプトに従います。

ステップ7. 翻訳を生成する

i18n.jsonファイルを含むディレクトリで、次のコマンドを実行します:

npx lingo.dev@latest run

このコマンドは:

  1. i18n.jsonファイルを読み込みます。
  2. 翻訳が必要なファイルを検索します。
  3. ファイルから翻訳可能なコンテンツを抽出します。
  4. 設定されたLLMを使用して抽出されたコンテンツを翻訳します。
  5. 翻訳されたコンテンツをファイルシステムに書き戻します。

翻訳が初めて生成されると、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