185 lines
7.0 KiB
Markdown
185 lines
7.0 KiB
Markdown
# 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
|
||
```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`):
|
||
|
||
```d
|
||
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 `.mo` translation files.
|
||
|
||
### Translating Messages
|
||
|
||
Use the `_()` function to translate messages:
|
||
|
||
```d
|
||
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 the `bindtextdomain` function to customize localization paths.
|
||
- **Usage**:
|
||
```bash
|
||
./preload/build.sh <program_name>
|
||
```
|
||
Replace `<program_name>` with the name of your program (e.g., `myapp`).
|
||
- **How It Works**:
|
||
Compiles `override_bindtextdomain.c` into a shared library, `.preload/liboverride_bindtextdomain.so`, defining `PNAME` as a macro.
|
||
- **Output**: Generates `.preload/liboverride_bindtextdomain.so`, which can be preloaded with `LD_PRELOAD` to override `bindtextdomain` behavior.
|
||
|
||
##### `override_bindtextdomain.c`
|
||
|
||
- **Purpose**: A C source file that intercepts calls to `bindtextdomain` and redirects the localization path to `build/usr/share/locale` for a specified program name (`PNAME`).
|
||
- **How It Works**: Checks if the `domainname` matches the predefined `PNAME` (set during compilation). If matched, redirects the localization path to `build/usr/share/locale`.
|
||
- **Requirements**: The `PNAME` macro must be defined during compilation (via `build.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 `.po` translation files based on D source code in the `source/` directory.
|
||
- **Usage**:
|
||
```bash
|
||
./scripts/generate_translations.sh [language]
|
||
```
|
||
Replace `[language]` with an optional language code (e.g., `ru` or `en`). If omitted, processes `ru` and `en` by default. For help:
|
||
```bash
|
||
./scripts/generate_translations.sh --help
|
||
```
|
||
- **How It Works**:
|
||
1. Checks for `.d` files in `source/`.
|
||
2. Generates or updates `translations/messages.pot` using `xgettext` to extract translatable strings (marked with `_`).
|
||
3. For each language:
|
||
- Creates a new `.po` file with `msginit` if it doesn’t exist.
|
||
- Updates existing `.po` files with `msgmerge`, preserving prior translations.
|
||
4. Deletes the temporary `.pot` file upon completion.
|
||
- **Example**:
|
||
```bash
|
||
./scripts/generate_translations.sh ru
|
||
```
|
||
Creates or updates `translations/ru.po`.
|
||
- **Requirements**: GNU Gettext tools (`xgettext`, `msgmerge`, `msginit`).
|
||
- **Output**: Fresh or updated `.po` files in `translations`, ready for translation and compilation into `.mo` files.
|
||
|
||
##### `compile_mo.sh`
|
||
|
||
- **Purpose**: Compiles `.po` files from the `translations` directory into `.mo` files and generates a `run.sh` script for launching the program with a chosen language.
|
||
- **Usage**:
|
||
```bash
|
||
./scripts/compile_mo.sh <program_path>
|
||
```
|
||
Replace <program_path> with the path to your program (e.g., `./build/usr/bin/myapp`).
|
||
- **How It Works**:
|
||
1. Compiles each `.po` file into an `.mo` file, placing them in `build/usr/share/locale/<lang>/LC_MESSAGES/<program_name>.mo`.
|
||
2. Creates an executable `run.sh` script that:
|
||
- Accepts a language code (e.g., `ru` or `en`) as an argument.
|
||
- Validates the language against available `.po` files.
|
||
- Sets `LANG` and `LD_PRELOAD` environment variables to run the program with the selected localization.
|
||
- **Example Launch**:
|
||
```bash
|
||
./run.sh ru
|
||
```
|
||
Runs the program with Russian localization, preloading `.preload/liboverride_bindtextdomain.so`.
|
||
- **Output**: Compiled `.mo` files and a `run.sh` script 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`:
|
||
|
||
```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:
|
||
1. **Build the Project**: Run `dub build` in your project’s root directory.
|
||
2. **Post-Build Steps**:
|
||
- `bash scripts/compile_mo.sh ./build/usr/bin/myapp`:
|
||
- Compiles `.po` files into `.mo` files, storing them in `build/usr/share/locale/<lang>/LC_MESSAGES/myapp.mo`.
|
||
- Generates a `run.sh` script for launching `myapp` with a specified language.
|
||
- `bash preload/build.sh myapp`:
|
||
- Compiles `.preload/liboverride_bindtextdomain.so` with `PNAME` set to `myapp`.
|
||
3. **Run the Program**:
|
||
```bash
|
||
./run.sh ru
|
||
```
|
||
Launches `myapp` with Russian localization, leveraging the preloaded library.
|