egui-i18n
An internationalization (i18n) library for egui, providing runtime language switching, dynamic parameter interpolation, and a language fallback chain — without any modifications to egui's source code.
Supports two independent translation backends selectable via Cargo features:
| Feature | Backend | File format |
|---|---|---|
classic (default) |
Key-value pairs | .egl / .properties |
fluent |
Mozilla Fluent | .ftl |
Installation
[]
# Classic key-value backend (default)
= "0.2"
# Fluent backend
= { = "0.2", = ["fluent"] }
The two features are mutually exclusive. Enabling
fluentdisablesclassic.
Quick Start
Classic backend
Translation file (assets/en-US.egl):
# Lines beginning with # are comments and are ignored.
welcome = Welcome to the app!
hello-name = Hello, {name}!
intro = My name is {name} and I am {age} years old.
# Keys that contain a literal = must escape it with \=
Hello\=, {name}! = Hello=, {name}!
Rust code:
use tr;
// Inside your egui update loop:
ui.label;
ui.label;
ui.label;
Fluent backend
Translation file (assets/en-US.ftl):
welcome = Welcome to the app!
hello-name = Hello, { $name }!
item-count =
{ $count ->
[one] One item
*[other] { $count } items
}
Rust code:
use tr;
// Inside your egui update loop:
ui.label;
ui.label;
ui.label;
API Reference
Language configuration
// Set the active display language.
set_language;
// Get the currently active language identifier.
let lang: String = get_language;
// Set the fallback language used when a key is missing in the active language.
set_fallback;
// Get the current fallback language identifier.
let fallback: String = get_fallback;
// Return all language identifiers that have been loaded.
let langs: = languages;
Loading translations
// Load from an in-memory string (the most common approach with include_str!).
load_translations_from_text?;
// Load from a HashMap<String, String> — classic backend only.
// Returns Err in fluent mode.
load_translations_from_map?;
// Scan a directory and load every .egl / .ftl file found.
// Each file's stem is used as the language identifier.
load_translations_from_path?;
Translating
// No arguments.
let s: String = tr!;
// One or more named arguments.
let s: String = tr!;
let s: String = tr!;
Fluent-only options
// Control whether Fluent wraps placeables in Unicode directionality marks.
// Default: true. Set to false before loading bundles to suppress the marks.
set_use_isolating;
// Query the current setting.
let isolating: bool = get_use_isolating;
Translation file format
Classic (.egl)
# Comment — this line is ignored entirely.
key = value
hello-name = Hello, {name}!
# Multi-line values: lines without = are appended to the previous key.
long-text = Line one
continues here
still the same value
# Keys containing a literal = must escape it with \=
A\=B = A equals B
Rules:
- Lines starting with
#are comments. - Both Unix (
LF) and Windows (CRLF) line endings are supported. - Leading and trailing whitespace around keys and values is trimmed.
- Placeholders use
{name}syntax and are replaced at runtime.
Fluent (.ftl)
Fluent is a fully-featured localization system. See the Fluent syntax guide for the complete reference. Key capabilities used here include:
- Named arguments:
{ $name } - Plural selectors:
{ $count -> [one] … *[other] … } - Exact number matching:
{ $n -> [0] Zero [1] One *[other] … }
Fallback behaviour
When a translation key is looked up:
- The active language (
set_language) is searched first. - If the key is not found (or the language was never loaded), the fallback language
(
set_fallback) is tried. - If neither contains the key, an empty string is returned.
set_language; // primary
set_fallback; // used when primary is missing a key
Important: call all configuration functions (
set_language,set_fallback,set_use_isolating) before loading any translation bundles, so that each bundle is constructed with the correct settings.
Loading from the filesystem
load_translations_from_path accepts either a file path or a directory path.
// Load a single file — its stem becomes the language identifier.
load_translations_from_path?;
// Load all .egl / .ftl files in a directory.
load_translations_from_path?;
// This is equivalent to loading i18n/en-US.ftl → "en-US",
// i18n/zh-Hans.ftl → "zh-Hans", etc.
CLI tool
The companion egui-i18n-cli tool scans Rust source files for tr!(...) macro calls,
extracts the translation keys, and generates or updates translation files with stubs for
any newly discovered keys.
egui-i18n-cli generate \
--source-path ./src \
--output-path ./i18n \
--language en-US \
--language zh-Hans \
--default-language en-US \
--ext egl
| Option | Description |
|---|---|
--source-path |
Root directory to scan for .rs files |
--output-path |
Directory where translation files are written (default: current directory) |
--extension |
Additional file extensions to scan (default: rs) |
--language |
Language identifiers to generate files for (default: en_US) |
--default-language |
When set, newly found keys in this language are pre-filled with the key itself as the value |
--ext |
Output file extension: egl or ftl (default: tgl) |
Running the command again is safe — existing translations are preserved and only new keys are appended.
Examples
Two fully runnable example applications are included:
| Example | Command |
|---|---|
| Classic backend | cargo run -p egui-i18n-example-classic |
| Fluent backend | cargo run -p egui-i18n-example-fluent |
Both examples demonstrate runtime language switching via on-screen buttons and dynamic argument interpolation.
Feature flags
| Feature | Description | Default |
|---|---|---|
classic |
Enable the key-value translation backend | ✅ yes |
fluent |
Enable the Mozilla Fluent translation backend | ❌ no |
The two features are mutually exclusive. If fluent is enabled, classic is
automatically disabled.
License
This project is licensed under the MIT License.