commit 97f78f7728fa48285ee04ad439e32abd814a48fb Author: Alexander Zhirov Date: Thu Jun 26 22:12:31 2025 +0300 init diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ea3a94a --- /dev/null +++ b/.gitignore @@ -0,0 +1,16 @@ +.dub +docs.json +__dummy.html +docs/ +/gettext-syslocale +gettext-syslocale.so +gettext-syslocale.dylib +gettext-syslocale.dll +gettext-syslocale.a +gettext-syslocale.lib +gettext-syslocale-test-* +*.exe +*.pdb +*.o +*.obj +*.lst diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..f3cb66f --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,16 @@ +{ + // Используйте IntelliSense, чтобы узнать о возможных атрибутах. + // Наведите указатель мыши, чтобы просмотреть описания существующих атрибутов. + // Для получения дополнительной информации посетите: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "type": "code-d", + "request": "launch", + "dubBuild": true, + "name": "Build & Debug DUB project", + "cwd": "${command:dubWorkingDirectory}", + "program": "bin/${command:dubTarget}" + } + ] +} diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..d1c022f --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "editor.insertSpaces": false, + "editor.tabSize": 4, + "editor.detectIndentation": false +} \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..36b7cd9 --- /dev/null +++ b/LICENSE @@ -0,0 +1,23 @@ +Boost Software License - Version 1.0 - August 17th, 2003 + +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..3998e16 --- /dev/null +++ b/README.md @@ -0,0 +1,44 @@ +# gettext_syslocale + +A D module that extends the `gettext` library to support system locale detection and standard GNU/Linux translation paths. + +## Overview + +The `gettext_syslocale` module enhances the `gettext` library by automatically selecting the system locale from environment variables (`LC_ALL`, `LC_MESSAGES`, `LANG`) and loading translation `.mo` files from standard GNU/Linux paths (`/usr/share/locale//LC_MESSAGES/.mo`). It prioritizes full language codes (e.g., `ru_RU`) before falling back to short codes (e.g., `ru`). + +## Features + +- Automatically detects the system locale. +- Searches for `.mo` files in `/usr/share/locale//LC_MESSAGES/.mo`. +- Checks full language codes (e.g., `ru_RU`) before short codes (e.g., `ru`). + +## Usage + +```d +import gettext; +import gettext_syslocale; + +void main(string[] args) { + mixin(gettext.main); + initializeSystemLocale(args[0].baseName); + writeln(tr!"Hello, world!"); +} +``` + +1. Include `mixin(gettext.main)` in your `main` function. +2. Call `initializeSystemLocale` with the program name (e.g., `args[0].baseName`). +3. Use `tr` for translatable strings, as provided by the `gettext` library. + +## Requirements + +- D compiler (e.g., DMD, LDC). +- The `gettext` library for D, including the `mofile` module. +- `.mo` translation files in `/usr/share/locale//LC_MESSAGES/`. + +## Installation + +Add `gettext_syslocale.d` to your project and ensure the `gettext` library is available. Compile with a D compiler supporting the `gettext` library. + +## License + +Boost License 1.0, consistent with the `gettext` library. diff --git a/dub.json b/dub.json new file mode 100644 index 0000000..b093b95 --- /dev/null +++ b/dub.json @@ -0,0 +1,13 @@ +{ + "authors": [ + "Alexander Zhirov" + ], + "copyright": "Copyright © 2025, Alexander Zhirov", + "dependencies": { + "gettext": "~>1" + }, + "description": "Support system locale detection and standard GNU/Linux translation paths for gettext", + "license": "BSL-1.0", + "name": "gettext-syslocale", + "targetType": "library" +} diff --git a/dub.selections.json b/dub.selections.json new file mode 100644 index 0000000..fee0d30 --- /dev/null +++ b/dub.selections.json @@ -0,0 +1,7 @@ +{ + "fileVersion": 1, + "versions": { + "gettext": "1.0.8", + "mofile": "0.2.1" + } +} diff --git a/source/gettext_syslocale.d b/source/gettext_syslocale.d new file mode 100644 index 0000000..366a799 --- /dev/null +++ b/source/gettext_syslocale.d @@ -0,0 +1,94 @@ +module gettext_syslocale; + +import gettext; +import std.file : exists, isFile; +import std.path : buildPath, baseName; +import std.process : environment; +import std.string : split, empty; + +/** + * Extends the gettext library with support for system locale and standard GNU/Linux paths. + * + * This module automatically selects the language from system environment variables + * (LC_ALL, LC_MESSAGES, LANG) and searches for .mo files in the standard path + * /usr/share/locale//LC_MESSAGES/.mo. + * It first checks the full language code (e.g., "ru_RU"), then the short code (e.g., "ru"). + * + * Params: + * programName = The name of the program (required parameter). + */ +bool initializeSystemLocale(string programName) @safe +{ + if (programName.empty) + { + throw new Exception("Program name must not be empty"); + } + + // Get the language from the system locale + string fullLang = getSystemLanguage(); + if (fullLang.empty) + { + selectLanguage(""); // Empty MoFile if no locale is defined + return false; + } + + // Check full and short language codes + string shortLang = fullLang.split("_")[0]; + foreach (lang; [fullLang, shortLang]) + { + if (tryLoadMoFile(programName, lang)) + { + return true; // Successfully loaded .mo file + } + } + + // If no file is found, use an empty MoFile + selectLanguage(""); + return false; +} + +/** + * Attempts to load an .mo file for the specified program name and language code. + * + * Params: + * programName = The name of the program. + * lang = The language code (e.g., "ru_RU" or "ru"). + * + * Returns: + * true if the .mo file is found and loaded, false otherwise. + */ +private bool tryLoadMoFile(string programName, string lang) @safe +{ + string moPath = buildPath("/usr/share/locale", lang, "LC_MESSAGES", programName ~ ".mo"); + if (moPath.exists && moPath.isFile) + { + selectLanguage(moPath); + return true; + } + return false; +} + +/** + * Retrieves the language from the system locale. + * + * Checks environment variables LC_ALL, LC_MESSAGES, LANG in that order. + * Returns the full language code (e.g., "ru_RU" from "ru_RU.UTF-8"). + * If the locale contains only a short code (e.g., "ru"), returns it as is. + * + * Returns: + * The full language code (e.g., "ru_RU", "zh_CN") or an empty string if no locale is defined. + */ +private string getSystemLanguage() @safe +{ + foreach (var; ["LC_ALL", "LC_MESSAGES", "LANG"]) + { + string value = environment.get(var); + if (!value.empty) + { + // Split on dot to ignore encoding (e.g., .UTF-8) + auto parts = value.split("."); + return parts[0]; // Return the full language code (e.g., ru_RU or ru) + } + } + return ""; +}