actix_cloud/
i18n.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
use std::collections::HashMap;

pub use actix_cloud_codegen::i18n;

/// Get I18n text
///
/// ```no_run
/// use actix_cloud::{i18n::{i18n, Locale},t};
///
/// let mut locale = Locale::new("en-US").add_locale(i18n!("locale"));
///
/// // Get default locale's text
/// t!(locale, "greeting");
/// // With variables
/// t!(locale, "messages.hello", name = "Jason");
/// // Get a special locale's text
/// t!(locale, "greeting", "de");
/// // With locale and variables
/// t!(locale, "messages.hello", "de", name = "Jason");
/// ```
#[macro_export]
macro_rules! t {
    ($l:expr, $key:expr) => {
        $l.translate(&$l.default, $key)
    };

    ($l:expr, $key:expr, $($var_name:tt = $var_val:expr),+) => {
        {
            let mut message = $l.translate(&$l.default, $key);
            $(
                message = message.replace(concat!("%{", stringify!($var_name), "}"), $var_val);
            )+
            message
        }
    };

    ($l:expr, $key:expr, $locale:expr) => {
        $l.translate($locale, $key)
    };

    ($l:expr, $key:expr, $locale:expr, $($var_name:tt = $var_val:expr),+) => {
        {
            let mut message = $l.translate($locale, $key);
            $(
                message = message.replace(concat!("%{", stringify!($var_name), "}"), $var_val);
            )+
            message
        }
    };
}

/// Make map creation easier.
///
/// # Examples
///
/// ```
/// use actix_cloud::map;
/// let val = map!{"key" => "value"};
/// ```
#[macro_export]
macro_rules! map {
    {$($key:expr => $value:expr),+} => {{
        let mut m = std::collections::HashMap::new();
        $(
            m.insert($key, $value);
        )+
        m
    }};
}

#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[derive(Debug)]
pub struct Locale {
    pub locale: HashMap<String, String>,
    pub default: String,
}

impl Locale {
    pub fn new<S: Into<String>>(default: S) -> Self {
        Self {
            locale: HashMap::new(),
            default: default.into(),
        }
    }

    /// Add new locale items.
    pub fn add_locale<S: Into<String>>(mut self, l: HashMap<S, S>) -> Self {
        self.locale
            .extend(l.into_iter().map(|(a, b)| (a.into(), b.into())));
        self
    }

    /// Translate string.
    /// - Fallback to default language if not exist.
    /// - Again fallback to `key` if still not found.
    pub fn translate<S1: AsRef<str>, S2: AsRef<str>>(&self, locale: S1, key: S2) -> String {
        let locale_key = format!("{}.{}", locale.as_ref(), key.as_ref());
        self.locale.get(locale_key.as_str()).map_or_else(
            || {
                if locale.as_ref() == self.default {
                    key.as_ref().to_owned()
                } else {
                    self.translate(&self.default, key)
                }
            },
            ToString::to_string,
        )
    }
}