Kielet - GNU Gettext for Gleam

Package Version Hex Docs

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
Search Document