aux_i18n/
lib.rs

1use std::collections::HashMap;
2use std::env;
3use std::fs;
4use std::fs::File;
5use std::io;
6use std::io::Read;
7use std::path::Path;
8
9use anyhow::anyhow;
10pub use fluent::FluentArgs as Args;
11use fluent::FluentResource;
12use fluent_bundle::bundle::FluentBundle;
13use intl_memoizer::concurrent::IntlLangMemoizer;
14use lazy_static::lazy_static;
15
16lazy_static! {
17    static ref BUNDLES_MAP: HashMap<String, FluentBundle<FluentResource, IntlLangMemoizer>> = {
18        init().unwrap()
19    };
20}
21
22/// 获取 i18n 信息
23pub fn get_message(lang: impl Into<String>, key: &str, args: Option<&Args>) -> Option<String> {
24    if let Some(bundle) = BUNDLES_MAP.get(&lang.into()) {
25        if let Some(msg) = bundle.get_message(key) {
26            if let Some(pattern) = msg.value() {
27                let value = bundle.format_pattern(pattern, args, &mut vec![]);
28                return Some(value.to_string());
29            }
30        }
31    }
32    None
33}
34
35fn init() -> anyhow::Result<HashMap<String, FluentBundle<FluentResource, IntlLangMemoizer>>> {
36    let mut bundles = HashMap::new();
37    let resource = get_available_resource(env::var("i18n_dir").unwrap_or("i18n/".to_owned()))?;
38    for (langid, source) in resource.iter() {
39        let mut bundle = FluentBundle::new_concurrent(vec![langid.parse()?]);
40        bundle.add_resource(FluentResource::try_new(source.clone())
41            .map_err(|e| anyhow!("parse resource error: {:?}", e))?)
42            .map_err(|e| anyhow!("add resource error: {:?}", e))?;
43        bundles.insert(langid.clone(), bundle);
44    }
45    Ok(bundles)
46}
47
48fn get_available_resource<P: AsRef<Path>>(dir: P) -> anyhow::Result<HashMap<String, String>> {
49    let mut result = HashMap::new();
50    let res_dir = fs::read_dir(dir)?;
51    for entry in res_dir {
52        if let Ok(entry) = entry {
53            let path = entry.path();
54            if path.is_dir() {
55                continue;
56            }
57            if let Some(name) = path.file_name() {
58                if let Some(name) = name.to_str() {
59                    if name.starts_with("messages_") && name.ends_with(".ftl") {
60                        let langid = name.trim_start_matches("messages_")
61                            .trim_end_matches(".ftl")
62                            .to_owned();
63                        result.insert(langid, read_file(&path)?);
64                    }
65                }
66            }
67        }
68    }
69    Ok(result)
70}
71
72fn read_file(path: &Path) -> Result<String, io::Error> {
73    let mut f = File::open(path)?;
74    let mut s = String::new();
75    f.read_to_string(&mut s)?;
76    Ok(s)
77}