README.md

# Kielet - GNU Gettext for Gleam

[![Package Version](https://img.shields.io/hexpm/v/kielet)](https://hex.pm/packages/kielet)
[![Hex Docs](https://img.shields.io/badge/hex-docs-ffaff3)](https://hexdocs.pm/kielet/)

Kielet is a [GNU Gettext](https://www.gnu.org/software/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:

```sh
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):

```gleam
import gleam/io
import kielet.{gettext as g_, ngettext as n_}
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)
  )
}
```

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_` and `n_`:

```sh
xgettext src/**/*.gleam --keyword=g_:2 --keyword=n_:2,3 -o - --copyright-holder='Your Name' --package-name='Your App' --package-version='X.Y.Z' --msgid-bugs-address='email@example.com'
```

Store this output into a template file with the `.pot` extension and then use a translation app such as
[Poedit](https://poedit.net) 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.

### 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

```sh
gleam test  # Run the tests
```