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
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
// locale-to-unicode-flag.rs
//
// Copyright 2022 nee <nee-git@patchouli.garden>
// SPDX-License-Identifier: AGPL-3.0-or-later
use anyhow::{bail, Result};
const START_UNICODE: u32 = 0x1f1e6;
const START_ASCII: u32 = 65; // A
const END_ASCII: u32 = 91; // Z+1
// converts a locale string to a flag sequence
// Example: es_CL.UTF-8 -> ๐จ๐ฑ
// C.UTF-8 returns a c locale Error
// Locales that aren't formatted in LA_RE format returns an error
// case does not matter
pub fn locale_str_to_flag_sequence(locale_str: String) -> Result<String> {
let locale_str = locale_str.to_uppercase();
if locale_str.len() >= 5 && locale_str.get(2..3) == Some("_") {
let location = &locale_str[3..5];
region_str_to_flag_sequence(location.to_string())
} else if locale_str.starts_with("C.") || locale_str == "C" {
bail!("C locale")
} else {
bail!("invalid locale format, no region")
}
}
// converts a 2char long region string to unicode flag sequence
// Example VN -> ๐ป๐ณ
pub fn region_str_to_flag_sequence(location: String) -> Result<String> {
let upper = location.to_uppercase();
let chars = upper.chars();
if upper.len() < 2 {
bail!("not a valid region, must be 2 characters long")
}
let mut failure: bool = false;
let result = Ok(chars
.into_iter()
.map(|c| {
let ascii = c as u32;
if !(START_ASCII..END_ASCII).contains(&ascii) {
// return Err("not a valid region, must only contain A-Z")
failure = true;
return '1';
}
std::char::from_u32(START_UNICODE + (ascii - START_ASCII)).unwrap_or_else(|| {
failure = true;
'2'
})
})
.collect());
if failure {
bail!("failed to convert ascii to unicode")
} else {
result
}
}
#[cfg(test)]
mod test {
use super::*;
fn check(a: &str, b: &str) {
assert_eq!(
locale_str_to_flag_sequence(a.to_string()).unwrap(),
b.to_string()
)
}
fn check_r(a: &str, b: &str) {
assert_eq!(
region_str_to_flag_sequence(a.to_string()).unwrap(),
b.to_string()
)
}
#[test]
fn it_works() {
assert_eq!(
locale_str_to_flag_sequence("C.UTF-8".to_string()).ok(),
None
);
check("cs_CZ", "๐จ๐ฟ");
check("de_DE", "๐ฉ๐ช");
check("de_DE.UTF-8", "๐ฉ๐ช");
check("en_AU", "๐ฆ๐บ");
check("en_AU.UTF-8", "๐ฆ๐บ");
check("en_CA", "๐จ๐ฆ");
check("en_GB", "๐ฌ๐ง");
check("en_GB.UTF-8", "๐ฌ๐ง");
check("en_IE", "๐ฎ๐ช");
check("en_US", "๐บ๐ธ");
check("en_US.UTF-8", "๐บ๐ธ");
check("es_CL.UTF-8", "๐จ๐ฑ");
check("es_ES.UTF-8", "๐ช๐ธ");
check("fr_FR", "๐ซ๐ท");
check("fr_FR.UTF-8", "๐ซ๐ท");
check("it_IT.UTF-8", "๐ฎ๐น");
check("pl_PL", "๐ต๐ฑ");
check("pl_PL.UTF-8", "๐ต๐ฑ");
check("pt_BR", "๐ง๐ท");
check("pt_BR.UTF-8", "๐ง๐ท");
check_r("AC", "๐ฆ๐จ"); // Ascension Island
check_r("AD", "๐ฆ๐ฉ"); // Andorra
check_r("AE", "๐ฆ๐ช"); // United Arab Emirates
check_r("AF", "๐ฆ๐ซ"); // Afghanistan
check_r("AG", "๐ฆ๐ฌ"); // Antigua & Barbuda
check_r("AI", "๐ฆ๐ฎ"); // Anguilla
check_r("AL", "๐ฆ๐ฑ"); // Albania
check_r("AM", "๐ฆ๐ฒ"); // Armenia
check_r("AO", "๐ฆ๐ด"); // Angola
check_r("AQ", "๐ฆ๐ถ"); // Antarctica
check_r("AR", "๐ฆ๐ท"); // Argentina
check_r("AS", "๐ฆ๐ธ"); // American Samoa
check_r("AT", "๐ฆ๐น"); // Austria
check_r("AU", "๐ฆ๐บ"); // Australia
check_r("AW", "๐ฆ๐ผ"); // Aruba
check_r("AX", "๐ฆ๐ฝ"); // ร
land Islands
check_r("AZ", "๐ฆ๐ฟ"); // Azerbaijan
check_r("BA", "๐ง๐ฆ"); // Bosnia & Herzegovina
check_r("BB", "๐ง๐ง"); // Barbados
check_r("BD", "๐ง๐ฉ"); // Bangladesh
check_r("BE", "๐ง๐ช"); // Belgium
check_r("BF", "๐ง๐ซ"); // Burkina Faso
check_r("BG", "๐ง๐ฌ"); // Bulgaria
check_r("BH", "๐ง๐ญ"); // Bahrain
check_r("BI", "๐ง๐ฎ"); // Burundi
check_r("BJ", "๐ง๐ฏ"); // Benin
check_r("BL", "๐ง๐ฑ"); // St. Barthรฉlemy
check_r("BM", "๐ง๐ฒ"); // Bermuda
check_r("BN", "๐ง๐ณ"); // Brunei
check_r("BO", "๐ง๐ด"); // Bolivia
check_r("BQ", "๐ง๐ถ"); // Caribbean Netherlands
check_r("BR", "๐ง๐ท"); // Brazil
check_r("BS", "๐ง๐ธ"); // Bahamas
check_r("BT", "๐ง๐น"); // Bhutan
check_r("BV", "๐ง๐ป"); // Bouvet Island
check_r("BW", "๐ง๐ผ"); // Botswana
check_r("BY", "๐ง๐พ"); // Belarus
check_r("BZ", "๐ง๐ฟ"); // Belize
check_r("CA", "๐จ๐ฆ"); // Canada
check_r("CC", "๐จ๐จ"); // Cocos (Keeling) Islands
check_r("CD", "๐จ๐ฉ"); // Congo - Kinshasa
check_r("CF", "๐จ๐ซ"); // Central African Republic
check_r("CG", "๐จ๐ฌ"); // Congo - Brazzaville
check_r("CH", "๐จ๐ญ"); // Switzerland
check_r("CI", "๐จ๐ฎ"); // Cรดte d'Ivoire
check_r("CK", "๐จ๐ฐ"); // Cook Islands
check_r("CL", "๐จ๐ฑ"); // Chile
check_r("CM", "๐จ๐ฒ"); // Cameroon
check_r("CN", "๐จ๐ณ"); // China
check_r("CO", "๐จ๐ด"); // Colombia
check_r("CP", "๐จ๐ต"); // Clipperton Island
check_r("CR", "๐จ๐ท"); // Costa Rica
check_r("CU", "๐จ๐บ"); // Cuba
check_r("CV", "๐จ๐ป"); // Cape Verde
check_r("CW", "๐จ๐ผ"); // Curaรงao
check_r("CX", "๐จ๐ฝ"); // Christmas Island
check_r("CY", "๐จ๐พ"); // Cyprus
check_r("CZ", "๐จ๐ฟ"); // Czechia
check_r("DE", "๐ฉ๐ช"); // Germany
check_r("DG", "๐ฉ๐ฌ"); // Diego Garcia
check_r("DJ", "๐ฉ๐ฏ"); // Djibouti
check_r("DK", "๐ฉ๐ฐ"); // Denmark
check_r("DM", "๐ฉ๐ฒ"); // Dominica
check_r("DO", "๐ฉ๐ด"); // Dominican Republic
check_r("DZ", "๐ฉ๐ฟ"); // Algeria
check_r("EA", "๐ช๐ฆ"); // Ceuta & Melilla
check_r("EC", "๐ช๐จ"); // Ecuador
check_r("EE", "๐ช๐ช"); // Estonia
check_r("EG", "๐ช๐ฌ"); // Egypt
check_r("EH", "๐ช๐ญ"); // Western Sahara
check_r("ER", "๐ช๐ท"); // Eritrea
check_r("ES", "๐ช๐ธ"); // Spain
check_r("ET", "๐ช๐น"); // Ethiopia
check_r("EU", "๐ช๐บ"); // European Union
check_r("FI", "๐ซ๐ฎ"); // Finland
check_r("FJ", "๐ซ๐ฏ"); // Fiji
check_r("FK", "๐ซ๐ฐ"); // Falkland Islands
check_r("FM", "๐ซ๐ฒ"); // Micronesia
check_r("FO", "๐ซ๐ด"); // Faroe Islands
check_r("FR", "๐ซ๐ท"); // France
check_r("GA", "๐ฌ๐ฆ"); // Gabon
check_r("GB", "๐ฌ๐ง"); // United Kingdom
check_r("GD", "๐ฌ๐ฉ"); // Grenada
check_r("GE", "๐ฌ๐ช"); // Georgia
check_r("GF", "๐ฌ๐ซ"); // French Guiana
check_r("GG", "๐ฌ๐ฌ"); // Guernsey
check_r("GH", "๐ฌ๐ญ"); // Ghana
check_r("GI", "๐ฌ๐ฎ"); // Gibraltar
check_r("GL", "๐ฌ๐ฑ"); // Greenland
check_r("GM", "๐ฌ๐ฒ"); // Gambia
check_r("GN", "๐ฌ๐ณ"); // Guinea
check_r("GP", "๐ฌ๐ต"); // Guadeloupe
check_r("GQ", "๐ฌ๐ถ"); // Equatorial Guinea
check_r("GR", "๐ฌ๐ท"); // Greece
check_r("GS", "๐ฌ๐ธ"); // South Georgia & South Sandwich Islands
check_r("GT", "๐ฌ๐น"); // Guatemala
check_r("GU", "๐ฌ๐บ"); // Guam
check_r("GW", "๐ฌ๐ผ"); // Guinea-Bissau
check_r("GY", "๐ฌ๐พ"); // Guyana
check_r("HK", "๐ญ๐ฐ"); // Hong Kong SAR China
check_r("HM", "๐ญ๐ฒ"); // Heard & McDonald Islands
check_r("HN", "๐ญ๐ณ"); // Honduras
check_r("HR", "๐ญ๐ท"); // Croatia
check_r("HT", "๐ญ๐น"); // Haiti
check_r("HU", "๐ญ๐บ"); // Hungary
check_r("IC", "๐ฎ๐จ"); // Canary Islands
check_r("ID", "๐ฎ๐ฉ"); // Indonesia
check_r("IE", "๐ฎ๐ช"); // Ireland
check_r("IL", "๐ฎ๐ฑ"); // Israel
check_r("IM", "๐ฎ๐ฒ"); // Isle of Man
check_r("IN", "๐ฎ๐ณ"); // India
check_r("IO", "๐ฎ๐ด"); // British Indian Ocean Territory
check_r("IQ", "๐ฎ๐ถ"); // Iraq
check_r("IR", "๐ฎ๐ท"); // Iran
check_r("IS", "๐ฎ๐ธ"); // Iceland
check_r("IT", "๐ฎ๐น"); // Italy
check_r("JE", "๐ฏ๐ช"); // Jersey
check_r("JM", "๐ฏ๐ฒ"); // Jamaica
check_r("JO", "๐ฏ๐ด"); // Jordan
check_r("JP", "๐ฏ๐ต"); // Japan
check_r("KE", "๐ฐ๐ช"); // Kenya
check_r("KG", "๐ฐ๐ฌ"); // Kyrgyzstan
check_r("KH", "๐ฐ๐ญ"); // Cambodia
check_r("KI", "๐ฐ๐ฎ"); // Kiribati
check_r("KM", "๐ฐ๐ฒ"); // Comoros
check_r("KN", "๐ฐ๐ณ"); // St. Kitts & Nevis
check_r("KP", "๐ฐ๐ต"); // North Korea
check_r("KR", "๐ฐ๐ท"); // South Korea
check_r("KW", "๐ฐ๐ผ"); // Kuwait
check_r("KY", "๐ฐ๐พ"); // Cayman Islands
check_r("KZ", "๐ฐ๐ฟ"); // Kazakhstan
check_r("LA", "๐ฑ๐ฆ"); // Laos
check_r("LB", "๐ฑ๐ง"); // Lebanon
check_r("LC", "๐ฑ๐จ"); // St. Lucia
check_r("LI", "๐ฑ๐ฎ"); // Liechtenstein
check_r("LK", "๐ฑ๐ฐ"); // Sri Lanka
check_r("LR", "๐ฑ๐ท"); // Liberia
check_r("LS", "๐ฑ๐ธ"); // Lesotho
check_r("LT", "๐ฑ๐น"); // Lithuania
check_r("LU", "๐ฑ๐บ"); // Luxembourg
check_r("LV", "๐ฑ๐ป"); // Latvia
check_r("LY", "๐ฑ๐พ"); // Libya
check_r("MA", "๐ฒ๐ฆ"); // Morocco
check_r("MC", "๐ฒ๐จ"); // Monaco
check_r("MD", "๐ฒ๐ฉ"); // Moldova
check_r("ME", "๐ฒ๐ช"); // Montenegro
check_r("MF", "๐ฒ๐ซ"); // St. Martin
check_r("MG", "๐ฒ๐ฌ"); // Madagascar
check_r("MH", "๐ฒ๐ญ"); // Marshall Islands
check_r("MK", "๐ฒ๐ฐ"); // North Macedonia
check_r("ML", "๐ฒ๐ฑ"); // Mali
check_r("MM", "๐ฒ๐ฒ"); // Myanmar (Burma)
check_r("MN", "๐ฒ๐ณ"); // Mongolia
check_r("MO", "๐ฒ๐ด"); // Macao SAR China
check_r("MP", "๐ฒ๐ต"); // Northern Mariana Islands
check_r("MQ", "๐ฒ๐ถ"); // Martinique
check_r("MR", "๐ฒ๐ท"); // Mauritania
check_r("MS", "๐ฒ๐ธ"); // Montserrat
check_r("MT", "๐ฒ๐น"); // Malta
check_r("MU", "๐ฒ๐บ"); // Mauritius
check_r("MV", "๐ฒ๐ป"); // Maldives
check_r("MW", "๐ฒ๐ผ"); // Malawi
check_r("MX", "๐ฒ๐ฝ"); // Mexico
check_r("MY", "๐ฒ๐พ"); // Malaysia
check_r("MZ", "๐ฒ๐ฟ"); // Mozambique
check_r("NA", "๐ณ๐ฆ"); // Namibia
check_r("NC", "๐ณ๐จ"); // New Caledonia
check_r("NE", "๐ณ๐ช"); // Niger
check_r("NF", "๐ณ๐ซ"); // Norfolk Island
check_r("NG", "๐ณ๐ฌ"); // Nigeria
check_r("NI", "๐ณ๐ฎ"); // Nicaragua
check_r("NL", "๐ณ๐ฑ"); // Netherlands
check_r("NO", "๐ณ๐ด"); // Norway
check_r("NP", "๐ณ๐ต"); // Nepal
check_r("NR", "๐ณ๐ท"); // Nauru
check_r("NU", "๐ณ๐บ"); // Niue
check_r("NZ", "๐ณ๐ฟ"); // New Zealand
check_r("OM", "๐ด๐ฒ"); // Oman
check_r("PA", "๐ต๐ฆ"); // Panama
check_r("PE", "๐ต๐ช"); // Peru
check_r("PF", "๐ต๐ซ"); // French Polynesia
check_r("PG", "๐ต๐ฌ"); // Papua New Guinea
check_r("PH", "๐ต๐ญ"); // Philippines
check_r("PK", "๐ต๐ฐ"); // Pakistan
check_r("PL", "๐ต๐ฑ"); // Poland
check_r("PM", "๐ต๐ฒ"); // St. Pierre & Miquelon
check_r("PN", "๐ต๐ณ"); // Pitcairn Islands
check_r("PR", "๐ต๐ท"); // Puerto Rico
check_r("PS", "๐ต๐ธ"); // Palestinian Territories
check_r("PT", "๐ต๐น"); // Portugal
check_r("PW", "๐ต๐ผ"); // Palau
check_r("PY", "๐ต๐พ"); // Paraguay
check_r("QA", "๐ถ๐ฆ"); // Qatar
check_r("RE", "๐ท๐ช"); // Rรฉunion
check_r("RO", "๐ท๐ด"); // Romania
check_r("RS", "๐ท๐ธ"); // Serbia
check_r("RU", "๐ท๐บ"); // Russia
check_r("RW", "๐ท๐ผ"); // Rwanda
check_r("SA", "๐ธ๐ฆ"); // Saudi Arabia
check_r("SB", "๐ธ๐ง"); // Solomon Islands
check_r("SC", "๐ธ๐จ"); // Seychelles
check_r("SD", "๐ธ๐ฉ"); // Sudan
check_r("SE", "๐ธ๐ช"); // Sweden
check_r("SG", "๐ธ๐ฌ"); // Singapore
check_r("SH", "๐ธ๐ญ"); // St. Helena
check_r("SI", "๐ธ๐ฎ"); // Slovenia
check_r("SJ", "๐ธ๐ฏ"); // Svalbard & Jan Mayen
check_r("SK", "๐ธ๐ฐ"); // Slovakia
check_r("SL", "๐ธ๐ฑ"); // Sierra Leone
check_r("SM", "๐ธ๐ฒ"); // San Marino
check_r("SN", "๐ธ๐ณ"); // Senegal
check_r("SO", "๐ธ๐ด"); // Somalia
check_r("SR", "๐ธ๐ท"); // Suriname
check_r("SS", "๐ธ๐ธ"); // South Sudan
check_r("ST", "๐ธ๐น"); // Sรฃo Tomรฉ & Prรญncipe
check_r("SV", "๐ธ๐ป"); // El Salvador
check_r("SX", "๐ธ๐ฝ"); // Sint Maarten
check_r("SY", "๐ธ๐พ"); // Syria
check_r("SZ", "๐ธ๐ฟ"); // Eswatini
check_r("TA", "๐น๐ฆ"); // Tristan da Cunha
check_r("TC", "๐น๐จ"); // Turks & Caicos Islands
check_r("TD", "๐น๐ฉ"); // Chad
check_r("TF", "๐น๐ซ"); // French Southern Territories
check_r("TG", "๐น๐ฌ"); // Togo
check_r("TH", "๐น๐ญ"); // Thailand
check_r("TJ", "๐น๐ฏ"); // Tajikistan
check_r("TK", "๐น๐ฐ"); // Tokelau
check_r("TL", "๐น๐ฑ"); // Timor-Leste
check_r("TM", "๐น๐ฒ"); // Turkmenistan
check_r("TN", "๐น๐ณ"); // Tunisia
check_r("TO", "๐น๐ด"); // Tonga
check_r("TR", "๐น๐ท"); // Turkey
check_r("TT", "๐น๐น"); // Trinidad & Tobago
check_r("TV", "๐น๐ป"); // Tuvalu
check_r("TW", "๐น๐ผ"); // Taiwan
check_r("TZ", "๐น๐ฟ"); // Tanzania
check_r("UA", "๐บ๐ฆ"); // Ukraine
check_r("UG", "๐บ๐ฌ"); // Uganda
check_r("UM", "๐บ๐ฒ"); // U.S. Outlying Islands
check_r("UN", "๐บ๐ณ"); // United Nations
check_r("US", "๐บ๐ธ"); // United States
check_r("UY", "๐บ๐พ"); // Uruguay
check_r("UZ", "๐บ๐ฟ"); // Uzbekistan
check_r("VA", "๐ป๐ฆ"); // Vatican City
check_r("VC", "๐ป๐จ"); // St. Vincent & Grenadines
check_r("VE", "๐ป๐ช"); // Venezuela
check_r("VG", "๐ป๐ฌ"); // British Virgin Islands
check_r("VI", "๐ป๐ฎ"); // U.S. Virgin Islands
check_r("VN", "๐ป๐ณ"); // Vietnam
check_r("VU", "๐ป๐บ"); // Vanuatu
check_r("WF", "๐ผ๐ซ"); // Wallis & Futuna
check_r("WS", "๐ผ๐ธ"); // Samoa
check_r("XK", "๐ฝ๐ฐ"); // Kosovo
check_r("YE", "๐พ๐ช"); // Yemen
check_r("YT", "๐พ๐น"); // Mayotte
check_r("ZA", "๐ฟ๐ฆ"); // South Africa
check_r("ZM", "๐ฟ๐ฒ"); // Zambia
check_r("ZW", "๐ฟ๐ผ"); // Zimbabwe
}
}