Advanced Installer (AIL)

AI translation for Advanced Installer localization files with Lingo.dev CLI

What is Advanced Installer AIL?

Advanced Installer is a Windows installer authoring tool that helps developers create MSI (Microsoft Installer) packages. AIL (Advanced Installer Localization) is an XML-based multilanguage dictionary format used to localize installer dialogs, buttons, messages, and properties. All translations for multiple languages are stored in a single AIL file.

What is Lingo.dev CLI?

Lingo.dev CLI is a free, open-source CLI for translating apps and content with AI. It's designed to replace traditional translation management software while integrating with existing pipelines.

To learn more, see Overview.

About this guide

This guide explains how to translate Advanced Installer AIL files with Lingo.dev CLI.

You'll learn how to:

  • Create a project from scratch
  • Configure a translation pipeline
  • Generate translations with AI

Prerequisites

To use Lingo.dev CLI, ensure that Node.js v18+ is installed:

❯ node -v
v22.17.0

Step 1. Set up a project

In your project's directory, create an i18n.json file:

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

This file defines the behavior of the translation pipeline, including what languages to translate between and where the localizable content exists on the file system.

To learn more about the available properties, see i18n.json.

Step 2. Configure the source locale

The source locale is the original language and region that your content was written in. To configure the source locale, set the locale.source property in the i18n.json file:

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

The source locale must be provided as a BCP 47 language tag.

For the complete list of the locale codes that Lingo.dev CLI supports, see Supported locale codes.

Step 3. Configure the target locales

The target locales are the languages and regions you want to translate your content into. To configure the target locales, set the locale.targets property in the i18n.json file:

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

Step 4. Create the source content

If you haven't already, create an AIL file that contains the content to be translated. AIL files use an XML structure where all language translations are stored in a single file.

File structure:

<?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>

Translatable content:

  • Each ENTRY element represents a translatable string with a unique id attribute
  • STRING elements within each ENTRY contain translations for specific languages
  • The lang attribute specifies the language code
  • The value attribute contains the translatable text

Entry ID conventions:

AIL files use structured IDs to organize installer content:

  • Control text: Control.Text.DialogName#ElementName
  • Control buttons: Control.Button.ButtonName
  • Properties: Property.PropertyName

For example:

  • Control.Text.WelcomeDlg#Title - Title text for the Welcome dialog
  • Control.Button.Next - Text for the Next button
  • Property.ProductName - Product name property

Advanced Installer variables:

AIL files support Advanced Installer variables that get replaced at runtime:

  • [ProductName] - Replaced with the product name
  • [ProductVersion] - Replaced with the product version
  • [Manufacturer] - Replaced with the manufacturer name

These variables are preserved during translation:

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

Output mode:

The AIL bucket mutates the original file rather than creating separate files for each locale. When you run translations, the CLI adds or updates STRING elements for target locales within the existing AIL file. This is because AIL files are designed to store all language translations in a single file.

Step 5. Create a bucket

  1. In the i18n.json file, add an "ail" object to the buckets object:

    {
      "$schema": "https://lingo.dev/schema/i18n.json",
      "version": "1.10",
      "locale": {
        "source": "en",
        "targets": ["es"]
      },
      "buckets": {
        "ail": {}
      }
    }
    
  2. In the "ail" object, define an array of one or more include patterns:

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

    These patterns define which files to translate.

    The patterns themselves:

    • can point to file paths (e.g., "./installer.ail")
    • can use asterisks as wildcard placeholders (e.g., "./*.ail")
    • do not use the [locale] placeholder (since all locales are in the same file)

    Recursive glob patterns (e.g., **/*.ail) are not supported.

Step 6. Configure an LLM

Lingo.dev CLI uses large language models (LLMs) to translate content with AI. To use one of these models, you need an API key from a supported provider.

To get up and running as quickly as possible, we recommend using Lingo.dev Engine:

  1. Sign up for a Lingo.dev account.

  2. Run the following command:

    npx lingo.dev@latest login
    

    This will open your default browser and ask you to authenticate.

  3. Follow the prompts.

Step 7. Generate the translations

In the directory that contains the i18n.json file, run the following command:

npx lingo.dev@latest run

This command:

  1. Reads the i18n.json file.
  2. Finds the files that need to be translated.
  3. Extracts the translatable content from the files.
  4. Uses the configured LLM to translate the extracted content.
  5. Writes the translated content back to the file system.

The first time translations are generated, an i18n.lock file is created. This file keeps track of what content has been translated, preventing unnecessary retranslations on subsequent runs.

Example

Before translation (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>

After translation (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