/* This file is part of jellything (https://codeberg.org/metamuffin/jellything) which is licensed under the GNU Affero General Public License (version 3); see /COPYING. Copyright (C) 2026 metamuffin */ use std::{borrow::Cow, collections::HashMap, sync::LazyLock}; macro_rules! languages { ($($lang:literal),*) => { #[cfg(feature = "reload")] const LANGUAGES: &[&str] = &[$($lang),*]; #[cfg(not(feature = "reload"))] const LANGUAGES: &[(&str, &str)] = &[$(($lang, include_str!(concat!("../../../locale/", $lang, ".ini")))),*]; }; } languages!("en", "de", "nl", "zh_Hans"); pub static LANG_TABLES: LazyLock>> = LazyLock::new(|| { let mut langs = LANGUAGES .iter() .map(|(k, v)| (*k, parse_ini(v))) .collect::>(); let fallback = langs["en"].clone(); for l in langs.values_mut() { for (k, fv) in &fallback { if !l.contains_key(k) { l.insert(k, fv); } } } langs }); fn parse_ini(source: &str) -> HashMap<&str, &str> { source .lines() .filter_map(|line| { let (key, value) = line.split_once("=")?; Some((key.trim(), value.trim())) }) .collect() } pub fn tr(lang: &str, key: &str) -> Cow<'static, str> { let tr_map = LANG_TABLES.get(&lang).unwrap(); tr_map .get(key) .copied() .map(Cow::Borrowed) .unwrap_or_else(|| format!("MISSING TRANSLATION {:?}", key).into()) } pub fn escape(str: &str) -> String { let mut o = String::with_capacity(str.len()); let mut last = 0; for (index, byte) in str.bytes().enumerate() { if let Some(esc) = match byte { b'<' => Some("<"), b'>' => Some(">"), b'&' => Some("&"), b'"' => Some("""), _ => None, } { o += &str[last..index]; o += esc; last = index + 1; } } o += &str[last..]; o }