1#[path = "_shared.rs"]
2pub mod shared;
3
4pub mod ar;
5pub mod ar_ae;
6pub mod ar_sa;
7pub mod bd;
8pub mod be;
9pub mod bg;
10pub mod cl;
11pub mod co;
12pub mod cs;
13pub mod cy;
14pub mod da;
15pub mod de;
16pub mod de_at;
17pub mod ec;
18pub mod eg;
19pub mod el;
20pub mod en;
21pub mod en_au;
22pub mod en_ca;
23pub mod en_gb;
24pub mod en_ng;
25pub mod en_nz;
26pub mod en_sg;
27pub mod en_za;
28pub mod es;
29pub mod et;
30pub mod fi;
31pub mod fr;
32pub mod fr_be;
33pub mod fr_ca;
34pub mod ga;
35pub mod he;
36pub mod hi;
37pub mod hr;
38pub mod hu;
39pub mod id;
40pub mod it;
41pub mod ja;
42pub mod ko;
43pub mod lb;
44pub mod lt;
45pub mod lv;
46pub mod ms;
47pub mod mt;
48pub mod mx;
49pub mod nb;
50pub mod nl;
51pub mod nl_be;
52pub mod pe;
53pub mod pk;
54pub mod pl;
55pub mod pt;
56pub mod pt_br;
57pub mod ro;
58pub mod ru;
59pub mod sk;
60pub mod sl;
61pub mod sr;
62pub mod sv;
63pub mod th;
64pub mod tl;
65pub mod tr;
66pub mod tw;
67pub mod uk;
68pub mod uy;
69pub mod ve;
70pub mod vi;
71pub mod zh;
72
73#[derive(Clone, Copy)]
74pub struct City {
75 pub name: &'static str,
76 pub region: &'static str,
77 pub postal: &'static str,
78 pub lat: f64,
79 pub lon: f64,
80 pub tz: &'static str,
81}
82
83#[derive(Clone, Copy, PartialEq, Eq)]
84pub enum NameOrder {
85 Western,
87 Eastern,
89 DoubleSurname,
91 Patronymic { particle: &'static str },
93 PatronymicMiddle,
95}
96
97#[derive(Clone, Copy)]
98pub struct Locale {
99 pub code: &'static str,
100 pub name_order: NameOrder,
101 pub first_names: &'static [&'static str],
102 pub first_names_common: usize,
105 pub last_names: &'static [&'static str],
106 pub last_names_common: usize,
107 pub domains: &'static [&'static str],
108 pub domains_common: usize,
110 pub companies: &'static [&'static str],
111 pub cities: &'static [City],
112 pub streets: &'static [&'static str],
113 pub native_first_names: Option<&'static [&'static str]>,
114 pub native_last_names: Option<&'static [&'static str]>,
115 pub native_cities: Option<&'static [City]>,
116 pub native_streets: Option<&'static [&'static str]>,
117}
118
119const LOCALE_TABLE: &[(&str, &Locale)] = &[
122 ("en", &en::LOCALE),
123 ("en-gb", &en_gb::LOCALE),
124 ("en-ca", &en_ca::LOCALE),
125 ("en-au", &en_au::LOCALE),
126 ("en-nz", &en_nz::LOCALE),
127 ("en-sg", &en_sg::LOCALE),
128 ("en-za", &en_za::LOCALE),
129 ("en-ng", &en_ng::LOCALE),
130 ("de", &de::LOCALE),
131 ("fr", &fr::LOCALE),
132 ("ja", &ja::LOCALE),
133 ("es", &es::LOCALE),
134 ("pt-br", &pt_br::LOCALE),
135 ("it", &it::LOCALE),
136 ("nl", &nl::LOCALE),
137 ("pl", &pl::LOCALE),
138 ("se", &sv::LOCALE),
139 ("tr", &tr::LOCALE),
140 ("ru", &ru::LOCALE),
141 ("uk", &uk::LOCALE),
142 ("be", &be::LOCALE),
143 ("sr", &sr::LOCALE),
144 ("ar", &ar::LOCALE),
145 ("ro", &ro::LOCALE),
146 ("hr", &hr::LOCALE),
147 ("bg", &bg::LOCALE),
148 ("cs", &cs::LOCALE),
149 ("sk", &sk::LOCALE),
150 ("hu", &hu::LOCALE),
151 ("fi", &fi::LOCALE),
152 ("da", &da::LOCALE),
153 ("no", &nb::LOCALE),
154 ("el", &el::LOCALE),
155 ("pt", &pt::LOCALE),
156 ("mx", &mx::LOCALE),
157 ("cl", &cl::LOCALE),
158 ("co", &co::LOCALE),
159 ("sl", &sl::LOCALE),
160 ("et", &et::LOCALE),
161 ("lt", <::LOCALE),
162 ("lv", &lv::LOCALE),
163 ("ie", &ga::LOCALE),
164 ("pe", &pe::LOCALE),
165 ("uy", &uy::LOCALE),
166 ("hi", &hi::LOCALE),
167 ("vi", &vi::LOCALE),
168 ("zh", &zh::LOCALE),
169 ("ko", &ko::LOCALE),
170 ("id", &id::LOCALE),
171 ("th", &th::LOCALE),
172 ("ms", &ms::LOCALE),
173 ("tl", &tl::LOCALE),
174 ("tw", &tw::LOCALE),
175 ("ve", &ve::LOCALE),
176 ("ec", &ec::LOCALE),
177 ("pk", &pk::LOCALE),
178 ("bd", &bd::LOCALE),
179 ("eg", &eg::LOCALE),
180 ("de-at", &de_at::LOCALE),
181 ("nl-be", &nl_be::LOCALE),
182 ("fr-be", &fr_be::LOCALE),
183 ("fr-ca", &fr_ca::LOCALE),
184 ("cy", &cy::LOCALE),
185 ("mt", &mt::LOCALE),
186 ("lb", &lb::LOCALE),
187 ("he", &he::LOCALE),
188 ("ar-sa", &ar_sa::LOCALE),
189 ("ar-ae", &ar_ae::LOCALE),
190];
191
192pub fn get(code: &str) -> Option<&'static Locale> {
193 LOCALE_TABLE.iter().find(|(c, _)| *c == code).map(|(_, l)| *l)
194}
195
196pub const ALL_CODES: &[&str] = &{
197 const N: usize = LOCALE_TABLE.len();
198 let mut out = [""; N];
199 let mut i = 0;
200 while i < N {
201 out[i] = LOCALE_TABLE[i].0;
202 i += 1;
203 }
204 out
205};
206
207pub fn resolve(codes: &[String]) -> Result<Vec<&'static Locale>, String> {
214 if codes.is_empty() || (codes.len() == 1 && codes[0] == "all") {
215 return Ok(ALL_CODES.iter().filter_map(|c| get(c)).collect());
216 }
217 let has_weights = codes.iter().any(|c| c.contains('='));
218 let mut result = Vec::new();
219 for code in codes {
220 let (name, weight) = if has_weights {
221 if let Some((n, w)) = code.split_once('=') {
222 let w: usize = w.parse().map_err(|_| format!("invalid locale weight: '{code}'"))?;
223 if w == 0 {
224 return Err(format!("locale weight must be > 0: '{code}'"));
225 }
226 (n, w)
227 } else {
228 (code.as_str(), 1)
229 }
230 } else {
231 (code.as_str(), 1)
232 };
233 match get(name) {
234 Some(loc) => {
235 for _ in 0..weight {
236 result.push(loc);
237 }
238 }
239 None => {
240 return Err(format!("unknown locale '{name}'; valid: {}", ALL_CODES.join(", ")))
241 }
242 }
243 }
244 Ok(result)
245}
246
247pub fn resolve_str(s: &str) -> Result<Vec<&'static Locale>, String> {
250 let codes: Vec<String> = s.split(',').map(|c| c.trim().to_string()).collect();
251 resolve(&codes)
252}