1use country_code::iso3166_1::alpha_2::CountryCode;
4
5use crate::{language_code, language_tag};
6
7language_code! {
8 length = 2;
9 #[derive(Debug, Clone)]
10 #[allow(non_camel_case_types)]
11 pub enum LanguageCode {
12 ab,
13 aa,
14 af,
15 ak,
16 sq,
17 am,
18 ar,
19 an,
20 hy,
21 r#as,
22 av,
23 ae,
24 ay,
25 az,
26 bm,
27 ba,
28 eu,
29 be,
30 bn,
31 bi,
32 bs,
33 br,
34 bg,
35 my,
36 ca,
37 ch,
38 ce,
39 ny,
40 zh,
41 cu,
42 cv,
43 kw,
44 co,
45 cr,
46 hr,
47 cs,
48 da,
49 dv,
50 nl,
51 dz,
52 en,
53 eo,
54 et,
55 ee,
56 fo,
57 fj,
58 fi,
59 fr,
60 fy,
61 ff,
62 gd,
63 gl,
64 lg,
65 ka,
66 de,
67 el,
68 kl,
69 gn,
70 gu,
71 ht,
72 ha,
73 he,
74 hz,
75 hi,
76 ho,
77 hu,
78 is,
79 io,
80 ig,
81 id,
82 ia,
83 ie,
84 iu,
85 ik,
86 ga,
87 it,
88 ja,
89 jv,
90 kn,
91 kr,
92 ks,
93 kk,
94 km,
95 ki,
96 rw,
97 ky,
98 kv,
99 kg,
100 ko,
101 kj,
102 ku,
103 lo,
104 la,
105 lv,
106 li,
107 ln,
108 lt,
109 lu,
110 lb,
111 mk,
112 mg,
113 ms,
114 ml,
115 mt,
116 gv,
117 mi,
118 mr,
119 mh,
120 mn,
121 na,
122 nv,
123 nd,
124 nr,
125 ng,
126 ne,
127 no,
128 nb,
129 nn,
130 ii,
131 oc,
132 oj,
133 or,
134 om,
135 os,
136 pi,
137 ps,
138 fa,
139 pl,
140 pt,
141 pa,
142 qu,
143 ro,
144 rm,
145 rn,
146 ru,
147 se,
148 sm,
149 sg,
150 sa,
151 sc,
152 sr,
153 sn,
154 sd,
155 si,
156 sk,
157 sl,
158 so,
159 st,
160 es,
161 su,
162 sw,
163 ss,
164 sv,
165 tl,
166 ty,
167 tg,
168 ta,
169 tt,
170 te,
171 th,
172 bo,
173 ti,
174 to,
175 ts,
176 tn,
177 tr,
178 tk,
179 tw,
180 ug,
181 uk,
182 ur,
183 uz,
184 ve,
185 vi,
186 vo,
187 wa,
188 cy,
189 wo,
190 xh,
191 yi,
192 yo,
193 za,
194 zu,
195 }
196}
197
198impl Default for LanguageCode {
200 fn default() -> Self {
201 Self::en
202 }
203}
204
205language_tag! {
206 #[derive(Debug, Clone)]
207 pub struct LanguageTag {
208 pub language_code: LanguageCode,
209 pub country_code: Option<CountryCode>,
210 }
211}
212
213impl Default for LanguageTag {
214 fn default() -> Self {
215 Self::new(LanguageCode::en, None)
216 }
217}
218
219#[cfg(test)]
220mod tests {
221 use super::*;
222
223 use alloc::string::ToString as _;
224
225 use csv::Reader;
226
227 #[test]
228 fn test_language_code() {
229 let mut rdr = Reader::from_reader(
231 include_str!("../tests/List_of_ISO_639-1_codes/list.csv").as_bytes(),
232 );
233
234 let mut n = 0;
235 for record in rdr.records() {
236 let record = record.unwrap();
237
238 let code = &record[1];
239 assert_eq!(code.parse::<LanguageCode>().unwrap().to_string(), code);
240 n += 1;
241 }
242
243 assert_eq!(LanguageCode::VARS.len(), n);
244
245 assert_eq!(
247 "zz".parse::<LanguageCode>().unwrap(),
248 LanguageCode::Other("zz".into())
249 );
250 assert_eq!(
251 "x".parse::<LanguageCode>().err().unwrap(),
252 crate::error::ParseError::Invalid("x".into())
253 );
254 #[cfg(feature = "std")]
255 {
256 std::println!("{}", "x".parse::<LanguageCode>().err().unwrap());
257 }
258
259 assert_eq!(LanguageCode::en, LanguageCode::en);
261 assert_eq!(LanguageCode::en, LanguageCode::Other("en".into()));
262 assert_eq!(LanguageCode::en, "en");
263
264 #[cfg(feature = "std")]
265 {
266 let mut h = std::collections::HashSet::new();
268 h.insert(LanguageCode::en);
269 h.insert(LanguageCode::Other("en".into()));
270 assert_eq!(h.len(), 1);
271 }
272
273 assert_eq!(LanguageCode::default(), LanguageCode::en);
275
276 #[cfg(feature = "serde")]
277 {
278 #[derive(serde::Serialize, serde::Deserialize)]
279 struct Foo {
280 code: LanguageCode,
281 }
282
283 assert_eq!(
284 serde_json::from_str::<Foo>(r#"{"code":"en"}"#)
285 .unwrap()
286 .code,
287 LanguageCode::en
288 );
289 assert_eq!(
290 serde_json::to_string(&Foo {
291 code: LanguageCode::en
292 })
293 .unwrap(),
294 r#"{"code":"en"}"#
295 );
296 }
297 }
298
299 #[test]
300 fn test_language_tag() {
301 assert_eq!(
303 "en".parse::<LanguageTag>().unwrap(),
304 LanguageTag::new(LanguageCode::en, None)
305 );
306 assert_eq!(LanguageTag::new(LanguageCode::en, None).to_string(), "en",);
307
308 assert_eq!(
309 "zh-CN".parse::<LanguageTag>().unwrap(),
310 LanguageTag::new(LanguageCode::zh, Some(CountryCode::CN))
311 );
312 assert_eq!(
313 LanguageTag::new(LanguageCode::zh, Some(CountryCode::CN)).to_string(),
314 "zh-CN"
315 );
316 assert_eq!(
317 "zh-TW".parse::<LanguageTag>().unwrap(),
318 LanguageTag::new(LanguageCode::zh, Some(CountryCode::TW))
319 );
320
321 assert_eq!(
322 "x-y".parse::<LanguageTag>().err().unwrap(),
323 crate::error::LanguageTagParseError::LanguageCodeInvalid("x".into())
324 );
325 assert_eq!(
326 "en-y".parse::<LanguageTag>().err().unwrap(),
327 crate::error::LanguageTagParseError::CountryCodeInvalid("y".into())
328 );
329
330 assert_eq!(
332 LanguageTag::new(LanguageCode::en, None),
333 LanguageTag::new(LanguageCode::en, None)
334 );
335 assert_eq!(LanguageTag::new(LanguageCode::en, None), "en");
336
337 assert_eq!(
339 LanguageTag::default(),
340 LanguageTag::new(LanguageCode::en, None)
341 );
342
343 #[cfg(feature = "serde")]
344 {
345 #[derive(serde::Serialize, serde::Deserialize)]
346 struct Foo {
347 tag: LanguageTag,
348 }
349
350 assert_eq!(
351 serde_json::from_str::<Foo>(r#"{"tag":"en"}"#).unwrap().tag,
352 LanguageTag::new(LanguageCode::en, None),
353 );
354 assert_eq!(
355 serde_json::to_string(&Foo {
356 tag: LanguageTag::new(LanguageCode::en, None)
357 })
358 .unwrap(),
359 r#"{"tag":"en"}"#
360 );
361 }
362 }
363}