use crate::config::Config;
use crate::validation::register_validation_translator;
use ferro_lang::{LangConfig, Translator};
use std::sync::OnceLock;
static TRANSLATOR: OnceLock<Translator> = OnceLock::new();
pub fn init() {
let config = Config::get::<LangConfig>().unwrap_or_else(LangConfig::from_env);
match Translator::load(&config.path, &config.fallback_locale) {
Ok(translator) => {
let _ = TRANSLATOR.set(translator);
register_validation_translator(validation_bridge_fn);
}
Err(e) => {
eprintln!("[ferro::lang] Failed to load translations: {e}");
}
}
}
pub fn t(key: &str, params: &[(&str, &str)]) -> String {
match TRANSLATOR.get() {
Some(translator) => translator.get(&super::locale(), key, params),
None => key.to_string(),
}
}
pub fn trans(key: &str, params: &[(&str, &str)]) -> String {
t(key, params)
}
pub fn choice(key: &str, count: i64, params: &[(&str, &str)]) -> String {
match TRANSLATOR.get() {
Some(translator) => translator.choice(&super::locale(), key, count, params),
None => key.to_string(),
}
}
fn validation_bridge_fn(key: &str, params: &[(&str, &str)]) -> Option<String> {
let translator = TRANSLATOR.get()?;
let locale = super::locale();
Some(translator.get(&locale, key, params))
}
#[cfg(test)]
mod tests {
use super::*;
use crate::validation::TranslatorFn;
#[test]
fn t_returns_key_when_no_translator_loaded() {
let result = t("some.key", &[]);
assert!(!result.is_empty());
}
#[test]
fn trans_is_alias_for_t() {
let key = "alias.test";
assert_eq!(trans(key, &[]), t(key, &[]));
}
#[test]
fn choice_returns_key_when_no_translator_loaded() {
let result = choice("items.count", 5, &[]);
assert!(!result.is_empty());
}
#[test]
fn t_with_params_returns_key_when_no_translator() {
let result = t("app.hello", &[("name", "World")]);
assert!(!result.is_empty());
}
#[test]
fn choice_with_count_returns_key_when_no_translator() {
let result = choice("messages.items", 5, &[]);
assert!(!result.is_empty());
}
#[test]
fn validation_bridge_fn_matches_translator_fn_signature() {
let _f: TranslatorFn = validation_bridge_fn;
}
}