Kielet - GNU Gettext for Gleam
Kielet is a GNU Gettext implementation for Gleam. With Kielet,
you can translate your Gleam or BEAM application without needing to change its source code or recompile
it. Kielet implements translation functions for singular and plural forms and an MO file parser to read
compiled translations. Gleam source code can be processed with the xgettext
program to automatically
generate the translation templates (POT files).
Usage
First add Kielet to your project:
gleam add kielet
Then you can start annotating your source code to prepare it for translation (skip the file reading and language loading when you don’t have languages yet):
import gleam/io
import kielet.{gettext as g_, ngettext as n_, pgettext as p_}
import kielet/context.{Context}
import kielet/database
import kielet/language
import simplifile
pub fn main() {
// This example uses simplifile to read the MO data
let assert Ok(mo_data) = simplifile.read_bits("./path/to/fi.mo")
// Load language from MO file
let assert Ok(finnish) = language.load("fi", mo_data)
// Create language database
let db = database.new() |> database.add_language(finnish)
// Create translation context to choose active language
let ctx = Context(db, "fi")
// "Morjens, maailma!"
io.println(
g_(ctx, "Hello, world!")
)
// "Ou jee, mulla on %s euroa" -- The correct plural form is chosen based on the amount provided
io.println(
n_(ctx, "Nice, I have %s euro", "Nice, I have %s euros", 15)
)
// "Lainhuuto" -- The context is used to choose between words that are written the same but have different meanings,
// and to give the translator additional hints.
io.println(
p_(ctx, "A legal contract showing bond.", "A deed")
)
// "Teko"
io.println(
p_(ctx, "Something that is carried out; an act or action.", "A deed")
)
}
When you have annotated your code, but have no translations, the original messages will be returned. Thus it’s safe to add new strings to your program, the worst that can happen is that the original strings will be shown.
To start translating your program, first extract the strings from your source code. You should read
the documentation of the xgettext
program to do this, but here is an example command that works for
Gleam source code, when you have imported the functions as g_
(gettext
), n_
(ngettext
), p_
(pgettext
), and
np_
(npgettext
):
xgettext src/**/*.gleam --keyword=g_:2 --keyword=n_:2,3 --keyword=p_:2c,3 --keyword=np_:2c,3,4 --from-code=UTF-8 -o - --copyright-holder='Your Name' --package-name='Your App' --package-version='X.Y.Z' --msgid-bugs-address='email@example.com'
Don’t forget the --from-code=UTF-8
if your file has any non-ASCII characters!
Store this output into a template file with the .pot
extension and then use a translation app such as
Poedit to create language specific translation files. The output should be human
readable PO files that you can add to your version tracking if wanted, and binary MO files that Kielet
can read.
Context
The pgettext
and npgettext
functions accept additional context. It is used to disambiguate between several
identical instances of an untranslated string. For example, if you have the word “paint” both meaning literal paint, and
the act of painting, you will need to add context to tell these usages apart.
Another use for the context is to give the translator helpful hints. A translator may not be as knowledgeable about the application as the developer, so giving some context may be helpful.
String replacement
Note that Kielet does not do any string replacement. It’s convention to use %s
to denote the number
of items in a translatable string, but it’s not enforced and has no special meaning. This means that
the translated message will contain the %s
unchanged, and it is up to you to replace it with the
appropriate number, taking into account the target locale’s number format.
Plural-Forms header
Kielet requires a compiled translation file to contain a Plural-Forms
header to use plurals. There is
no builtin database of plural form algorithms, so if such a header does not exist, all attempts at
translating plurals will fail. Such a file can be used to translate singular messages, however.
Gettext limitations
Due to how Gettext is built, the source language (the language used in your source files) can only be a language with two plural forms. This means that there is a singular form, used when there is one item, and a plural form that is used for every other amount of items. Unfortunately Gettext does not support languages with more plural forms such as Arabic as the source language. They are supported as translation targets, though.
If you do not have any usage of ngettext
in your code, your source language can be any language. This
may be a risky choice, though, since it’s quite likely you will need plural forms in the future.
Development
gleam test # Run the tests