stut-it Martin Stut - Information Technology Tailored to You
By Martin Stut, 2016-06-10
If you want to jump directly to the technical stuff, how to internationalize your AutoIt application and to download the code, go to https://github.com/martinstut/gettext_au3.
The blog post here is more about the background and reasoning why I did things the way I did them.
While developing an AutoIT-based application for an international christian organization, the need came up to provide this application for users of different native languages. So MsgBox(64, "App Title", "Please reboot your computer to complete the process.")
is no longer good enough. The application needs to present its user interface in a different language, depending on the user's preference.
Of course there are many approaches to implement this. But however you do it, you will need two different toolkits: one for the translator and one for the programmer.
The programmer will need something to define the translatable strings or, preferably, extract them from the source code.
The translator will need something to edit the translation.
The programmer will need something to incorporate the translation in to the program.
And all of this should be repeatable with little effort when a few strings in the program change - don't make the translator retranslate everything if you just add two strings for a new little feature of your program.
To avoid reinventing the wheel, I decided to go the route many large open source projects go: gettext.
For a general overview of the GNU gettext system you can read https://en.wikipedia.org/wiki/Gettext . You can find detailed information about gettext in https://www.gnu.org/software/gettext/manual/index.html .
In a nutshell, gettext works like this:
MsgBox(64, "App Title", gettext("Please reboot your computer to complete the process."))
. In a number of cases it's not that easy, e.g. if you are intermixing variables, but there are solutions, mostly built around sprintf
and friends.gettext()
evaluate at run time, when the language is known, not at compile time.xgettext
on your source code files to extract the translatable strings into a messages.pot
(portable object template) file. Repeat this whenever a translatable string changes or is added. After the first run of xgettext
, generate [language].po
(portable object) from messages.pot
. In the C world, run the msginit
program.messages.pot
is modified, merge it into the existing [language].po
files by the msgmerge
program.[language].po
file. After the translator has completed her work, [language].po
contains pairs of lines like (this example would be in de.po for German):
msgid "Please reboot your computer to complete the process." msgstr "Bitte starten Sie Ihren Computer neu um den Vorgang abzuschließen."
The translators can use a variety of tools, ranging from simple text editors like Notepad++ to specialized CAT programs like OmegaT. My personal favourite is PoEdit, as it can remember previous translations like OmegaT, but is even easier to handle than a text editor.
[language].po
files. In the C world, use the msgfmt
program to create binary [language].mo
(machine object) files.Gettext originated in a C-centric, fully compiling world, assuming a setup.exe program to install the product. But one of AutoIt's strengths is the ability to create a standalone executable, capable to run without installing (portable program). So it's better to include some compilable file rather than adding a .mo file per language to the distribution.
Here is how I set up the above gettext infrastructure for AutoIt:
gettext("english version of translatable string")
. When concatenation, variables, quotes and other things beyond simple strings are involved, things aren't that easy, but the StringFormat()
function, which is the AutoIt equivalent of sprintf()
, helps a lot. Read the "Prepare Source Code" section of https://github.com/martinstut/gettext_au3 for detailed options how to deal with or work around such situations.gettext_au3_runtime_library.au3
- just #include
it.gettext_au3_language_select_ui()
in the runtime library. You need to store the code (2 characters) of the chosen language in a global variable with a special name, like this:Global $gettext_au3_lang = gettext_au3_language_select_ui($apptitle, gettext_au3_language_list(), "en")
This presents a radio buttoned choice of languages (returned by automatically generated function gettext_au3_language_list()
) to the user, with the OS language being the default position of the button. If the OS language has no translation available, the default language in the third parameter is offered as a default. If even that is not available (which shouldn't happen, because you have planned for a default language), the last one in the list of languages is used.C:\Program Files
with the option of adding that subdirectory to your %PATH%
environment variable. Do use that option.xgettext
program as for C is used, which works remarkably well, because AutoIt is sufficiently similar to C in how function calls look like.[language].po
, you can just copy messages.pot
. No special msginit program needed.messages.pot
into [language].po
, the standard msgmerge
program works. For the detailed command line, see the "Merge Updated Messages and Existing Translations" section of[language].po
files are then processed by the core program of this tool set, gettext_au3_msgfmt.au3
, to generate a single #include
able source code file gettext_au3_gettext.au3
, containing the combined translations of all languages of the collection of ??.po
files. [language]
must be exactly two characters, such as in ko.po
for Korean.