use std::{collections::HashMap, fs::{self, File}, io::BufReader, process::Command}; use derive_more::From; use rocket_dyn_templates::tera::{self, Value}; use gettext::Catalog; #[derive(From, Debug)] pub enum LoadCatalogsError { Io(std::io::Error), Parse(gettext::Error), MissingDefaultLanguage, } const DEFAULT: &str = "ja"; pub fn load_catalogs() -> Result, LoadCatalogsError> { let mut catalogs = HashMap::new(); for file in fs::read_dir("i18n")? { let file = file?; let path = file.path(); if !file.file_type()?.is_file() || !path.extension().map(|extension| extension.eq("po")).unwrap_or(false) { continue; } let language_code = path .file_stem() .expect("Invalid translation file name") .to_string_lossy() .to_string(); let po_file_path = path; let mo_file_path = format!("i18n/{}.mo", language_code); Command::new("msgfmt") .arg(&po_file_path) .arg("-o") .arg(&mo_file_path) .output()?; catalogs.insert(language_code, Catalog::parse(BufReader::new(File::open(mo_file_path)?))?); } if !catalogs.contains_key(DEFAULT) { return Err(LoadCatalogsError::MissingDefaultLanguage); } Ok(catalogs) } pub fn i18n_filter(value: &Value, _args: &HashMap, catalogs: &HashMap) -> tera::Result { let key = value.as_str().ok_or_else(|| { tera::Error::msg("The translation key must be a string") })?; let translation = catalogs .get(DEFAULT) .expect("Missing catalog") .gettext(key); Ok(Value::String(translation.to_owned())) }