---
title: "Translations"
description: "Translations"
---
{/* cSpell: ignore msgfmt msgctx msginit poedit Lokalize Transifex libintl bindtextdomain */}

import { Tabs, TabItem, FileTree } from '@astrojs/starlight/components';
import LangRefLink from '@slint/common-files/src/components/LangRefLink.astro';
import Link from '@slint/common-files/src/components/Link.astro';

Slint's translation infrastructure makes your application available in different languages.

:::tip[Prerequisite]
Install the [`slint-tr-extractor`](https://crates.io/crates/slint-tr-extractor) tool to extract translatable strings from `.slint` files:
```sh
cargo install --locked slint-tr-extractor
```
:::

You can choose between runtime translations using `gettext` or bundling translations directly into your executable for platforms where `gettext` is unavailable or impractical.

To translate your application, follow these steps:

1. Identify all user-visible strings that need translation and annotate them with the `@tr()` macro.
2. Extract annotated strings by running the `slint-tr-extractor` tool to generate `.pot` files.
3. Use a third-party tool to translate the strings into `.po` files for each target language.
4. **(For runtime `gettext` translations only)** Convert `.po` files into `.mo` files using [gettext's `msgfmt`](https://www.gnu.org/software/gettext/manual/gettext.html).
5. **(For bundled translations only)** Configure bundling during the build process to embed translations into your application.
6. Use Slint's API to select the appropriate translation based on the user's locale.

At this point, all strings marked for translation will be automatically rendered in the selected language.

## Annotating Translatable Strings

Use the `@tr` macro in `.slint` files to mark strings for translation.
This macro supports formatting and pluralization, and can include contextual information.

The first argument must be a plain string literal, followed by the arguments:

### Basic Example
```slint
export component Example {
    property <string> name;
    Text {
        text: @tr("Hello, {}", name);
    }
}
```

### Formatting

Each `{}` placeholder in the format string is replaced with the corresponding argument, in order.
A placeholder can name a zero-based position, as in `{0}` or `{1}`, to pick an argument explicitly.
Positional and non-positional placeholders can't be mixed in one format string.
A translation may use positional placeholders even when the source string doesn't.

Write a literal `{` or `}` by doubling it, as `{{` or `}}`.
An unterminated placeholder, an unescaped `{` or `}`, or more placeholders than arguments is an error.

### Plurals

A plural form picks between two format strings based on a count.
Write it with `|` between the two string literals and `%` before the count expression:

```slint no-test
@tr("I have {n} item" | "I have {n} items" % count)
```

Both sides of the `|` must be plain string literals, and the count expression is converted to `int`.
The `{n}` placeholder refers to the count and is only valid in a plural form.
Other placeholders still refer to the arguments after the count:

```slint
export component Example inherits Text {
    in property <int> score;
    in property <int> name;
    text: @tr("Hello {0}, you have one point" | "Hello {0}, you have {n} points" % score, name);
}
```

### Contexts

A context disambiguates strings that share the same source text but differ in meaning.
Write it as a plain string literal followed by `=>` before the format string:

```slint
export component MenuItem {
    property <string> name: @tr("Default Name"); // context: `MenuItem`
    property <string> tooltip: @tr("ToolTip" => "ToolTip for {}", name); // context: `ToolTip`
}
```

Without a context, it defaults to the name of the enclosing component.

Pass the `--no-default-translation-context` flag to `slint-tr-extractor` if you don't want the component name to be the default context. The same option needs to be passed to the Slint compiler:

<Tabs syncKey="dev-language">
<TabItem label="Rust" icon="seti:rust">
With <LangRefLink lang="rust-slint-build" relpath="struct.compilerconfiguration#method.with_default_translation_context">`slint_build::CompilerConfiguration::with_default_translation_context(slint_build::DefaultTranslationContext::None)`</LangRefLink>
when using a build script.
With <LangRefLink lang="rust-slint-interpreter" relpath="struct.compiler#method.set_default_translation_context">`slint_interpreter::Compiler::set_default_translation_context(slint_interpreter::DefaultTranslationContext::None)`</LangRefLink>
when using the `slint-interpreter` crate.
</TabItem>
<TabItem label="C++" icon="seti:cpp">
Set the <LangRefLink lang="cpp" relpath="cmake-reference/disable-default-translation-context/">`SLINT_NO_DEFAULT_TRANSLATION_CONTEXT`</LangRefLink> target property on your CMake target.
</TabItem>
</Tabs>

## Extracting Translatable Strings

Use [`slint-tr-extractor`](https://crates.io/crates/slint-tr-extractor) to generate a `.pot` file with all strings marked for translation:
```sh
find -name \*.slint | xargs slint-tr-extractor -o MY_PROJECT.pot
```

This creates a file called `MY_PROJECT.pot`. Replace "MY_PROJECT" with your actual project name.
To learn how the project name affects the lookup of translations, read the sections below.

:::tip[Tip]
`.pot` files are [Gettext](https://www.gnu.org/software/gettext/) template files.
:::

## Translating Strings

Start a new translation by creating a `.po` file from a `.pot` file. Both file formats are identical.
You can either copy the file manually or use a tool like Gettext's `msginit` to start a new `.po` file.

The `.po` file contains the strings in a target language.

`.po` and `.pot` files are plain text files that you can edit with a text editor. We recommend
using a dedicated translation tool for working with them, such as the following:

-   [poedit](https://poedit.net/)
-   [OmegaT](https://omegat.org/)
-   [Lokalize](https://userbase.kde.org/Lokalize)
-   [Transifex](https://www.transifex.com/) (web interface)

## Runtime Translations with Gettext

Slint can use the [Gettext](https://www.gnu.org/software/gettext/) library to load translations at run-time.

Gettext expects translation files - called message catalogs - in following directory hierarchy:

<FileTree>

- dir_name/
  - locale/  e.g. `fr`, `en`, `de`, etc
    - LC_MESSAGES/
      - domain_name.mo
</FileTree>


-   `dir_name`: the base directory that you can choose freely.
-   `locale`: The name of the user's locale for a given target language, such as `fr` for French, or `de` for German.

    The locale is typically determined using environment variables that your operating system sets.

-   `domain_name`: Selected based on the programming language you're using Slint with.

:::tip[Tip]
Read the [Gettext documentation](https://www.gnu.org/software/gettext/manual/gettext.html#Locating-Catalogs) for more information.
:::

### Convert `.po` Files to `.mo` Files

Convert the human readable `.po` files into machine-friendly `.mo` files, which are a binary representation
that is more efficient to read by code.

Use [Gettext](https://www.gnu.org/software/gettext/)'s `msgfmt` command line tool to convert `.po` files to `.mo`
files:

```sh
msgfmt translation.po -o translation.mo
```

### Select and Load Translations
<Tabs syncKey="dev-language">
<TabItem label="Rust" icon="seti:rust">

First, enable the `gettext` feature of the `slint` crate in the `features` section to gain access to the translations API
and activate run-time translation support.

Next, use the <LangRefLink lang="rust-slint" relpath="macro.init_translations">`slint::init_translations!`</LangRefLink> macro to specify the base location of your `.mo` files.
This is the `dir_name` in the scheme of the previous section. Slint expects the `.mo` files to be in the
corresponding sub-directories and their file name - `domain_name` - must match the package name
in your `Cargo.toml`. This is often the same as the crate name.

For example:

```rust
slint::init_translations!(concat!(env!("CARGO_MANIFEST_DIR"), "/lang/"));
```

For example, if your `Cargo.toml` contains the following lines and the user's locale is `fr`:

```toml
[package]
name = "gallery"
```

With these settings, Slint looks for `gallery.mo` in the `lang/fr/LC_MESSAGES/gallery.mo`.
</TabItem>
<TabItem label="C++" icon="seti:cpp">

First, enable the `SLINT_FEATURE_GETTEXT` cmake option when compiling Slint to gain access to
the translations API and activate run-time translation support.

In C++ applications using cmake, the `domain_name` is the CMake target name.

Next, bind the text domain to a path using the standard gettext library.

To do so, add this in your `CMakeLists.txt` file:

```cmake
find_package(Intl)
if(Intl_FOUND)
    target_compile_definitions(my_application PRIVATE HAVE_GETTEXT SRC_DIR="${CMAKE_CURRENT_SOURCE_DIR}")
    target_link_libraries(my_application PRIVATE Intl::Intl)
endif()
```

You can then setup the locale and the text domain

```c++
#ifdef HAVE_GETTEXT
#    include <locale>
#    include <libintl.h>
#endif

int main()
{
#ifdef HAVE_GETTEXT
    bindtextdomain("my_application", SRC_DIR "/lang/");
    std::locale::global(std::locale(""));
#endif
   //...
}
```

For example, if you're using the above and the user's locale is `fr`,
Slint looks for `my_application.mo` in the `lang/fr/LC_MESSAGES/` directory.
</TabItem>
</Tabs>

## Bundled Translations

Bundled translations embed the translated strings directly into your application binary.
This approach is ideal for platforms like WASM or microcontrollers where `gettext` is unavailable.

Configure the Slint compiler to bundle translations by providing a path to the translations.
Translation files should be organized in the following hierarchy:

```
path/<lang>/LC_MESSAGES/<domain>.po
```

### Bundling
<Tabs syncKey="dev-language">
<TabItem label="Rust" icon="seti:rust">

Use `slint_build::CompilerConfiguration`'s <LangRefLink lang="rust-slint-build" relpath="struct.compilerconfiguration#method.with_bundled_translations">`with_bundled_translations()`</LangRefLink> function to set up bundling in
`build.rs`:

```rust
let config = slint_build::CompilerConfiguration::new()
    .with_bundled_translations("path/to/translations");
slint_build::compile_with_config("path/to/main-ui.slint", config).unwrap();
```

The `<domain>` is the crate name.
</TabItem>
<TabItem label="C++" icon="seti:cpp">
Set the <LangRefLink lang="cpp" relpath="cmake-reference/bundle-translations/">`SLINT_BUNDLE_TRANSLATIONS`</LangRefLink> property in CMake:

```cmake
set_property(TARGET my_application PROPERTY SLINT_BUNDLE_TRANSLATIONS "${CMAKE_CURRENT_SOURCE_DIR}/lang")
```

the `<domain>` is the cmake target name.

</TabItem>
</Tabs>



### Selecting a Translation

If you enable the `std` feature with Slint, language for translations is detected based on the locale:
if one of the bundled language matches the selected locale, it will be used.

<Tabs syncKey="dev-language">
<TabItem label="Rust" icon="seti:rust">
Use the <LangRefLink lang="rust-slint" relpath="fn.select_bundled_translation.html">`slint::select_bundled_translation`</LangRefLink> function to change translations at runtime.
</TabItem>
<TabItem label="C++" icon="seti:cpp">
Use the <LangRefLink lang="cpp" relpath="api/slint/select-bundled-translation/">`slint::select_bundled_translation`</LangRefLink> function to change translations at runtime.
</TabItem>
<TabItem label="Python" icon="seti:python">
Use the <LangRefLink lang="python" relpath="api/functions/init_translations/">`slint.init_translations()`</LangRefLink> function to change translations at runtime.
</TabItem>
</Tabs>

## Previewing Translations with `slint-viewer`

Make sure the `gettext` feature was enabled when building slint-viewer.
Use the `--translation-domain` and `--translation-dir` command line options to load translations for preview.

## Selecting the Decimal Separator

Conversions between `float` and `string` use the locale's decimal separator,
for example the comma (`,`) in a German locale.
See [Converting Between Numbers and Strings](/master/docs/slint/reference/language/type-conversions.md#converting-between-numbers-and-strings) for the conversion rules.

Read the currently used separator from [Platform.decimal-separator](/master/docs/slint/reference/platform.md#decimal-separator).
It defaults to the dot (`.`).

When bundling translations, the decimal separator of each language is determined at compile time
and bundled with the application:
selecting a translation also selects its decimal separator.
When the `gettext` feature is enabled, the decimal separator is determined from the system locale.