Localization (i18n)
Relevant source files
The following files were used as context for generating this wiki page:The Ghostbird add-on supports internationalization (i18n) to provide a localized user interface. The system is based on the standard WebExtension i18n API, which uses messages.json files for different locales. The project centralizes all translations into a single locales.toml file, which is then processed during the build to generate the required locale-specific files.
This approach simplifies translation management by keeping all strings in one place. A dedicated build script and a suite of tests ensure the integrity and consistency of the localization data across the application. The project encourages community contributions for translations.
Sources: README.md, doc/building.md
Architecture
The localization process is integrated into the project's build system. It starts with a single TOML file containing all translations, which is then transformed into the directory structure and file format expected by Thunderbird's WebExtension framework.
The following diagram illustrates the data flow from the source translation file to its usage within the add-on.
This diagram shows the build-time process of converting locales.toml into standard messages.json files, which are then used by Thunderbird at runtime.
Sources: tools/generate_locale_messages.ts, doc/building.md, manifest_template.json
Locale String Management
The locales.toml File
All user-facing strings are defined in locales.toml. This file serves as the single source of truth for all translations. It is structured with top-level keys representing the MessageId, and nested keys for each LocaleId (e.g., "en", "ja").
A MessageId is a unique identifier for a string, typically following the format filename_english_message.
Example structure within locales.toml:
# This is an example structure based on the processing script.
[manifest_name]
en = "Ghostbird"
ja = "ゴーストバード"
[manifest_description]
en = "Compose your emails in your favorite text editor."
This centralized file is parsed by the build script to generate the necessary messages.json files.
Sources: tools/generate_locale_messages.ts:32-40, src/util/types.ts:2-15
Data Structures
The localization system uses several specific types to handle the data from locales.toml and messages.json. These types are defined in src/util/types.ts.
| Type Name | Description |
|---|---|
LocalesTomlContent | Represents the entire content of locales.toml. It's a record where each key is a MessageId and the value is another record mapping a LocaleId to the translated string or message object. |
MessagesJsonContent | Represents the content of a generated messages.json file for a single locale. It's a record mapping a MessageId to an object with a message key. |
LocaleId | A string representing a language or dialect, following the BCP 47 language tag format (e.g., "en", "en-US"). |
MessageId | A unique string ID for a message, often in the format ${filename}_${english_message} (e.g., options_enable_notifications). |
MessageLabel | A string representing the translated message text shown to the user. |
Sources: src/util/types.ts
Build Process
The conversion from locales.toml to the required _locales/*/messages.json format is handled by a custom Rolldown plugin during the build.
Sources: doc/building.md
generate_locale_messages.ts Plugin
This build script defines the generateLocaleMessages plugin, which is responsible for the i18n file generation.
The process is as follows:
- The plugin resolves the path to
locales.toml. - It reads and parses the TOML file into a
LocalesTomlContentobject using the@std/tomllibrary. - The
localeToMessagesfunction transforms this object into a map where keys areLocaleIds and values areMessagesJsonContentobjects. - Finally, it iterates through the map and emits a
messages.jsonfile for each locale into thedist/ext/_locales/directory.
The following diagram shows the logic inside the generateLocaleMessages plugin.
Usage in the Application
The generated messages.json files are used by Thunderbird in two primary ways: declaratively in the manifest and programmatically at runtime.
Manifest File
The manifest_template.json file uses __MSG_...__ placeholders to reference localized strings. Thunderbird automatically replaces these placeholders with the appropriate string from the user's current locale.
Example from manifest_template.json:
{
"name": "__MSG_manifest_name__",
"description": "__MSG_manifest_description__",
"commands": {
"start_ghostbird": {
"description": "__MSG_manifest_commands_start_ghostbird_description__"
}
}
}
The locales.test.ts file confirms this usage by scanning manifest_template.json for these placeholders.
Sources: manifest_template.json:3-5, 30-32, src/test/locales.test.ts:32-34, 42-44
Runtime Usage
While the specific implementation file src/thunderbird/messenger/i18n.ts is a placeholder, the testing suite implies how strings are used at runtime. The test locales.test.ts scans source files for message IDs, which suggests that a function like messenger.i18n.getMessage() is used to retrieve localized strings programmatically.
The test specifically looks for IDs matching the pattern "src_\\w+" within TypeScript files, indicating a convention for runtime message IDs.
Sources: src/test/locales.test.ts:24-30, 46-52
Testing
The integrity of the localization system is verified by the test file src/test/locales.test.ts. This test ensures that there is a one-to-one mapping between the message IDs defined in locales.toml and the IDs used throughout the codebase.
The test performs the following checks:
- Loads Defined IDs: It parses
locales.tomlto get a set of all definedMessageIds. - Loads Used IDs: It scans the following sources for message ID usage:
manifest_template.json(for__MSG_...__patterns).- CSS files (for
__MSG_...__patterns). - Source code (
.tsfiles insrc/rootandsrc/ghosttext-adaptor) for patterns like"src_...".
- Compares Sets: It compares the set of defined IDs with the sets of used IDs to find discrepancies. The test fails if:
- An ID is defined in
locales.tomlbut never used. - An ID is used in the code, manifest, or CSS but not defined in
locales.toml.
- An ID is defined in
This ensures that no translations are obsolete and no part of the UI will show a missing string.
Sources: src/test/locales.test.ts:8-17