# Internationalization

## Features <a href="#features" id="features"></a>

* Automatic language detection (based on the browser language settings).
* Dynamic language change.
* Multi-language support for built-in advanced components:
  * rich date and time picker - 26 languages
  * rich text editor - 2 languages
* Minimal impact of internationalization process on the application source code.
* Automatic extraction of text for translation from the application code.
* Support for well known translation files format (gettext `*.po` files).

## Requirements

Apply `kotlinx-gettext` Gradle plugin and add `kilua-i18n` module to your dependencies.

{% code title="libs.versions.toml" %}
```toml
[versions]
gettext = "0.7.0"

[libraries]
kilua-i18n = { module = "dev.kilua:kilua-i18n", version.ref = "kilua" }

[plugins]
gettext = { id = "name.kropp.kotlinx-gettext", version.ref = "gettext" }
```
{% endcode %}

{% code title="build.gradle.kts" %}
```kotlin
plugins {
    alias(libs.plugins.gettext)
}

kotlin {
    sourceSets {
        val commonMain by getting {
            dependencies {
                implementation(libs.kilua.i18n)
            }
        }
    }
}

gettext {
    potFile.set(File(projectDir, "src/commonMain/resources/modules/i18n/messages.pot"))
    keywords.set(listOf("tr","trn:1,2","trc:2","trnc:2,3","marktr"))
}
```
{% endcode %}

## Using multi-language text in the application sources <a href="#using-multi-language-text-in-application-sources" id="using-multi-language-text-in-application-sources"></a>

To mark some text for translation use one of the methods of the `dev.kilua.i18n.I18n` class instead of plain string literals. You can start your work with an empty instance of the class.

```kotlin
import dev.kilua.i18n.I18n

val i18n = I18n()
```

There are a few different methods in the `I18n` class, which can be used for singular and plural forms in different contexts.

<table><thead><tr><th width="187">Method</th><th>Description</th></tr></thead><tbody><tr><td><code>tr()</code></td><td>Translate a singular form</td></tr><tr><td><code>trn()</code></td><td>Translate plural forms</td></tr><tr><td><code>trc()</code></td><td>Translate a singular form with a given context</td></tr><tr><td><code>trnc()</code></td><td>Translate plural forms with a given context</td></tr><tr><td><code>marktr()</code></td><td>Mark text for translation</td></tr></tbody></table>

These methods are `@Composable` , and they are bound to the application current locale. When the locale changes, all methods using translated texts are recomposed.&#x20;

This is an example of multi-language code with singular and plural forms.

```kotlin
div {
    +i18n.tr("This is a localized message.")
}
div {
    val count = 3
    +i18n.trn("{{name}} has one car", "{{name}} has {{count}} cars", count, "name" to "Robert", "count" to "$count")
}
```

{% hint style="info" %}
Note: You can use `{{ }}`  operators to substitute named values.
{% endhint %}

## Translation files

The whole idea of ​​gettext translations is that the translation key is the actual text in the primary language. Until you create and initialize translation files for some other language, your application will work correctly just by using string literals used in the source code. It's probably a good practice to use English literals in your code and other languages in the translation files.

To generate basic translation files run the command:

```
./gradlew gettext                                (on Linux)
gradlew.bat gettext                              (on Windows)
```

This command will search your sources for any usages of internationalization methods (`tr` or others) and generate a `messages.pot` file in the `src/commonMain/resources/modules/i18n` directory. This file is the base for your translations. For any language you would like to support, copy the `messages.pot` file to `messages-XX.po`, where XX is a country code (en, de, es, fr etc.). These files should be translated according to the [PO format specification](https://www.gnu.org/software/gettext/manual/html_node/PO-Files.html). You can use many popular tools for editing PO files to simplify the translation process.

{% code title="messages-pl.po" %}
```gettext
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the KVision package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: Kilua\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2018-08-18 01:34+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: Polish\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=CHARSET\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"

msgid "This is a localized message."
msgstr "To jest przetłumaczona wiadomość."

msgid "{{name}} has one car"
msgid_plural "{{name}} has {{count}} cars"
msgstr[0] "{{name}} ma jeden samochód"
msgstr[1] "{{name}} ma {{count}} samochody"
msgstr[2] "{{name}} ma {{count}} samochodów"
```
{% endcode %}

{% hint style="info" %}
You should correctly set Language and Plural-Forms headers of your PO files.
{% endhint %}

After adding some new texts to your sources you can call the `./gradlew gettext` task again to refresh the `messages.pot` file. You can then use the [`msgmerge`](https://www.gnu.org/software/gettext/manual/html_node/msgmerge-Invocation.html) tool from the GNU gettext package to merge new keys with existing translation files. You can also add new `msgid` and `msgstr` lines to your translation files manually.

## Initializing translations

To initialize translations for one or more languages, you need to pass the translation files as constructor parameters of the `I18n` class.

```kotlin
@JsModule("/kotlin/modules/i18n/messages-en.po")
external object messagesEn: JsAny

@JsModule("/kotlin/modules/i18n/messages-pl.po")
external object messagesPl: JsAny

val i18n = I18n(
    "en" to messagesEn,
    "pl" to messagesPl
)
```

## Changing the application locale

The current locale is stored in the `LocaleManager.currentLocale` property. It is initialized with the default locale from the browser language settings. It can be changed at any time using `LocaleManager.setCurrentLocale()` method.

```kotlin
select(listOf("en" to "English", "pl" to "Polski", "de" to "Deutsch"), LocaleManager.currentLocale.language) {
    onChange {
        LocaleManager.setCurrentLocale(SimpleLocale(this.value ?: "en"))
    }
}
```
