mail-server/crates/common/build.rs
2025-06-25 17:21:19 +02:00

100 lines
3.1 KiB
Rust

use std::collections::HashMap;
use std::env;
use std::fs;
use std::path::Path;
fn main() {
let out_dir = env::var("OUT_DIR").unwrap();
let dest_path = Path::new(&out_dir).join("locales.rs");
// Read the YAML file
let manifest_dir = env::var("CARGO_MANIFEST_DIR").unwrap();
let repo_root = Path::new(&manifest_dir).parent().unwrap().parent().unwrap();
let yaml_path = repo_root.join("resources/locales/i18n.yml");
let yaml_content =
fs::read_to_string(&yaml_path).unwrap_or_else(|_| panic!("Failed to read {yaml_path:?}"));
let locales = parse_yaml(&yaml_content);
let generated_code = generate_locale_code(&locales);
fs::write(&dest_path, generated_code).expect("Failed to write generated locales.");
println!("cargo:rerun-if-changed={}", yaml_path.display());
}
fn parse_yaml(content: &str) -> HashMap<String, HashMap<String, String>> {
let mut result: HashMap<String, HashMap<String, String>> = HashMap::new();
let mut current_key = None;
for line in content.lines() {
if let Some((key, value)) = line.split_once(':') {
let is_translation = key
.as_bytes()
.first()
.is_some_and(|&b| b.is_ascii_whitespace());
let key = key.trim();
if !key.starts_with('#') && !key.is_empty() {
if !is_translation {
current_key = result.entry(key.replace('.', "_")).or_default().into();
} else {
current_key
.as_mut()
.unwrap()
.insert(key.to_string(), value.trim().trim_matches('"').to_string());
}
}
}
}
result
}
fn generate_locale_code(locales: &HashMap<String, HashMap<String, String>>) -> String {
let mut code = String::new();
code.push_str("#[derive(Debug, Clone)]\n");
code.push_str("pub struct Locale {\n");
for key in locales.keys() {
code.push_str(&format!(" pub {}: &'static str,\n", key));
}
code.push_str("}\n\n");
let mut languages = std::collections::HashSet::new();
for translations in locales.values() {
for lang in translations.keys() {
languages.insert(lang.clone());
}
}
for lang in &languages {
code.push_str(&format!(
"pub static {}_LOCALES: Locale = Locale {{\n",
lang.to_uppercase()
));
for (key, translations) in locales {
let value = translations
.get(lang)
.unwrap_or_else(|| panic!("Missing: {}", key));
code.push_str(&format!(" {key}: {value:?},\n"));
}
code.push_str("};\n\n");
}
code.push_str("pub fn locale(name: &str) -> Option<&'static Locale> {\n");
code.push_str(" hashify::tiny_map!(name.as_bytes(),\n");
for lang in &languages {
code.push_str(&format!(
" \"{}\" => &{}_LOCALES,\n",
lang,
lang.to_uppercase()
));
}
code.push_str(" )\n");
code.push_str("}\n");
code
}