pub mod error;
pub mod loader;
pub use error::LangError;
use std::sync::OnceLock;
use crate::loader::FileLoader;
static INIT_RESULT: OnceLock<Result<(), LangError>> = OnceLock::new();
pub fn load_translations(base_dir: &str) -> Result<(), LangError> {
let result = INIT_RESULT.get_or_init(|| {
let loader = FileLoader::new(base_dir);
let translations = loader.scan_and_load_all()?;
rat_embed_lang::register_translations(translations);
let lang = rat_embed_lang::get_language_from_env();
rat_embed_lang::set_language(&lang);
println!("多语言系统加载完成,当前语言: {}", lang);
Ok(())
});
result.clone()
}
#[deprecated(note = "使用 load_translations 替代")]
pub fn init(base_dir: &str) -> Result<(), LangError> {
load_translations(base_dir)
}
pub fn t(key: &str) -> String {
rat_embed_lang::t(key)
}
pub fn set_language(lang: &str) -> Result<(), LangError> {
rat_embed_lang::set_language(lang);
Ok(())
}
pub fn current_language() -> String {
rat_embed_lang::current_language()
}
pub fn has_translation(key: &str) -> bool {
rat_embed_lang::has_translation(key)
}
pub fn get_all_keys() -> Vec<String> {
rat_embed_lang::get_all_keys()
}
pub fn get_supported_languages(key: &str) -> Vec<String> {
rat_embed_lang::get_supported_languages(key)
}
pub fn tf(key: &str, args: &[(&str, &str)]) -> String {
rat_embed_lang::tf(key, args)
}
pub fn tf_with_lang(key: &str, lang: &str, args: &[(&str, &str)]) -> String {
rat_embed_lang::tf_with_lang(key, lang, args)
}
pub fn reload(base_dir: &str) -> Result<(), LangError> {
rat_embed_lang::clear_translations();
let loader = FileLoader::new(base_dir);
let translations = loader.scan_and_load_all()?;
rat_embed_lang::register_translations(translations);
println!("语言文件重新加载完成");
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
use std::fs;
#[test]
fn test_basic_functionality() {
let _ = fs::remove_dir_all("test_lang");
fs::create_dir_all("test_lang/common").unwrap();
fs::write("test_lang/common/zh_CN.toml", r#"
welcome = "欢迎"
buttons.save = "保存"
"#).unwrap();
fs::write("test_lang/common/en_US.toml", r#"
welcome = "Welcome"
buttons.save = "Save"
"#).unwrap();
fs::write("test_lang/ui.toml", r#"
[zh_CN]
title = "标题"
[en_US]
title = "Title"
"#).unwrap();
let loader = FileLoader::new("test_lang");
let translations = loader.scan_and_load_all().unwrap();
rat_embed_lang::clear_translations();
rat_embed_lang::register_translations(translations);
let welcome = t("common.welcome");
set_language("zh-CN").unwrap();
let welcome_zh = t("common.welcome");
assert_eq!(welcome_zh, "欢迎");
set_language("en-US").unwrap();
let welcome_en = t("common.welcome");
assert_eq!(welcome_en, "Welcome");
let title = t("ui.title");
assert!(!title.is_empty());
assert!(title == "标题" || title == "Title");
fs::remove_dir_all("test_lang").unwrap();
}
#[test]
fn test_file_loader() {
let _ = fs::remove_dir_all("test_lang2");
fs::create_dir_all("test_lang2/module1").unwrap();
fs::write("test_lang2/module1/zh_CN.toml", "test = \"测试\"").unwrap();
fs::write("test_lang2/module1/en_US.toml", "test = \"Test\"").unwrap();
let loader = FileLoader::new("test_lang2");
let translations = loader.scan_and_load_all().unwrap();
assert!(translations.contains_key("module1.test"));
let lang_map = &translations["module1.test"];
assert!(lang_map.contains_key("zh-CN"));
assert!(lang_map.contains_key("en-US"));
assert_eq!(lang_map["zh-CN"], "测试");
assert_eq!(lang_map["en-US"], "Test");
fs::remove_dir_all("test_lang2").unwrap();
}
}