This tool minimizes external dependencies when builing software that uses GNU gettext on Windows by replacing it with Windows native API. This is accomplished by
- collecting all translations from PO files
- producing a message catalog file to be used by Message Compiler
- replacing `_()` with `FuncName(MSG_ID)` within the source code
- linking in generated binary message table resources as well as an extra source file containing `FuncName` definition that uses FormatMessage.
- Just for Fun
- to see if it can be done as it is not the first time I have this idea
- It allows for a very portable executables without extra dependencies
- sometimes translations are the only extras to carry around
- gettext-enabled applications sometimes expect Machine Object (MO) files
with translations to be in a hardcoded location (LOCALEDIR)
- that is not quite portable to move around without proper “installation”
- You don’t feel particularly inclined to include a notice that your
binary uses gettext runtime under LGPL terms
- you can use gettext ecosystem for in-house development only but ship it without a trace
Don’t get me wrong GNU gettext is great! This is just a potentially alternative way to pack things.
This tool does not help with the process of development, internationalization, or localization. You do want to keep using GNU gettext for development and your favorite PO tools for translations. Instead, this tool helps to build the final executable using Windows API instead of GNU gettext by patching the source code. The resulting changes are meant to be discarded after compilation.
One of the goals is to have the least number of dependencies. So there would be no need to install or compile anything. However, the chances are that you already have Git (for Windows) installed. And that comes bundled with Perl.
This tool is intended for Windows port maintainers for C/C++ projects that would like to avoid using GNU gettext in favor of Windows native localization approch.
This tool converts the content of po files into Windows Message Compiler(mc.exe) format for use with MESSAGETABLE resource and FormatMessage instead of gettext. Usage: perl gt2mt.pl [option...] Options: --help print this message --podir=<dir> directory with PO files (default: po) --srcdir=<dir> source code directory (default: src.orig) --destdir=<dir> destination directory (default: src) --missing=<file> a CSV file where to keep missing translations (default: missing.csv) --msgfile=<file> directory with PO files [default: po] --func_name=<name> function identifier [default: GetString]
The code like this
*errstr = xasprintf(_("the server does not support TLS "
"via the STARTTLS command"));
gets replaced with
*errstr = xasprintf(GetString(MSG_THE_SERVER_DOES5));
while producing
MessageId=344
SymbolicName=MSG_THE_SERVER_DOES5
Language=Romanian
serverul nu acceptă TLS prin intermediul comenzii STARTTLS
.
Language=Esperanto
la servilo ne regas TLS-on per la komando STLS
.
Take a look at GitHub Actions workflow for an example.
This is a proof of concept. Certain things are still broken.
It is tested on (modified) msmtp and hunspell. You can see what went wrong in this gist.
The main (Perl) part of this project is licensed under the
GPLv3. However, the reference C code that uses FormatMessage()
is
licensed under the BSL-1.0. You may compile and link against that C
code without any attribution.
- windmc generates `#pragma code_page(1)` for some languages that windres does not like
- Resource compiler from Visual Studio does not like certain languages (e.g. Tamil) when building non-UNICODE (-U) but ANSI (-A althoug MBCS) applications.
- It won’t work if messages to be translated are stored in array with N_ as those can’t be initialized with a function call.
- It won’t work if there is some string concatenation going on using a macro, e.g. N_(“%s %s differ: byte %”PRIdMAX”, line %”PRIdMAX”\n”)