rinova-proxy-sdk 1.0.0

Proxy subscription to Clash config converter — SDK
Documentation
use std::collections::HashMap;
use std::sync::OnceLock;

const EN_JSON: &str = include_str!("../locales/en.json");
const ZH_JSON: &str = include_str!("../locales/zh.json");

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Lang {
    En,
    Zh,
}

static LANG: OnceLock<Lang> = OnceLock::new();
static EN: OnceLock<HashMap<String, String>> = OnceLock::new();
static ZH: OnceLock<HashMap<String, String>> = OnceLock::new();

fn detect_lang() -> Lang {
    let lang = std::env::var("LANG")
        .or_else(|_| std::env::var("LC_ALL"))
        .unwrap_or_default();
    if lang.starts_with("zh") {
        Lang::Zh
    } else {
        Lang::En
    }
}

fn load_locale(json: &str) -> HashMap<String, String> {
    serde_json::from_str(json).unwrap_or_default()
}

pub fn get_lang() -> Lang {
    *LANG.get_or_init(detect_lang)
}

pub fn t(key: &str, params: &[(&str, &str)]) -> String {
    t_with_fallback(key, params, None)
}

pub fn t_with_fallback(key: &str, params: &[(&str, &str)], fallback: Option<&str>) -> String {
    let en = EN.get_or_init(|| load_locale(EN_JSON));
    let zh = ZH.get_or_init(|| load_locale(ZH_JSON));

    let mut msg = match get_lang() {
        Lang::Zh => zh.get(key).or_else(|| en.get(key)),
        Lang::En => en.get(key),
    }
    .cloned()
    .or_else(|| fallback.map(str::to_string))
    .unwrap_or_else(|| key.to_string());

    for (k, v) in params {
        msg = msg.replace(&format!("{{{k}}}"), v);
    }

    msg
}

pub fn t_simple(key: &str) -> String {
    t(key, &[])
}