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
22pub 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}