# Internationalization

## Features

* Automatic language detection (based on the browser language settings).
* Dynamic language change with automatic re-rendering of the whole application GUI.
* Multi-language support for built-in complex components:

  * datetime control - 46 languages
  * select control - 12 languages
  * upload control - 39 languages
  * richtext editor - 2 languages

  Contributions are welcomed.
* Minimal impact of internationalization process on the application source code.
* Automatic extraction of text to be translated from the application code.
* Support for well known translation files format (gettext `*.po` files).

## Requirements

To create a multi-language application you have to add the `kvision-i18n` module as a dependency for your project.

```groovy
dependencies {
// ...
    compile "io.kvision:kvision-i18n:${kvisionVersion}"
// ...
}
```

## Using multi-language text in application sources

To mark some text for translation just use one of the four available helper methods from the `io.kvision.i18n.I18n` object instead of plain string literals.

| Method   | Description                            |
| -------- | -------------------------------------- |
| tr       | Dynamic translation for singular form. |
| ntr      | Dynamic translation for plural forms.  |
| gettext  | Static translation for singular form.  |
| ngettext | Static translation for plural forms.   |

Dynamic translations are bound to the components they are part of (tag content, button text etc.). They are dynamically changed when the current language for the application is changed.

```kotlin
// ...
import io.kvision.i18n.tr
// ...

span(tr("Label text"))
button(tr("Button text"))
```

Static translations are evaluated only when the helper method is called. They can be used to translate text not bound to any KVision component.

```kotlin
// ...
import io.kvision.i18n.gettext
// ...

console.log(gettext("Some info message"))
```

KVision has support for plural language forms, so you can use `ntr` or `ngettext` methods when plural forms are necessary.

```kotlin
// ...
import io.kvision.i18n.I18n.ntr
// ...

val count = 5
hPanel {
    span("$count")
    span(ntr("file", "files", count))
}
```

The `gettext` and `ngettext` methods allow you to use additional runtime parameters, using gettext.js substitution mechanism and the following format of translation files:

{% code title="messages-en.po" %}

```kotlin
msgid "%2 has one car"
msgid_plural "%2 has %1 cars"
msgstr[0] ""
msgstr[1] ""
```

{% endcode %}

{% code title="messages-pl.po" %}

```kotlin
msgid "%2 has one car"
msgid_plural "%2 has %1 cars"
msgstr[0] "%2 ma jeden samochód"
msgstr[1] "%2 ma %1 samochody"
msgstr[2] "%2 ma %1 samochodów"
```

{% endcode %}

Use this translation in your application like this:

```kotlin
ngettext("%2 has one car", "%2 has %1 cars", 3, "Robert")
```

## Translation files

Until you create and initialize translation files for some other language, your application will use 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 generatePotFile                                (on Linux)
gradlew.bat generatePotFile                              (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/jsMain/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.

{% 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 generatePotFile` task 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 by hand.

## Initializing translations

To initialize translations for one or more languages, you need to initialize the `I18n.manager` property during application initialization (preferably in the `start` method of your `Application` object). You should add all supported languages to the map given as the parameter to the `DefaultI18nManager` constructor.

```kotlin
@JsModule("/kotlin/modules/i18n/messages-en.json")
external val messagesEn: dynamic

@JsModule("/kotlin/modules/i18n/messages-pl.json")
external val messagesPl: dynamic

@JsModule("/kotlin/modules/i18n/messages-de.json")
external val messagesDe: dynamic

class Helloworld : Application() {
    override fun start() {
        // ...
        I18n.manager =
                DefaultI18nManager(
                    mapOf(
                        "en" to messagesEn,
                        "pl" to messagesPl,
                        "de" to messagesDe
                    )
                )
        // ...
    }
}
```

## Changing the current language

The current language is bound to the `I18n.language` property. This property is initialized with the default country code from the browser language settings. It can be changed at any time from your code.

```kotlin
select(listOf("en" to "English", "de" to "Deutsch"), I18n.language) {
    onEvent {
        change = {
            I18n.language = self.value ?: "en"
        }
    }
}
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://kvision.gitbook.io/kvision-guide/2.-frontend-development-guide/internationalization.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
