-
Notifications
You must be signed in to change notification settings - Fork 9
Design Internationalization
The i18n framework provides multi-language support, plural forms, number / date / currency formatting, and RTL helpers. Everything lives in crates/yororen-ui-core/src/i18n/ plus three optional locale crates.
crates/yororen-ui-core/src/i18n/
├── format/ → NumberFormatter, DateTimeFormatter, …
├── loader.rs → parse_translation_value
├── locale.rs → Locale, TextDirection, SupportedLocale
├── mod.rs → re-exports the public surface
├── placeholder.rs → PlaceholderResolver
├── runtime.rs → I18n, Translate, TranslationMap
└── translate.rs → PluralCategory, TranslatedString
Three locale crates ship — yororen-ui-locale-en, yororen-ui-locale-zh-CN, yororen-ui-locale-ar. Each exposes translation_map() and install(cx).
yororen_ui::locale_en::install(cx); // English
// or: yororen_ui::locale_zh_cn::install(cx);
// or: yororen_ui::locale_ar::install(cx); // Arabic (RTL)Or use the longer form for finer control:
use yororen_ui::i18n::{I18n, Locale};
let mut i18n = I18n::with_locale_fallback(
Locale::new("zh-CN").unwrap(),
Locale::new("en").unwrap(),
);
i18n.load_translations(Locale::new("zh-CN").unwrap(), yororen_ui::locale_zh_cn::translation_map());
i18n.load_translations(Locale::new("en").unwrap(), yororen_ui::locale_en::translation_map());
// Layer app strings on top:
i18n.merge_translations(Locale::new("zh-CN").unwrap(), my_app_zh_cn_map);
cx.set_global(i18n);The Translate trait is implemented for gpui::App and Context<'_, T>:
pub trait Translate {
fn t(&self, key: &str) -> SharedString;
fn t_with_args(&self, key: &str, args: &[&str]) -> SharedString;
fn lookup(&self, key: &str) -> Option<SharedString>;
}let save: SharedString = cx.t("common.save");Lookup order: current locale → fallback locale (if set) → raw key path with a one-shot warning.
Templates use positional {} slots: "greeting": "Hello {}, you have {} items".
let text = cx.t_with_args("greeting", &["World", "5"]);
// → "Hello World, you have 5 items"TranslationMap::tn(key, n) selects the language-appropriate PluralCategory for n and looks up key.<category>. Falls back to key.other.
| Category | Example languages |
|---|---|
Zero / One / Two / Few / Many / Other
|
Arabic (six forms) |
One / Other
|
English, German, Dutch |
Other only |
Chinese, Japanese, Korean, Vietnamese, Thai |
{
"items": {
"one": "{} item",
"other": "{} items"
}
}let cat = PluralCategory::for_number(5, &Locale::new("en").unwrap()); // Other
let cat = PluralCategory::for_number(1, &Locale::new("en").unwrap()); // Onecx.i18n().set_locale(Locale::new("zh-CN").unwrap());
let locale = cx.i18n().locale();
let is_rtl = cx.i18n().is_rtl();
let direction = cx.i18n().text_direction();
cx.i18n().set_fallback_locale(Some(Locale::new("en").unwrap()));
cx.i18n().set_fallback_locale(None);Locale::text_direction() returns TextDirection::Ltr or TextDirection::Rtl. RTL languages: ar, he, fa, ur, yi, ps.
use yororen_ui::i18n::{NumberFormatter, Locale};
let formatter = NumberFormatter::new(Locale::new("en").unwrap());
formatter.format_decimal(1234.5); // "1,234.5"
formatter.format_currency(99.99, "USD"); // "$ 99.99"
let ar = NumberFormatter::new(Locale::new("ar").unwrap());
ar.format_decimal(1234567.89); // "١٬٢٣٤٫٥٦٧٫٨٩"Date formatting:
| Locale | format_date(2024-01-01) |
|---|---|
| en | 2024-01-01 |
| zh / ja | 2024年01月01日 |
| de | 01.01.2024 |
| fr | 01/01/2024 |
crates/yororen-ui-core/src/rtl.rs flips common "start / end" concepts for RTL locales:
use yororen_ui::rtl;
let direction = cx.i18n().text_direction();
let align = rtl::text_align_start(direction); // LTR: Left, RTL: Right
let flex = rtl::flex_row(direction); // LTR: Row, RTL: RowReverse
rtl::padding_start(&mut style, direction, px(8.));
rtl::padding_end(&mut style, direction, px(8.));
rtl::corner_radius_start(&mut style, direction, px(4.));If your custom layout uses .left_* / .right_* directly instead of these helpers (or gpui's built-in .start_* / .end_*), it will render wrong in RTL locales.
- Always provide explicit placeholders on components that default to one. The framework's bundled strings may not match your intent.
-
Use positional
{}placeholders, not{name}-style. The runtime parser is non-greedy and ignores anything between{and}, treating each{}as the next positional slot. -
Always pair a non-en locale with an
enfallback so a partial catalog doesn't leak rawcommon.cancelkeys into the UI. -
Use the
rtl::*helpers for any direction-sensitive style. Never call.left_*/.right_*directly on a custom div. -
Layer app strings on top of framework strings via
I18n::merge_translations(locale, app_map)so the framework'scommon.savecontinues to resolve.
- Layout rules — RTL-aware flex / padding / radius.
- Theming — themes are JSON; locales are JSON.
Yororen UI v0.3.0 · repository · Apache-2.0 · This wiki documents Yororen UI v0.3.0.
This wiki documents Yororen UI v0.3.0 — the headless-core, swappable-renderer build.