Advanced Installer (AIL)

Lingo.dev CLI를 사용한 Advanced Installer 로컬라이제이션 파일의 AI 번역

Advanced Installer AIL이란?

Advanced Installer는 개발자가 MSI(Microsoft Installer) 패키지를 생성할 수 있도록 돕는 Windows 설치 프로그램 제작 도구입니다. AIL(Advanced Installer Localization)은 설치 프로그램 대화 상자, 버튼, 메시지 및 속성을 로컬라이즈하는 데 사용되는 XML 기반 다국어 사전 형식입니다. 여러 언어에 대한 모든 번역은 단일 AIL 파일에 저장됩니다.

Lingo.dev CLI란?

Lingo.dev CLI는 AI를 사용하여 앱과 콘텐츠를 번역하는 무료 오픈 소스 CLI입니다. 기존 파이프라인과 통합하면서 기존 번역 관리 소프트웨어를 대체하도록 설계되었습니다.

자세한 내용은 개요를 참조하세요.

이 가이드 정보

이 가이드는 Lingo.dev CLI를 사용하여 Advanced Installer AIL 파일을 번역하는 방법을 설명합니다.

다음 내용을 배우게 됩니다:

  • 처음부터 프로젝트 생성하기
  • 번역 파이프라인 구성하기
  • 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단계. 소스 콘텐츠 생성하기

아직 생성하지 않았다면, 번역할 콘텐츠가 포함된 AIL 파일을 생성하세요. AIL 파일은 모든 언어 번역이 단일 파일에 저장되는 XML 구조를 사용합니다.

파일 구조:

<?xml version="1.0" encoding="UTF-8"?>
<DICTIONARY type="multilanguage">
  <ENTRY id="Control.Text.WelcomeDlg#Title">
    <STRING lang="en" value="Welcome to the Setup Wizard"/>
  </ENTRY>
  <ENTRY id="Control.Button.Next">
    <STRING lang="en" value="Next"/>
  </ENTRY>
</DICTIONARY>

번역 가능한 콘텐츠:

  • ENTRY 요소는 고유한 id 속성을 가진 번역 가능한 문자열을 나타냅니다
  • ENTRY 내의 STRING 요소는 특정 언어에 대한 번역을 포함합니다
  • lang 속성은 언어 코드를 지정합니다
  • value 속성은 번역 가능한 텍스트를 포함합니다

엔트리 ID 규칙:

AIL 파일은 인스톨러 콘텐츠를 구성하기 위해 구조화된 ID를 사용합니다:

  • 컨트롤 텍스트: Control.Text.DialogName#ElementName
  • 컨트롤 버튼: Control.Button.ButtonName
  • 속성: Property.PropertyName

예시:

  • Control.Text.WelcomeDlg#Title - Welcome 대화상자의 제목 텍스트
  • Control.Button.Next - Next 버튼의 텍스트
  • Property.ProductName - 제품명 속성

Advanced Installer 변수:

AIL 파일은 런타임에 대체되는 Advanced Installer 변수를 지원합니다:

  • [ProductName] - 제품명으로 대체됩니다
  • [ProductVersion] - 제품 버전으로 대체됩니다
  • [Manufacturer] - 제조사명으로 대체됩니다

이러한 변수는 번역 중에 보존됩니다:

<ENTRY id="Control.Text.WelcomeDlg#Title">
  <STRING lang="en" value="Welcome to [ProductName] Setup"/>
</ENTRY>

출력 모드:

AIL 버킷은 각 로케일에 대해 별도의 파일을 생성하는 대신 원본 파일을 변경합니다. 번역을 실행하면 CLI는 기존 AIL 파일 내에서 타겟 로케일에 대한 STRING 요소를 추가하거나 업데이트합니다. 이는 AIL 파일이 모든 언어 번역을 단일 파일에 저장하도록 설계되었기 때문입니다.

5단계. 버킷 생성

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

    {
      "$schema": "https://lingo.dev/schema/i18n.json",
      "version": "1.10",
      "locale": {
        "source": "en",
        "targets": ["es"]
      },
      "buckets": {
        "ail": {}
      }
    }
    
  2. "ail" 객체에서 하나 이상의 include 패턴 배열을 정의합니다:

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

    이 패턴들은 번역할 파일을 정의합니다.

    패턴 자체는:

    • 파일 경로를 가리킬 수 있습니다(예: "./installer.ail")
    • 와일드카드 자리 표시자로 별표를 사용할 수 있습니다(예: "./*.ail")
    • [locale] 자리 표시자를 사용하지 않습니다(모든 로케일이 동일한 파일에 있기 때문)

    재귀 glob 패턴(예: **/*.ail)은 지원되지 않습니다.

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 파일이 생성됩니다. 이 파일은 번역된 콘텐츠를 추적하여 후속 실행 시 불필요한 재번역을 방지합니다.

예제

번역 전 (example.ail)

<?xml version="1.0" encoding="UTF-8"?>
<DICTIONARY type="multilanguage">
  <ENTRY id="Control.Text.WelcomeDlg#Title">
    <STRING lang="en" value="Welcome to the [ProductName] Setup Wizard"/>
  </ENTRY>
  <ENTRY id="Control.Text.WelcomeDlg#Description">
    <STRING lang="en" value="The Setup Wizard will install [ProductName] on your computer. Click Next to continue or Cancel to exit the Setup Wizard."/>
  </ENTRY>
  <ENTRY id="Control.Text.LicenseAgreementDlg#Title">
    <STRING lang="en" value="End-User License Agreement"/>
  </ENTRY>
  <ENTRY id="Control.Text.LicenseAgreementDlg#AcceptCheckbox">
    <STRING lang="en" value="I accept the terms in the License Agreement"/>
  </ENTRY>
  <ENTRY id="Control.Button.Next">
    <STRING lang="en" value="Next"/>
  </ENTRY>
  <ENTRY id="Control.Button.Cancel">
    <STRING lang="en" value="Cancel"/>
  </ENTRY>
  <ENTRY id="Property.ProductName">
    <STRING lang="en" value="My Application"/>
  </ENTRY>
</DICTIONARY>

번역 후 (example.ail)

<?xml version="1.0" encoding="UTF-8"?>
<DICTIONARY type="multilanguage">
  <ENTRY id="Control.Text.WelcomeDlg#Title">
    <STRING lang="en" value="Welcome to the [ProductName] Setup Wizard"/>
    <STRING lang="es" value="Bienvenido al asistente de instalación de [ProductName]"/>
  </ENTRY>
  <ENTRY id="Control.Text.WelcomeDlg#Description">
    <STRING lang="en" value="The Setup Wizard will install [ProductName] on your computer. Click Next to continue or Cancel to exit the Setup Wizard."/>
    <STRING lang="es" value="El asistente de instalación instalará [ProductName] en su ordenador. Haga clic en Siguiente para continuar o en Cancelar para salir del asistente de instalación."/>
  </ENTRY>
  <ENTRY id="Control.Text.LicenseAgreementDlg#Title">
    <STRING lang="en" value="End-User License Agreement"/>
    <STRING lang="es" value="Acuerdo de licencia para el usuario final"/>
  </ENTRY>
  <ENTRY id="Control.Text.LicenseAgreementDlg#AcceptCheckbox">
    <STRING lang="en" value="I accept the terms in the License Agreement"/>
    <STRING lang="es" value="Acepto los términos del acuerdo de licencia"/>
  </ENTRY>
  <ENTRY id="Control.Button.Next">
    <STRING lang="en" value="Next"/>
    <STRING lang="es" value="Siguiente"/>
  </ENTRY>
  <ENTRY id="Control.Button.Cancel">
    <STRING lang="en" value="Cancel"/>
    <STRING lang="es" value="Cancelar"/>
  </ENTRY>
  <ENTRY id="Property.ProductName">
    <STRING lang="en" value="My Application"/>
    <STRING lang="es" value="My Application"/>
  </ENTRY>
</DICTIONARY>

i18n.json

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

i18n.lock

version: 1
checksums:
  f84d41a1c3ad7e70e25c84811ef9baef:
    Control.Text.WelcomeDlg%23Title: 93af4b47a8c0a84ce9fb82d2ee2bca13
    Control.Text.WelcomeDlg%23Description: 9cbc6500217ae2a7b3ffd74a3c723493
    Control.Text.LicenseAgreementDlg%23Title: 3fe6d3757d7129ede78b41dd06042bf2
    Control.Text.LicenseAgreementDlg%23AcceptCheckbox: 768d9d11db014facbc1b65af8e39e260
    Control.Button.Next: 4c49d903308e8e3f5c866cfd78ef0e89
    Control.Button.Cancel: a149e8d5b349f68b3cfc9fbe6b23cbb4
    Property.ProductName: c215a8d46c95f00089c5ea0d17eef742