Advanced Installer (AIL)

使用 Lingo.dev CLI 对 Advanced Installer 本地化文件进行 AI 翻译

什么是 Advanced Installer AIL?

Advanced Installer 是一款 Windows 安装包制作工具,帮助开发者创建 MSI(Microsoft Installer)安装包。AIL(Advanced Installer Localization)是一种基于 XML 的多语言词典格式,用于本地化安装程序对话框、按钮、消息和属性。多语言的所有翻译内容都存储在同一个 AIL 文件中。

什么是 Lingo.dev CLI?

Lingo.dev CLI 是一款免费、开源的命令行工具,可通过 AI 翻译应用和内容。它旨在替代传统的翻译管理软件,并可集成到现有的开发流水线中。

如需了解更多,请参见 概述

关于本指南

本指南介绍如何使用 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 步:配置目标语言环境

目标语言环境 指的是您希望将内容翻译成的语言和地区。要配置目标语言环境,请在 locale.targets 属性中于 i18n.json 文件进行设置:

{
  "$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 - 欢迎对话框的标题文本
  • Control.Button.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 bucket 会直接修改原始文件,而不是为每个语言环境创建单独的文件。运行翻译时,CLI 会在现有的 AIL 文件中为目标语言环境添加或更新 STRING 元素。这是因为 AIL 文件设计为在单个文件中存储所有语言的翻译内容。

步骤 5. 创建 bucket

  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