87 lines
2.3 KiB
Rust
87 lines
2.3 KiB
Rust
use rmcp::serde_json;
|
|
use serde::Deserialize;
|
|
use std::collections::HashMap;
|
|
use std::sync::{LazyLock, OnceLock, RwLock};
|
|
|
|
#[derive(Debug, Deserialize)]
|
|
struct Language {
|
|
translations: HashMap<String, String>,
|
|
}
|
|
|
|
static LANGUAGES: OnceLock<HashMap<Locale, Language>> = OnceLock::new();
|
|
static LOCALE_SELECTION: LazyLock<RwLock<Locale>> = LazyLock::new(|| RwLock::new(Locale::DE));
|
|
|
|
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
|
pub enum Locale {
|
|
DE,
|
|
}
|
|
|
|
#[macro_export]
|
|
macro_rules! include_language {
|
|
($file:expr) => {
|
|
serde_json::from_str::<Language>(include_str!($file)).unwrap()
|
|
};
|
|
}
|
|
|
|
fn load_languages() -> &'static HashMap<Locale, Language> {
|
|
LANGUAGES
|
|
.get_or_init(|| HashMap::from([(Locale::DE, include_language!("translations/de.json"))]))
|
|
}
|
|
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```
|
|
/// let formatted = format_dynamically("{...} is cool!".to_string(),
|
|
/// vec!["Rust".to_string()]);
|
|
/// assert_eq!(formatted, "Rust is cool!");
|
|
/// ```
|
|
fn format_dynamically(mut template: String, arguments: Vec<impl Into<String>>) -> String {
|
|
let replaced_str = "{...}";
|
|
|
|
for arg in arguments {
|
|
template = template.replacen(replaced_str, arg.into().as_str(), 1);
|
|
}
|
|
|
|
template
|
|
}
|
|
|
|
pub fn translate(template_name: String, arguments: Vec<impl Into<String>>) -> String {
|
|
let locale: Locale = *LOCALE_SELECTION.read().unwrap();
|
|
let languages = load_languages();
|
|
let translation = languages
|
|
.get(&locale)
|
|
.unwrap()
|
|
.translations
|
|
.get(&template_name)
|
|
.unwrap();
|
|
format_dynamically(translation.clone(), arguments)
|
|
}
|
|
|
|
#[macro_export]
|
|
macro_rules! tlt {
|
|
($template_name:tt) => {
|
|
translate($template_name.to_string(), Vec::<String>::new())
|
|
};
|
|
($template_name:tt, $($args:tt)*) => {
|
|
translate($template_name.to_string(), vec![$($args)*])
|
|
};
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn test_dynamic_formatting() {
|
|
let formatted = format_dynamically("{...} is cool!".to_string(), vec!["Rust".to_string()]);
|
|
assert_eq!(formatted, "Rust is cool!");
|
|
|
|
let formatted = format_dynamically(
|
|
"{...}, {...} and {...} are three consecutive numbers.".to_string(),
|
|
vec!["1".to_string(), "2".to_string(), "3".to_string()],
|
|
);
|
|
assert_eq!(formatted, "1, 2 and 3 are three consecutive numbers.");
|
|
}
|
|
}
|