Skip to main content

escouade_plugin_kit/
i18n.rs

1//! The language of the interface, in which a plugin of the first hand writes what the user reads (an error, a state's
2//! name): French or English, as Escouade's. A plugin is told it by `initialize` (a module has no environment,
3//! docs/PLUGINS.md §8.4.8); a process reads it from `ESCOUADE_LANG` (`fr`, `en`) before that. The core sets it as its
4//! own changes (`set_ui`).
5
6use std::sync::atomic::{AtomicU8, Ordering};
7
8#[derive(Debug, Clone, Copy, PartialEq, Eq)]
9pub enum Lang {
10    Fr,
11    En,
12}
13
14impl Lang {
15    pub fn code(self) -> &'static str {
16        match self {
17            Lang::Fr => "fr",
18            Lang::En => "en",
19        }
20    }
21
22    /// `en` is English; anything else French, as Escouade's default.
23    pub fn of_code(code: &str) -> Lang {
24        if code.trim().eq_ignore_ascii_case("en") {
25            Lang::En
26        } else {
27            Lang::Fr
28        }
29    }
30}
31
32static UI: AtomicU8 = AtomicU8::new(0);
33
34/// The interface's language.
35pub fn ui() -> Lang {
36    match UI.load(Ordering::Relaxed) {
37        1 => Lang::En,
38        _ => Lang::Fr,
39    }
40}
41
42pub fn set_ui(lang: Lang) {
43    UI.store(u8::from(lang == Lang::En), Ordering::Relaxed);
44}
45
46/// The language Escouade gave the plugin's process (`ESCOUADE_LANG`), when it gave one.
47pub fn from_env() {
48    if let Ok(code) = std::env::var("ESCOUADE_LANG") {
49        set_ui(Lang::of_code(&code));
50    }
51}
52
53/// The language `initialize` said, when it said one.
54pub fn from_greeting() {
55    let said = escouade_plugin_protocol::greeting().and_then(|g| g.lang.as_deref());
56    if let Some(code) = said {
57        set_ui(Lang::of_code(code));
58    }
59}
60
61/// A text in `lang`: `tr_in!(lang, "français {x}", "English {x}")`.
62#[macro_export]
63macro_rules! tr_in {
64    ($lang:expr, $fr:literal, $en:literal $(,)?) => {
65        match $lang {
66            $crate::i18n::Lang::Fr => format!($fr),
67            $crate::i18n::Lang::En => format!($en),
68        }
69    };
70    ($lang:expr, $fr:literal, $en:literal, $($args:tt)+) => {
71        match $lang {
72            $crate::i18n::Lang::Fr => format!($fr, $($args)+),
73            $crate::i18n::Lang::En => format!($en, $($args)+),
74        }
75    };
76}
77
78/// A text in the interface's language.
79#[macro_export]
80macro_rules! tr {
81    ($fr:literal, $en:literal $(, $($args:tt)+)?) => {
82        $crate::tr_in!($crate::i18n::ui(), $fr, $en $(, $($args)+)?)
83    };
84}