7.0 KiB
Singlang - Lightweight Internationalization (i18n) Library for D
Description
singlang integrates GNU Gettext for translations. The module features a singleton Singlang class for configuration and a convenient _() function for translating messages.
Installation
To use singlang in your D project, add it as a dependency in your dub.json or dub.sdl file:
dub.json
{
"dependencies": {
"singlang": "~>0.1.0"
}
}
Usage
Initializing the Translation System
Before translating messages, you must initialize the Singlang class with a domain name and a directory containing translation files (.mo):
import singlang;
void main() {
if (Singlang.set("myapp", "/usr/local/share/locale")) {
writeln("Translation system ready!");
} else {
writeln("Setup failed, check stderr for details!");
}
}
domain: The name of your application or translation domain.localeDir: The path to the directory containing your.motranslation files.
Translating Messages
Use the _() function to translate messages:
writeln(_("Hello, world!")); // Outputs the translated version of "Hello, world!" if available
writeln(_("Error: File not found")); // Outputs translated text or original if unavailable
If the system is not initialized or a translation is unavailable, the original message is returned.
Localization and Build Mechanisms
This project includes mechanisms to customize localization environments and automate translation workflows, located in the preload and scripts directories. Below is a detailed overview of their structure, purpose, and how to leverage them effectively in your project.
preload Directory
The preload directory provides tools to intercept and customize the bindtextdomain function from the GNU Gettext library, allowing you to redirect the path to localization files.
Structure
preload
├── build.sh
└── override_bindtextdomain.c
Files
build.sh
- Purpose: Compiles a shared library,
liboverride_bindtextdomain.so, which intercepts thebindtextdomainfunction to customize localization paths. - Usage:
Replace./preload/build.sh <program_name><program_name>with the name of your program (e.g.,myapp). - How It Works:
Compiles
override_bindtextdomain.cinto a shared library,.preload/liboverride_bindtextdomain.so, definingPNAMEas a macro. - Output: Generates
.preload/liboverride_bindtextdomain.so, which can be preloaded withLD_PRELOADto overridebindtextdomainbehavior.
override_bindtextdomain.c
- Purpose: A C source file that intercepts calls to
bindtextdomainand redirects the localization path tobuild/usr/share/localefor a specified program name (PNAME). - How It Works: Checks if the
domainnamematches the predefinedPNAME(set during compilation). If matched, redirects the localization path tobuild/usr/share/locale. - Requirements: The
PNAMEmacro must be defined during compilation (viabuild.sh); if undefined, it exits with an error. - Use Case: Ideal for projects needing to override default localization paths without modifying the core application code.
scripts Directory
The scripts directory contains utilities to streamline translation file management, including compiling .mo files and generating/updating .po files.
Structure
scripts
├── compile_mo.sh
└── generate_translations.sh
Files
generate_translations.sh
- Purpose: Automates the creation and updating of
.potranslation files based on D source code in thesource/directory. - Usage:
Replace./scripts/generate_translations.sh [language][language]with an optional language code (e.g.,ruoren). If omitted, processesruandenby default. For help:./scripts/generate_translations.sh --help - How It Works:
- Checks for
.dfiles insource/. - Generates or updates
translations/messages.potusingxgettextto extract translatable strings (marked with_). - For each language:
- Creates a new
.pofile withmsginitif it doesn’t exist. - Updates existing
.pofiles withmsgmerge, preserving prior translations.
- Creates a new
- Deletes the temporary
.potfile upon completion.
- Checks for
- Example:
Creates or updates./scripts/generate_translations.sh rutranslations/ru.po. - Requirements: GNU Gettext tools (
xgettext,msgmerge,msginit). - Output: Fresh or updated
.pofiles intranslations, ready for translation and compilation into.mofiles.
compile_mo.sh
- Purpose: Compiles
.pofiles from thetranslationsdirectory into.mofiles and generates arun.shscript for launching the program with a chosen language. - Usage:
Replace <program_path> with the path to your program (e.g.,./scripts/compile_mo.sh <program_path>./build/usr/bin/myapp). - How It Works:
- Compiles each
.pofile into an.mofile, placing them inbuild/usr/share/locale/<lang>/LC_MESSAGES/<program_name>.mo. - Creates an executable
run.shscript that:- Accepts a language code (e.g.,
ruoren) as an argument. - Validates the language against available
.pofiles. - Sets
LANGandLD_PRELOADenvironment variables to run the program with the selected localization.
- Accepts a language code (e.g.,
- Compiles each
- Example Launch:
Runs the program with Russian localization, preloading./run.sh ru.preload/liboverride_bindtextdomain.so. - Output: Compiled
.mofiles and arun.shscript for easy, localized program execution.
Applying These Mechanisms in Your Project
The preload mechanism allows overriding localization paths without altering the program’s source code.
Integration Example with dub.json
For seamless automation, integrate these mechanisms into your build process using the "postBuildCommands" field in dub.json, the configuration file for the DUB build tool.
Add the following to your dub.json:
{
"postBuildCommands": [
"bash scripts/compile_mo.sh <program_path>",
"bash preload/build.sh <program_name>"
]
}
Replace <program_path> with the path to your program (e.g., ./build/usr/bin/myapp).
Replace <program_name> with your program’s name (e.g., myapp).
How It Works:
- Build the Project: Run
dub buildin your project’s root directory. - Post-Build Steps:
bash scripts/compile_mo.sh ./build/usr/bin/myapp:- Compiles
.pofiles into.mofiles, storing them inbuild/usr/share/locale/<lang>/LC_MESSAGES/myapp.mo. - Generates a
run.shscript for launchingmyappwith a specified language.
- Compiles
bash preload/build.sh myapp:- Compiles
.preload/liboverride_bindtextdomain.sowithPNAMEset tomyapp.
- Compiles
- Run the Program:
Launches./run.sh rumyappwith Russian localization, leveraging the preloaded library.