How Locale Negotiation Works in OpenLogi: Reading Host Language Preferences
OpenLogi determines the host’s language preference by first checking explicit user settings, then querying the OS via sys_locale::get_locale(), and falling back to English, with all resolution logic centralized in the openlogi-core crate.
OpenLogi implements a deterministic locale negotiation system that ensures consistent language selection across its desktop UI, background agent, and overlay components. According to the AprilNEA/OpenLogi source code, the resolution pipeline lives entirely within crates/openlogi-core/src/locale.rs and relies on a strict priority order: stored preferences override system detection, while unrecognized codes gracefully degrade to the default English catalog.
The Six-Step Locale Resolution Pipeline
The resolve() function (lines 56–68 in locale.rs) implements a cascading fallback strategy:
- Explicit stored setting – The optional
languageargument passed toactivate()typically originates fromAppSettingsincrate::config::AppSettings. - OS locale detection – If no valid setting exists, the system calls
sys_locale::get_locale()to retrieve the host’s BCP‑47 language tag. - String normalization – Raw locale strings have underscores converted to dashes (e.g.,
en_US→en-US) before parsing. - Special-case handling – Language families like Chinese (
zh), Portuguese (pt), and Norwegian receive custom mapping rules viaspecial_locale(). - Supported catalog matching – For standard cases,
lookup_supported()usesfluent_langneg::negotiate_languageswith a lookup strategy against theSUPPORTEDconstant containing all shipped locales. - Global activation – The final resolved code is passed to
rust_i18n::set_locale(), which stores it in a process‑wide atomic for UI and agent consumption.
Core Resolution Logic in openlogi-core/src/locale.rs
The heart of the system is the resolve() function, which chains optionals to enforce the priority order:
/// Resolve the locale to apply, preferring an explicit stored `setting`,
/// then the system locale, and finally `"en"`.
fn resolve(setting: Option<&str>) -> &'static str {
setting
.and_then(match_supported) // 1️⃣ explicit setting
.or_else(|| {
sys_locale::get_locale() // 2️⃣ OS locale
.as_deref()
.and_then(match_supported) // 3️⃣ match against SUPPORTED
})
.unwrap_or("en") // 4️⃣ fallback
}
When match_supported() (lines 81–112) receives a locale string, it first attempts to parse it into a LanguageIdentifier from the fluent_langneg crate. The matcher validates the identifier against the catalog returned by supported_langids(), which derives from the internal SUPPORTED constant listing all available translation files in crates/openlogi-ui/locales/.
Special Locale Handling
The special_locale() helper applies deterministic rules for edge cases:
- Chinese variants map traditional scripts to specific region codes (
zh-Hant-HK→zh-HK). - Portuguese distinguishes between Brazil and Portugal (
pt-BRvspt). - Norwegian resolves
nb-NOandnn-NOto the unifiednbcatalog.
Activating Locales Across Application Components
All OpenLogi processes—GUI, agent, and overlay—call openlogi_core::locale::activate() at startup to synchronize language state.
To activate based on stored settings (or system default if none):
// In the GUI or agent startup
openlogi_core::locale::activate(None);
To explicitly override from a command‑line argument or settings picker:
// User selected “Français” in the Settings pane
openlogi_core::locale::activate(Some("fr"));
Integration Points
crates/openlogi-desktop/src/services/i18n.rsinitializes the UI locale during application boot.crates/openlogi-agent/src/main.rssets the background agent’s menu‑bar language before tray initialization.crates/openlogi-overlay/src/main.rspasses the invoking process language to ensure the overlay matches the active application context.
Testing Locale Matching
You can validate the normalization and matching logic directly:
use openlogi_core::locale::match_supported;
assert_eq!(match_supported("zh-Hant-HK"), Some("zh-HK"));
assert_eq!(match_supported("pt-BR"), Some("pt-BR"));
assert_eq!(match_supported("nb-NO"), Some("nb"));
This demonstrates how underspecified or overly specific locale strings collapse to the nearest supported catalog.
Summary
- OpenLogi centralizes all locale negotiation in
crates/openlogi-core/src/locale.rsto guarantee consistency across processes. - The resolution order is: stored user setting → OS locale via
sys_locale::get_locale()→ English fallback. - Special rules handle complex language families (Chinese, Portuguese, Norwegian) before standard lookup.
- The
match_supported()function validates locales against theSUPPORTEDconstant usingfluent_langnegnegotiation. - All components call
openlogi_core::locale::activate()to apply the resolved locale viarust_i18n::set_locale().
Frequently Asked Questions
How does OpenLogi prioritize multiple language sources?
OpenLogi uses a strict cascading fallback. It first checks the explicit language parameter passed to activate(), which typically comes from AppSettings. If that is None or unrecognized, it queries the host OS via sys_locale::get_locale(). Only if both sources fail to produce a match does it default to "en" (English).
What happens if my system locale is not in the supported list?
The match_supported() function attempts to negotiate the closest match using the fluent_langneg crate. For example, zh-Hant-HK resolves to the zh-HK catalog. If no reasonable match exists (e.g., an obscure language code), the system falls back to English to ensure the UI remains functional.
Why are Chinese, Portuguese, and Norwegian handled specially?
These languages have complex regional or script variants that standard BCP‑47 negotiation cannot map cleanly to OpenLogi’s shipped catalogs. The special_locale() function encodes explicit business logic—such as mapping nb-NO to nb—to ensure users receive the most appropriate translation file available.
Can I force a specific locale for testing or debugging?
Yes. By calling openlogi_core::locale::activate(Some("fr")) (or any valid code) before the UI initializes, you override both stored settings and OS detection. This is commonly used in the desktop entry points and integration tests to verify specific localization paths.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →