Skip to main content

gitversion_rs/
i18n.rs

1//! Locale selection helper.
2//!
3//! Translations themselves are handled by [`rust_i18n`] from YAML files in `locales/` (English default).
4//! This module maps the `--lang` argument or environment variables to a rust-i18n locale code.
5
6/// Normalise a locale string (e.g. "en", "ja", "zh-CN", "en_US.UTF-8") to a locale code.
7fn normalize(s: &str) -> Option<&'static str> {
8    let s = s.trim().to_lowercase();
9    if s.starts_with("ja") || s == "japanese" {
10        Some("ja")
11    } else if s.starts_with("zh") || s == "chinese" {
12        Some("zh")
13    } else if s.starts_with("ko") || s == "korean" {
14        Some("ko")
15    } else if s.starts_with("en") || s == "english" || s == "c" || s == "posix" {
16        Some("en")
17    } else {
18        None
19    }
20}
21
22/// Initialise the locale from the `--lang` argument (takes priority) or the `LC_ALL`/`LANG` environment variables. Defaults to English.
23pub fn init(explicit: Option<&str>) {
24    let chosen = explicit
25        .and_then(normalize)
26        .or_else(|| {
27            std::env::var("LC_ALL")
28                .or_else(|_| std::env::var("LANG"))
29                .ok()
30                .and_then(|v| normalize(&v))
31        })
32        .unwrap_or("en");
33    rust_i18n::set_locale(chosen);
34}
35
36#[cfg(test)]
37mod tests {
38    use rust_i18n::t;
39
40    // set_locale is global state and races under parallel tests.
41    // Tests use `t!(.., locale = "..")` to specify the locale per-call instead of mutating the global.
42    #[test]
43    fn translates_by_locale() {
44        assert_eq!(t!("status.ready", locale = "en"), "Ready");
45        assert_eq!(t!("status.ready", locale = "ko"), "준비 완료");
46        assert_eq!(t!("status.ready", locale = "ja"), "準備完了");
47        assert_eq!(t!("status.ready", locale = "zh"), "就绪");
48    }
49
50    #[test]
51    fn interpolation() {
52        assert_eq!(
53            t!("error.generic", locale = "en", error = "boom"),
54            "Error: boom"
55        );
56    }
57
58    /// The TUI passes keys as runtime variables (`t!(*k)`), so this verifies that variable key
59    /// resolution works and that every `tui.*` key actually exists in the YAML (missing keys render as the raw key string).
60    #[test]
61    fn runtime_variable_key_resolves() {
62        let key = "tui.tab.variables";
63        assert_eq!(t!(key, locale = "en"), "Variables");
64        assert_eq!(t!(key, locale = "ko"), "변수");
65    }
66}