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
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
use backend;
use TokenStream;
/// Initializes the localization system.
///
/// # Arguments
///
/// * **Unnamed arguments** — locale variants. At least one must be provided.
/// Optionally, a custom label can be specified using `=>`. If no label is
/// provided, it defaults to the variant name.
/// * `storage` — whether to generate storage for the current locale. Default to `false`.
/// * `path` — path to the module where the macro is invoked. Used for resolving
/// paths in the generated code. It is recommended to always specify this,
/// otherwise required imports for generated items may need to be added manually.
/// * `default` — the default locale. Defaults to the first locale variant.
/// * `derive` — a list of additional derives applied to the generated `enum Locale`.
/// Defaults to empty.
///
/// # Example with all features
///
/// ```rust
/// init_locale!(
/// En => "English",
/// Ru => "Russian",
/// storage = true,
/// path = crate::locale,
/// default = En,
/// derive = [Deserialize, Serialize],
/// );
/// ```
///
/// # Generated code
///
/// `enum Locale` — core of all system.
///
/// ```rust
/// #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, /* derives from `derive` */)]
/// #[repr(usize)]
/// pub enum Locale { /* provided locale variants */ }
///
/// impl Locale {
/// pub const COUNT: usize = /* number of locale variants */;
/// pub const VARIANTS: [Self; Self::COUNT] = /* array of locale variants */;
/// pub const LABELS: [&'static str; Self::COUNT] = /* array of locale variants labels */;
/// pub const DEFAULT: Self = /* compile-time equivalent of the `Default` trait */;
///
/// // Iterates over pairs of (variant, label)
/// pub fn iter() -> impl Iterator<Item=(Self, &'static str)> { /* ... */ }
///
/// // Iterates over all variants
/// pub fn iter_variants() -> impl Iterator<Item=Self> { /* ... */ }
///
/// // Iterates over all labels
/// pub fn iter_labels() -> impl Iterator<Item=&'static str> { /* ... */ }
///
/// // Converts the locale to `usize`
/// pub const fn to_usize(self) -> usize { /* ... */ }
///
/// // Converts from `usize`. Returns `None` if the value is invalid.
/// pub const fn from_usize(value: usize) -> Option<Self> { /* ... */ }
///
/// // Converts from `usize`. Uses the default value if invalid.
/// pub fn from_usize_or_default(value: usize) -> Self { /* ... */ }
///
/// // Converts the locale to `&str`
/// pub const fn to_str(self) -> &'static str { /* ... */ }
///
/// // Converts from `&str`. Returns `None` if the value is invalid.
/// pub fn from_str(str: &str) -> Option<Self> { /* ... */ }
///
/// // Converts from `&str`. Uses the default value if invalid.
/// pub fn from_str_or_default(str: &str) -> Self { /* ... */ }
///
/// // Converts from `&str`, ignoring ASCII case. Returns `None` if invalid.
/// pub const fn from_caseless_str(str: &str) -> Option<Self> { /* ... */ }
///
/// // Converts from `&str`, ignoring ASCII case. Uses the default value if invalid.
/// pub fn from_caseless_str_or_default(str: &str) -> Self { /* ... */ }
/// }
///
/// impl Default for Locale { /* ... */ }
/// impl core::fmt::Display for Locale { /* ... */ }
/// impl From<Locale> for usize { /* ... */ }
/// impl TryFrom<usize> for Locale { /* ... */ }
/// impl From<Locale> for &str { /* ... */ }
/// impl core::str::FromStr for Locale { /* ... */ }
/// impl TryFrom<&str> for Locale { /* ... */ }
/// ```
///
/// `mod storage` — generated only if `storage = true`.
/// Stores the default locale upon initialization.
/// The current locale is stored as an `AtomicUsize` using `Relaxed` ordering.
///
/// ```rust
/// pub mod storage {
/// // Returns the current locale
/// pub fn get() -> Locale { /* ... */ }
///
/// // Sets the current locale
/// pub fn set(locale: Locale) { /* ... */ }
///
/// // Returns the current locale as `usize`
/// pub fn get_as_usize() -> usize { /* ... */ }
///
/// // Sets the current locale from `usize`
/// pub fn set_from_usize(value: usize) -> Result<(), &'static str> { /* ... */ }
///
/// // Sets the current locale from `usize`
/// // If the value is invalid, the locale falls back to the default.
/// pub fn set_from_usize_or_default(value: usize) { /* ... */ }
///
/// // Returns the current locale as `&str`.
/// pub fn get_as_str() -> &'static str { /* ... */ }
///
/// // Sets the current locale from `&str`.
/// pub fn set_from_str(str: &str) -> Result<(), &'static str> { /* ... */ }
///
/// // Sets the current locale from `&str`.
/// // If the value is invalid, the locale falls back to the default.
/// pub fn set_from_str_or_default(str: &str) { /* ... */ }
///
/// // Sets the current locale from `&str`, ignoring ASCII case.
/// pub fn set_from_caseless_str(str: &str) -> Result<(), &'static str> { /* ... */ }
///
/// // Sets the current locale from `&str`, ignoring ASCII case.
/// // If the value is invalid, the locale falls back to the default.
/// pub fn set_from_caseless_str_or_default(str: &str) { /* ... */ }
///
/// // Resets the current locale to the default
/// pub fn reset() { /* ... */ }
/// }
/// ```
///
/// `expression!` — a macro for defining localized expressions.
///
/// ```rust
/// expression!(HELLO => {
/// En: "Hello",
/// Ru: "Привет",
/// });
/// ```
///
/// The expression can be any compile-time type, including functions.
/// For any type other than `&str`, the type must be specified explicitly.
///
/// ```rust
/// expression!(HELLO: fn(&str) -> String => {
/// En: |name: &str| format!("Hello, {name}!"),
/// Ru: |name: &str| format!("Привет, {name}!"),
/// });
/// ```
///
/// `expressions!` — similar to `expression!`, but allows defining multiple expressions at once.
///
/// ```rust
/// expressions!(
/// HELLO => {
/// En: "Hello",
/// Ru: "Привет",
/// },
/// HELLO_WITH_NAME: fn(&str) -> String => {
/// En: |name: &str| format!("Hello, {name}!"),
/// Ru: |name: &str| format!("Привет, {name}!"),
/// },
/// );
/// ```
///
/// `localize!` — a macro for retrieving a localized value.
///
/// If `storage = true` is enabled, the macro can be used without explicitly
/// specifying a locale — the current locale will be used automatically.
///
/// ```rust
/// localize!(HELLO);
/// ```
///
/// A locale can also be provided manually.
///
/// ```rust
/// localize!(HELLO, Locale::En);
/// ```
///
/// If the expression is callable, it can be invoked with arguments.
///
/// ```rust
/// let name = "Ivan";
/// localize!(HELLO_WITH_NAME as (name));
/// ```