19 releases
Uses new Rust 2024
| new 0.3.1 | Mar 1, 2026 |
|---|---|
| 0.3.0 | Feb 28, 2026 |
| 0.2.7 | Feb 28, 2026 |
| 0.1.9 | Feb 27, 2026 |
| 0.1.3 | Dec 29, 2023 |
#139 in Internationalization (i18n)
Used in poise-i18n
28KB
491 lines
Rusty18n
Rusty18n is a small in-memory i18n library for Rust with:
- A single DSL source of truth for fallback schema and values
- Sparse locale overrides
- Fallback resolution for omitted locale fields
- Static string resources and explicit dynamic formatters
Install
cargo add rusty18n
Current Macro Flow
- Define the fallback schema with
define_i18n_fallback!. - Define each locale override with
define_i18n!. - Generate
I18NUsage::Key,I18NUsage::locales(), andI18NUsage::locales_dynamic()withdefine_i18n_locales!. - Read values with
I18NStore::get/I18NDynamicWrapper::getandt_prefix!/t!.
DSL
define_i18n_fallback! and define_i18n! support:
- Nested field:
field: { ... } - Static resource:
field: "Text" - Dynamic resource:
field: |a, b, c| "{a} {b} {c}"
Both macros now require a locale key:
- Fallback:
define_i18n_fallback! { I18NUsage => en ... } - Locale:
define_i18n! { I18NUsage => pt ... }
define_i18n_fallback! and define_i18n! generate constructor functions named from the
locale key in lowercase (for example pt -> pt), so you do not need a manual wrapper fn.
Dynamic resources use explicit formatter parameters and are rendered with .with((...)).
Formatter arguments are passed as tuples, and each item only needs to implement Display.
Non-default locales are stored as sparse overrides. A lookup always returns a resolved view, so omitted override fields automatically read from the fallback locale.
Example
Fallback schema (example/src/i18n/en.rs)
use rusty18n::define_i18n_fallback;
define_i18n_fallback! {
I18NUsage => en
greetings: {
waves: "Waves",
cool: "Hey that is cool",
},
calculus: {
answers: |a, b, c| "{a}+{b}={c} yeah!",
},
}
Locale override (example/src/i18n/pt.rs)
use crate::i18n::I18NUsage;
use rusty18n::define_i18n;
define_i18n! {
I18NUsage => pt
greetings: {
waves: "Oi!",
}
}
Locale registry (example/src/i18n/mod.rs)
pub mod en;
pub mod pt;
rusty18n::define_i18n_locales! {
I18NUsage => en|pt
}
Use in app (example/src/main.rs)
use rusty18n::t_prefix;
mod i18n;
fn main() {
let locales = i18n::I18NUsage::locales();
let i18n = locales.get(i18n::I18NUsage::Key::pt);
let a = 3;
let b = 2;
let result = a + b;
t_prefix!($wah, i18n);
let response_static = wah!(greetings.waves);
let response_dynamic = wah!(calculus.answers).with((a, b, result));
println!("{}", response_static);
println!("{}", response_dynamic);
}
In this example:
greetings.wavesis overridden inpt("Oi!")calculus.answersis missing inpt, so it falls back to the fallback localewah!(calculus.answers)returns a dynamic formatter, so.with((a, b, result))renders it
Macros
define_i18n_fallback!: defines fallback type + values and generates a locale constructor.define_i18n!: defines sparse locale overrides and generates a locale constructor.define_i18n_locales!: generates theI18NUsagenamespace module withValue,Override,Key,locales(), andlocales_dynamic().t_prefix!: creates a scoped accessor macro for a resolved locale value.t!: direct accessor macro for one-off lookups.
Dependencies
~0.2–4.5MB
~68K SLoC