Gettext.jl
This package offers facilities for internationalization and localization (i18n and l10n) of software in the Julia programming language, using the standard gettext
system.
(This package calls GNU gettext's libintl
library directly from Julia, via the GettextRuntime_jll
package compiled for Julia by Yggdrasil; this is automatically installed for you by Julia's package manager. GNU gettext is free/open-source software licensed under the GNU LGPL.)
Overview of internationalization and localization
Internationalization (commonly abbreviated i18n) is the process of making computer software able to support translations into multiple languages. Localization (abbreviated l10n) is the creation of a specific translation for a particular language and cultural setting (a locale).
gettext
is a popular system, dating back to 1990, for i18n and l10n of messages (strings) exposed to users in a program's interface: prompts, menu items, error messages, and so on. This consists of two parts:
i18n: in your program, any string that might need translation should be wrapped in a call to a
gettext
function. In Gettext.jl, this is usually accomplished by macros: For a typical string"..."
, you simply replace it with_"..."
to make it translatable. There are also more specialized macros, such as@ngettext
for strings with runtime-dependent singular and plural forms. See the Internationalization (i18n) API chapter.l10n: for any locale, one can create a
.po
file that lists the translations of strings in a human-readable text format — this format is designed so that non-programmers can easily contribute translations, and there are many software tools to help create.po
files (either manually or via automated translation). These.po
files are then placed in a standardized directory for your package, and are converted to a binary.mo
format with the GNUmsgfmt
program. At runtime, Gettext.jl then automatically looks up translations (if any) from the current locale (as indicated by the operating system) and substitutes them for strings like_"..."
in your program. See the Localization (l10n) and PO files chapter.
(Other forms of i18n and l10n, such as locale-specific formatting of numbers and dates, are outside the scope of gettext
, but are provided by other libraries such as libc
.)
See also the introduction and overview from the GNU gettext
manual.
Simple example
Suppose that you have the following Julia program
println("Hello, world!")
To i18n it, the first step is simply to change the code to:
using Gettext
println(_"Hello, world!")
which tells Gettext.jl to translate the string "Hello, world!"
for the current locale, if possible. By default, if no translation is found, _"..."
will simply return the original untranslated string, and the program will have the same output as before.
The Gettext.jl package comes with a sample .po
translation file that includes a translation of "Hello, world!"
into French. In particular, the Gettext.jl package has a text file po/fr/LC_MESSAGES/sample.po
(along with its binary-format equivalent po/fr/LC_MESSAGES/sample.mo
) that includes the translation:
msgid "Hello, world!"
msgstr "Bonjour le monde !"
Here, in the sample.po
file, the msgid
is the original string and msgstr
is the translation. The po
directory (typically at the top level of the package) is where a package's translations are placed, and po/fr/LC_MESSAGES
contains translations for French-language (fr
) locales in the default "category" LC_MESSAGES
. Inside this directory, sample.po
contains the translations for the "domain" we called "sample"
— there will typically be one such domain per independent package/component of a program (see Gettext for modules and packages). We need to tell Gettext.jl where to find the translations we are using, which we could do here via:
using Gettext
bindtextdomain("sample", joinpath(dirname(pathof(Gettext)), "..", "po"))
textdomain("sample") # set domain for the global Main module only
println(_"Hello, world!")
Here, bindtextdomain
specifies the path of the po
directory for a given domain. For scripts (or interactive sessions) running in Julia's Main
module, you then call textdomain
to set the global domain. Inside packages and other modules, you instead define a __GETTEXT_DOMAIN__
global to set a package-specific domain, so that each package can have independent translations.
Now, when you run the code, you will still see "Hello, world!"
if you are in any non-French locale, but French locales will instead print "Bonjour le monde !"
. On Unix-like systems, you can set the locale simply via the LANGUAGE
environment variable. This can even be changed at runtime, so
using Gettext
bindtextdomain("sample", joinpath(dirname(pathof(Gettext)), "..", "po"))
textdomain("sample")
println(_"Hello, world!")
ENV["LANGUAGE"]="fr"
println(_"Hello, world!")
will print
Hello, world!
Bonjour le monde !
if you are in a non-French locale to start with.
(Note: Microsoft Windows has its own API to set the locale, not via environment variables, so you may not see French output unless you change the Windows display language.)