singlang/source/singlang.d

148 lines
4.4 KiB
D

/++
Module singlang - Lightweight internationalization (i18n) support for D programs.
Description:
This module integrates GNU Gettext for translations in D applications, using a singleton
`Singlang` class and a convenient `_()` function for message translation. Errors are
reported to stderr for proper error handling.
+/
module singlang;
import core.stdc.locale : setlocale, LC_ALL;
import std.string : toStringz;
import std.conv : to;
import std.stdio : writeln, stderr;
extern(C) {
char* bindtextdomain(const char* domainname, const char* dirname);
char* textdomain(const char* domainname);
char* gettext(const char* msgid);
}
/++
Class Singlang - Singleton manager for translation configuration.
Description:
The `Singlang` class encapsulates the setup and management of the GNU Gettext-based
translation system. It ensures that the translation environment is initialized only once
and provides a centralized configuration point for the domain and translation directory.
Usage Example:
---
import singlang;
void main() {
if (Singlang.set("myapp", "/usr/share/locale")) {
writeln("Translation system ready!");
}
}
---
+/
class Singlang {
private:
/++ Translation domain name used by GNU Gettext +/
string domain;
/++ Directory path containing translation files (.mo) +/
string localeDir;
/++ Singleton instance of the Singlang class +/
static Singlang instance;
/++
Private constructor for initializing a Singlang instance.
Params:
domain = The translation domain name
localeDir = Path to the directory with translation files
Note:
Accessible only internally; use `set` to create an instance.
+/
this(string domain, string localeDir) {
this.domain = domain;
this.localeDir = localeDir;
}
public:
/++
Initializes the translation system with a domain and directory.
Description:
Configures the GNU Gettext environment by setting the translation directory and domain.
This method must be called before using the `_()` function for translations. Errors
are reported to stderr.
Params:
domain = Name of the translation domain (e.g., application name)
localeDir = Path to the directory with translation files (.mo)
Returns:
`true` on successful initialization, `false` if an error occurs
Notes:
- Attempting to initialize an already initialized instance will fail with an error message to stderr.
- Errors during directory or domain setup will reset the instance to null and log messages to stderr.
Example:
---
if (Singlang.set("myapp", "/path/to/translations")) {
writeln("Ready to translate!");
} else {
writeln("Setup failed, check stderr for details!");
}
---
+/
static bool set(string domain, string localeDir) {
if (instance !is null) {
stderr.writeln("Error: Singlang is already initialized");
return false;
}
setlocale(LC_ALL, "");
instance = new Singlang(domain, localeDir);
if (bindtextdomain(domain.toStringz, localeDir.toStringz) is null) {
stderr.writeln("Error: Failed to set translations directory");
instance = null;
return false;
}
if (textdomain(domain.toStringz) is null) {
stderr.writeln("Error: Failed to set translations domain");
instance = null;
return false;
}
return true;
}
}
/++
Retrieves the translated version of a given message.
Description:
Translates a message using the configured `Singlang` instance. If the system is not
initialized, it returns the original message and logs an error to stderr.
Params:
msg = The message to translate (UTF-8 encoded)
Returns:
The translated string, or the original message if translation fails or system is uninitialized
Example:
---
writeln(_("Error: File not found")); // Outputs translated text or original if unavailable
---
+/
string _(string msg) {
if (Singlang.instance is null) {
stderr.writeln("Error: Singlang module is not initialized");
return msg;
}
auto result = gettext(msg.toStringz);
return result !is null ? result.to!string : msg;
}