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
ENTRYelement represents a translatable string with a uniqueidattribute STRINGelements within eachENTRYcontain translations for specific languages- The
langattribute specifies the language code - The
valueattribute 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 dialogControl.Button.Next- Text for the Next buttonProperty.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
-
In the
i18n.jsonfile, add an"ail"object to thebucketsobject:{ "$schema": "https://lingo.dev/schema/i18n.json", "version": "1.10", "locale": { "source": "en", "targets": ["es"] }, "buckets": { "ail": {} } } -
In the
"ail"object, define an array of one or moreincludepatterns:{ "$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. - can point to file paths (e.g.,
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:
-
Run the following command:
npx lingo.dev@latest loginThis will open your default browser and ask you to authenticate.
-
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:
- Reads the
i18n.jsonfile. - Finds the files that need to be translated.
- Extracts the translatable content from the files.
- Uses the configured LLM to translate the extracted content.
- 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