chuanyue-service/i18n/src/lib.rs
2024-10-31 19:53:30 +08:00

98 lines
3.3 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

extern crate self as i18n;
use std::{collections::HashMap, sync::OnceLock};
use message_ids::MessageId;
use strum::IntoEnumIterator;
pub mod message_ids;
const I18N_FILE: &str = "i18n.csv";
static I18N: OnceLock<HashMap<&'static str, HashMap<&'static str, &'static str>>> = OnceLock::new();
fn init() -> HashMap<&'static str, HashMap<&'static str, &'static str>> {
let mut i18n_map = HashMap::new();
let mut i18n_id_map = HashMap::new();
let mut rdr = csv::Reader::from_path(I18N_FILE).expect("读取多语言文件失败");
let headers = rdr.headers().expect("解析多语言文件失败");
let header_length = headers.len();
for i in 1..header_length {
let lang_id = headers.get(i).unwrap();
i18n_id_map.insert(i, lang_id.to_string());
}
for result in rdr.deserialize() {
let record: Vec<String> = result.expect("解析多语言文件失败");
let column_length = record.len();
let message_id: &'static str = Box::leak(Box::new(record[0].clone()));
for i in 1..column_length {
let lang_id: &'static str = Box::leak(Box::new(i18n_id_map.get(&i).unwrap().clone()));
let message: &'static str = Box::leak(Box::new(record[i].clone()));
i18n_map
.entry(lang_id)
.or_insert_with(HashMap::new)
.insert(message_id, message);
}
}
// 检查多语言文件是否完整
for (lang_id, lang_map) in i18n_map.iter() {
MessageId::iter().for_each(|message_id| {
if !lang_map.contains_key(message_id.as_ref()) {
tracing::error!("多语言文件缺失消息:{},语言:{}", message_id, lang_id);
}
});
}
i18n_map
}
fn init_i18n() -> &'static HashMap<&'static str, HashMap<&'static str, &'static str>> {
I18N.get_or_init(init)
}
/// 获取语言模板
pub fn lang(lang_id: &str, message_id: MessageId) -> &'static str {
init_i18n()
.get(lang_id)
.and_then(|map| map.get(message_id.as_ref()))
.unwrap_or_else(|| &"UNKNOWN")
}
/// 将模板消息转换为最终消息,支持模板占位符
pub fn convert_message_with_params(message_template: &'static str, args: Vec<&str>) -> String {
if message_template.is_empty() {
return String::new();
}
if message_template.contains("{}") {
let message_split_array: Vec<&str> = message_template.split("{}").collect();
let capacity = message_template.len() + args.iter().map(|s| s.len()).sum::<usize>();
let mut message = String::with_capacity(capacity);
message_split_array.iter().zip(args.iter().chain(std::iter::once(&""))).for_each(|(part, arg)| {
message.push_str(part);
message.push_str(arg);
});
message
} else {
String::from(message_template)
}
}
#[macro_export]
macro_rules! message {
// 通过lang id和message id获取消息
($lang_id:expr, $message_id:expr) => {
i18n::lang($lang_id, $message_id)
};
// 通过lang id和message id获取消息并将参数格式化到消息中
($lang_id:expr, $message_id:expr, $($arg:expr),*) => {
{
let message_template: &'static str = i18n::lang($lang_id, $message_id);
let args = vec![$($arg),*];
i18n::convert_message_with_params(message_template, args)
}
};
}