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단계. 소스 콘텐츠 생성하기

아직 생성하지 않았다면, 번역할 콘텐츠가 포함된 하나 이상의 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
  • 다음을 포함한 속성 값:
    • mj-imagealttitle 속성
    • mj-buttontitlearia-label 속성
    • mj-social-elementtitlealt 속성
    • HTML imga 요소의 alttitle 속성

인라인 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단계. 버킷 생성

  1. i18n.json 파일에서 buckets 객체에 "mjml" 객체를 추가합니다:

    {
      "$schema": "https://lingo.dev/schema/i18n.json",
      "version": "1.10",
      "locale": {
        "source": "en",
        "targets": ["es"]
      },
      "buckets": {
        "mjml": {}
      }
    }
    
  2. "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 사용을 권장합니다:

  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