1use lazy_static::lazy_static;
2use serde_json::Value;
3use std::sync::Arc;
4use std::{collections::HashMap, env};
5use string_template::Template;
6use structs::I18n;
7
8pub use structs::TranslationConfig;
9
10mod structs;
11
12static RESOURCES_KEY: &'static str = "INTL_RS_RESOURCES";
13
14static DEFAULT_LANGUAGE: &'static str = "INTL_RS_LANG";
15
16lazy_static! {
17 pub static ref I18N: Arc<I18n> = {
18 let resources_path = env::var(RESOURCES_KEY).unwrap_or("src/i18n".to_owned());
19 let default_language = env::var(DEFAULT_LANGUAGE).unwrap_or("en".to_owned());
20 let inner = I18n::init(resources_path, default_language);
21 Arc::new(inner)
22 };
23}
24
25pub fn format_message<S: Into<String>>(key: S, config: Option<&TranslationConfig>) -> String {
26 let key = key.into();
27 let default_config = TranslationConfig::default();
28 let TranslationConfig {
29 accept_language,
30 default_message,
31 args,
32 } = config.unwrap_or(&default_config);
33 let common_languages = accept_language::intersection(
34 accept_language.as_ref().unwrap_or(&I18N.default_language),
35 I18N.supported_languages.iter().map(|s| s as &str).collect(),
36 );
37 let language = common_languages
38 .first()
39 .expect("No supported language can be found");
40 let configs: &Value = &I18N.inner[language];
41
42 let template_string = match key
43 .split('.')
44 .fold(configs, |result: &Value, k| &result[&k])
45 {
46 Value::Null => default_message.clone(),
47 message => message.as_str().map(|other_str| other_str.to_string()),
48 }
49 .unwrap_or(key.to_string());
50 let template = Template::new(&template_string);
51 template.render(
52 &args
53 .as_ref()
54 .unwrap_or(&HashMap::new())
55 .iter()
56 .map(|(a, b)| (a.as_str(), b.as_str()))
57 .collect(),
58 )
59}
60
61#[macro_export]
62macro_rules! t {
63 ($key:expr) => {
64 $crate::format_message($key, None)
65 };
66 ($key:expr,accept_language:$accept_language:expr) => {
67 $crate::format_message(
68 $key,
69 Some(&$crate::TranslationConfig {
70 accept_language: Some($accept_language.into()),
71 ..Default::default()
72 }),
73 )
74 };
75 ($key:expr,accept_language:$accept_language:expr,args:$args:expr) => {
76 $crate::format_message(
77 $key,
78 Some(&$crate::TranslationConfig {
79 accept_language: Some($accept_language.into()),
80 args: Some($args),
81 ..Default::default()
82 }),
83 )
84 };
85 ($key:expr,config:$config:expr) => {
86 $crate::format_message($key, Some($config))
87 };
88}