use serde::Deserialize;
use std::sync::LazyLock;
#[derive(Debug, Clone, Deserialize)]
pub struct LangConfig {
#[serde(default)]
pub intent_phrases: Vec<String>,
#[serde(default)]
pub action_verbs: Vec<String>,
#[serde(default)]
pub line_start_re: String,
#[serde(default)]
pub work_announcement_re: String,
#[serde(default)]
pub completion_claims: Vec<String>,
#[serde(default)]
pub executed_framings: Vec<String>,
#[serde(default)]
pub generic_intent_re: String,
#[serde(default)]
pub intent_verb_exclusions: Vec<String>,
#[serde(default)]
pub plan_announcement_re: String,
#[serde(default)]
pub participle_object_re: String,
#[serde(default)]
pub announcement_tail_words: Vec<String>,
#[serde(default)]
pub tool_use_markers: Vec<String>,
#[serde(default)]
pub tool_nouns: Vec<String>,
#[serde(default)]
pub tool_name_determiners: Vec<String>,
#[serde(default)]
pub gerund_re: String,
#[serde(default)]
pub trailing_colon_re: String,
#[serde(default)]
pub now_imperative_re: String,
#[serde(default)]
pub numbered_steps_re: String,
#[serde(default)]
pub past_tense_standalone_re: String,
#[serde(default)]
pub path_re: String,
#[serde(default)]
pub ext_re: String,
#[serde(default)]
pub backtick_code_re: String,
#[serde(default)]
pub media_delivery_phrases: Vec<String>,
#[serde(default)]
pub media_context_words: Vec<String>,
#[serde(default)]
pub file_delivery_phrases: Vec<String>,
#[serde(default)]
pub file_context_words: Vec<String>,
}
const EN_TOML: &str = include_str!("en.toml");
const RU_TOML: &str = include_str!("ru.toml");
const AR_TOML: &str = include_str!("ar.toml");
const ZH_TOML: &str = include_str!("zh.toml");
const ES_TOML: &str = include_str!("es.toml");
const PT_TOML: &str = include_str!("pt.toml");
const FR_TOML: &str = include_str!("fr.toml");
const ID_TOML: &str = include_str!("id.toml");
pub(crate) static LANG_EN: LazyLock<LangConfig> =
LazyLock::new(|| toml::from_str(EN_TOML).expect("BUG: en.toml failed to parse at runtime"));
pub(crate) static LANG_RU: LazyLock<LangConfig> =
LazyLock::new(|| toml::from_str(RU_TOML).expect("BUG: ru.toml failed to parse at runtime"));
pub(crate) static LANG_AR: LazyLock<LangConfig> =
LazyLock::new(|| toml::from_str(AR_TOML).expect("BUG: ar.toml failed to parse at runtime"));
pub(crate) static LANG_ZH: LazyLock<LangConfig> =
LazyLock::new(|| toml::from_str(ZH_TOML).expect("BUG: zh.toml failed to parse at runtime"));
pub(crate) static LANG_ES: LazyLock<LangConfig> =
LazyLock::new(|| toml::from_str(ES_TOML).expect("BUG: es.toml failed to parse at runtime"));
pub(crate) static LANG_PT: LazyLock<LangConfig> =
LazyLock::new(|| toml::from_str(PT_TOML).expect("BUG: pt.toml failed to parse at runtime"));
pub(crate) static LANG_FR: LazyLock<LangConfig> =
LazyLock::new(|| toml::from_str(FR_TOML).expect("BUG: fr.toml failed to parse at runtime"));
pub(crate) static LANG_ID: LazyLock<LangConfig> =
LazyLock::new(|| toml::from_str(ID_TOML).expect("BUG: id.toml failed to parse at runtime"));
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Lang {
En,
Ru,
Ar,
Zh,
Es,
Pt,
Fr,
Id,
}
impl Lang {
pub const ALL: [Lang; 8] = [
Lang::En,
Lang::Ru,
Lang::Ar,
Lang::Zh,
Lang::Es,
Lang::Pt,
Lang::Fr,
Lang::Id,
];
pub fn code(self) -> &'static str {
match self {
Lang::En => "en",
Lang::Ru => "ru",
Lang::Ar => "ar",
Lang::Zh => "zh",
Lang::Es => "es",
Lang::Pt => "pt",
Lang::Fr => "fr",
Lang::Id => "id",
}
}
pub fn pack(self) -> &'static LangConfig {
match self {
Lang::En => &LANG_EN,
Lang::Ru => &LANG_RU,
Lang::Ar => &LANG_AR,
Lang::Zh => &LANG_ZH,
Lang::Es => &LANG_ES,
Lang::Pt => &LANG_PT,
Lang::Fr => &LANG_FR,
Lang::Id => &LANG_ID,
}
}
}
pub fn all_langs() -> [&'static LangConfig; 8] {
Lang::ALL.map(Lang::pack)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn every_lang_resolves_to_its_own_pack() {
let codes: Vec<&str> = Lang::ALL.iter().map(|lang| lang.code()).collect();
let unique: std::collections::HashSet<&&str> = codes.iter().collect();
assert_eq!(unique.len(), codes.len(), "two languages share a code");
let packs: Vec<*const LangConfig> = Lang::ALL
.iter()
.map(|lang| lang.pack() as *const LangConfig)
.collect();
let unique_packs: std::collections::HashSet<*const LangConfig> =
packs.iter().copied().collect();
assert_eq!(
unique_packs.len(),
packs.len(),
"two languages resolve to the same pack"
);
}
#[test]
fn all_langs_matches_the_registry_order() {
let listed = all_langs();
assert_eq!(listed.len(), Lang::ALL.len());
for (lang, pack) in Lang::ALL.iter().zip(listed) {
assert!(std::ptr::eq(pack, lang.pack()));
}
}
}