1 /*
2 * Multi-language Support - language codes
3 * Copyright (C) 2012 Adam Sutton
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 #include <string.h>
20 #include <stdlib.h>
21
22 #include "lang_codes.h"
23 #include "config.h"
24
25 /* **************************************************************************
26 * Code list
27 * *************************************************************************/
28
29 const lang_code_t lang_codes[] = {
30 { "und", NULL, NULL , "Undetermined" },
31 { "aar", "aa", NULL , "Afar" },
32 { "abk", "ab", NULL , "Abkhazian" },
33 { "ace", NULL, NULL , "Achinese" },
34 { "ach", NULL, NULL , "Acoli" },
35 { "ada", NULL, NULL , "Adangme" },
36 { "ady", NULL, NULL , "Adyghe; Adygei" },
37 { "afa", NULL, NULL , "Afro-Asiatic languages" },
38 { "afh", NULL, NULL , "Afrihili" },
39 { "afr", "af", NULL , "Afrikaans" },
40 { "ain", NULL, NULL , "Ainu" },
41 { "aka", "ak", NULL , "Akan" },
42 { "akk", NULL, NULL , "Akkadian" },
43 { "alb", "sq", "sqi", "Albanian" },
44 { "ale", NULL, NULL , "Aleut" },
45 { "alg", NULL, NULL , "Algonquian languages" },
46 { "alt", NULL, NULL , "Southern Altai" },
47 { "amh", "am", NULL , "Amharic" },
48 { "anp", NULL, NULL , "Angika" },
49 { "apa", NULL, NULL , "Apache languages" },
50 { "ara", "ar", NULL , "Arabic" },
51 { "arc", NULL, NULL , "Official Aramaic (700-300 BCE); Imperial Aramaic (700-300 BCE)" },
52 { "arg", "an", NULL , "Aragonese" },
53 { "arm", "hy", "hye", "Armenian" },
54 { "arn", NULL, NULL , "Mapudungun; Mapuche" },
55 { "arp", NULL, NULL , "Arapaho" },
56 { "art", NULL, NULL , "Artificial languages" },
57 { "arw", NULL, NULL , "Arawak" },
58 { "asm", "as", NULL , "Assamese" },
59 { "ast", NULL, NULL , "Asturian; Bable; Leonese; Asturleonese" },
60 { "ath", NULL, NULL , "Athapascan languages" },
61 { "aus", NULL, NULL , "Australian languages" },
62 { "ava", "av", NULL , "Avaric" },
63 { "ave", "ae", NULL , "Avestan" },
64 { "awa", NULL, NULL , "Awadhi" },
65 { "aym", "ay", NULL , "Aymara" },
66 { "aze", "az", NULL , "Azerbaijani" },
67 { "bad", NULL, NULL , "Banda languages" },
68 { "bai", NULL, NULL , "Bamileke languages" },
69 { "bak", "ba", NULL , "Bashkir" },
70 { "bal", NULL, NULL , "Baluchi" },
71 { "bam", "bm", NULL , "Bambara" },
72 { "ban", NULL, NULL , "Balinese" },
73 { "baq", "eu", "eus", "Basque" },
74 { "bas", NULL, NULL , "Basa" },
75 { "bat", NULL, NULL , "Baltic languages" },
76 { "bej", NULL, NULL , "Beja; Bedawiyet" },
77 { "bel", "be", NULL , "Belarusian" },
78 { "bem", NULL, NULL , "Bemba" },
79 { "ben", "bn", NULL , "Bengali" },
80 { "ber", NULL, NULL , "Berber languages" },
81 { "bho", NULL, NULL , "Bhojpuri" },
82 { "bih", "bh", NULL , "Bihari languages" },
83 { "bik", NULL, NULL , "Bikol" },
84 { "bin", NULL, NULL , "Bini; Edo" },
85 { "bis", "bi", NULL , "Bislama" },
86 { "bla", NULL, NULL , "Siksika" },
87 { "bnt", NULL, NULL , "Bantu languages" },
88 { "bos", "bs", NULL , "Bosnian" },
89 { "bra", NULL, NULL , "Braj" },
90 { "bre", "br", NULL , "Breton" },
91 { "btk", NULL, NULL , "Batak languages" },
92 { "bua", NULL, NULL , "Buriat" },
93 { "bug", NULL, NULL , "Buginese" },
94 { "bul", "bg", NULL , "Bulgarian" },
95 { "bur", "my", "mya", "Burmese" },
96 { "byn", NULL, NULL , "Blin; Bilin" },
97 { "cad", NULL, NULL , "Caddo" },
98 { "cai", NULL, NULL , "Central American Indian languages" },
99 { "car", NULL, NULL , "Galibi Carib" },
100 { "cat", "ca", NULL , "Catalan; Valencian" },
101 { "cau", NULL, NULL , "Caucasian languages" },
102 { "ceb", NULL, NULL , "Cebuano" },
103 { "cel", NULL, NULL , "Celtic languages" },
104 { "cha", "ch", NULL , "Chamorro" },
105 { "chb", NULL, NULL , "Chibcha" },
106 { "che", "ce", NULL , "Chechen" },
107 { "chg", NULL, NULL , "Chagatai" },
108 { "chi", "zh", "zho", "Chinese", "CN" },
109 { "chk", NULL, NULL , "Chuukese" },
110 { "chm", NULL, NULL , "Mari" },
111 { "chn", NULL, NULL , "Chinook jargon" },
112 { "cho", NULL, NULL , "Choctaw" },
113 { "chp", NULL, NULL , "Chipewyan; Dene Suline" },
114 { "chr", NULL, NULL , "Cherokee" },
115 { "chu", "cu", NULL , "Church Slavic; Old Slavonic; Church Slavonic; Old Bulgarian; Old Church Slavonic" },
116 { "chv", "cv", NULL , "Chuvash" },
117 { "chy", NULL, NULL , "Cheyenne" },
118 { "cmc", NULL, NULL , "Chamic languages" },
119 { "cop", NULL, NULL , "Coptic" },
120 { "cor", "kw", NULL , "Cornish" },
121 { "cos", "co", NULL , "Corsican" },
122 { "cre", "cr", NULL , "Cree" },
123 { "crh", NULL, NULL , "Crimean Tatar; Crimean Turkish" },
124 { "crp", NULL, NULL , "Creoles and pidgins" },
125 { "csb", NULL, NULL , "Kashubian" },
126 { "cus", NULL, NULL , "Cushitic languages" },
127 { "cze", "cs", "ces", "Czech" },
128 { "dak", NULL, NULL , "Dakota" },
129 { "dan", "da", NULL , "Danish" },
130 { "dar", NULL, NULL , "Dargwa" },
131 { "day", NULL, NULL , "Land Dayak languages" },
132 { "del", NULL, NULL , "Delaware" },
133 { "den", NULL, NULL , "Slave (Athapascan)" },
134 { "dgr", NULL, NULL , "Dogrib" },
135 { "din", NULL, NULL , "Dinka" },
136 { "div", "dv", NULL , "Divehi; Dhivehi; Maldivian" },
137 { "doi", NULL, NULL , "Dogri" },
138 { "dra", NULL, NULL , "Dravidian languages" },
139 { "dsb", NULL, NULL , "Lower Sorbian" },
140 { "dua", NULL, NULL , "Duala" },
141 { "dut", "nl", "nld", "Dutch; Flemish" },
142 { "dyu", NULL, NULL , "Dyula" },
143 { "dzo", "dz", NULL , "Dzongkha" },
144 { "efi", NULL, NULL , "Efik" },
145 { "egy", NULL, NULL , "Egyptian (Ancient)" },
146 { "eka", NULL, NULL , "Ekajuk" },
147 { "elx", NULL, NULL , "Elamite" },
148 { "eng", "en", NULL , "English", "US|GB" },
149 { "epo", "eo", NULL , "Esperanto" },
150 { "est", "et", NULL , "Estonian" },
151 { "ewe", "ee", NULL , "Ewe" },
152 { "ewo", NULL, NULL , "Ewondo" },
153 { "fan", NULL, NULL , "Fang" },
154 { "fao", "fo", NULL , "Faroese" },
155 { "fat", NULL, NULL , "Fanti" },
156 { "fij", "fj", NULL , "Fijian" },
157 { "fil", NULL, NULL , "Filipino; Pilipino" },
158 { "fin", "fi", NULL , "Finnish" },
159 { "fiu", NULL, NULL , "Finno-Ugrian languages" },
160 { "fon", NULL, NULL , "Fon" },
161 { "fre", "fr", "fra", "French" },
162 { "frr", NULL, NULL , "Northern Frisian" },
163 { "frs", NULL, NULL , "Eastern Frisian" },
164 { "fry", "fy", NULL , "Western Frisian" },
165 { "ful", "ff", NULL , "Fulah" },
166 { "fur", NULL, NULL , "Friulian" },
167 { "gaa", NULL, NULL , "Ga" },
168 { "gay", NULL, NULL , "Gayo" },
169 { "gba", NULL, NULL , "Gbaya" },
170 { "gem", NULL, NULL , "Germanic languages" },
171 { "geo", "ka", "kat", "Georgian" },
172 { "ger", "de", "deu", "German" },
173 { "gez", NULL, NULL , "Geez" },
174 { "gil", NULL, NULL , "Gilbertese" },
175 { "gla", "gd", NULL , "Gaelic; Scottish Gaelic" },
176 { "gle", "ga", NULL , "Irish" },
177 { "glg", "gl", NULL , "Galician" },
178 { "glv", "gv", NULL , "Manx" },
179 { "gon", NULL, NULL , "Gondi" },
180 { "gor", NULL, NULL , "Gorontalo" },
181 { "got", NULL, NULL , "Gothic" },
182 { "grb", NULL, NULL , "Grebo" },
183 { "gre", "el", NULL , "Greek" },
184 { "grn", "gn", NULL , "Guarani" },
185 { "gsw", NULL, NULL , "Swiss German; Alemannic; Alsatian" },
186 { "guj", "gu", NULL , "Gujarati" },
187 { "gwi", NULL, NULL , "Gwich'in" },
188 { "hai", NULL, NULL , "Haida" },
189 { "hat", "ht", NULL , "Haitian; Haitian Creole" },
190 { "hau", "ha", NULL , "Hausa" },
191 { "haw", NULL, NULL , "Hawaiian" },
192 { "heb", "he", NULL , "Hebrew" },
193 { "her", "hz", NULL , "Herero" },
194 { "hil", NULL, NULL , "Hiligaynon" },
195 { "him", NULL, NULL , "Himachali languages; Western Pahari languages" },
196 { "hin", "hi", NULL , "Hindi" },
197 { "hit", NULL, NULL , "Hittite" },
198 { "hmn", NULL, NULL , "Hmong; Mong" },
199 { "hmo", "ho", NULL , "Hiri Motu" },
200 { "hrv", "hr", NULL , "Croatian" },
201 { "hsb", NULL, NULL , "Upper Sorbian" },
202 { "hun", "hu", NULL , "Hungarian" },
203 { "hup", NULL, NULL , "Hupa" },
204 { "iba", NULL, NULL , "Iban" },
205 { "ibo", "ig", NULL , "Igbo" },
206 { "ice", "is", "isl", "Icelandic" },
207 { "ido", "io", NULL , "Ido" },
208 { "iii", "ii", NULL , "Sichuan Yi; Nuosu" },
209 { "ijo", NULL, NULL , "Ijo languages" },
210 { "iku", "iu", NULL , "Inuktitut" },
211 { "ile", "ie", NULL , "Interlingue; Occidental" },
212 { "ilo", NULL, NULL , "Iloko" },
213 { "ina", "ia", NULL , "Interlingua (International Auxiliary Language Association)" },
214 { "inc", NULL, NULL , "Indic languages" },
215 { "ind", "id", NULL , "Indonesian" },
216 { "ine", NULL, NULL , "Indo-European languages" },
217 { "inh", NULL, NULL , "Ingush" },
218 { "ipk", "ik", NULL , "Inupiaq" },
219 { "ira", NULL, NULL , "Iranian languages" },
220 { "iro", NULL, NULL , "Iroquoian languages" },
221 { "ita", "it", NULL , "Italian" },
222 { "jav", "jv", NULL , "Javanese" },
223 { "jbo", NULL, NULL , "Lojban" },
224 { "jpn", "ja", NULL , "Japanese" },
225 { "jpr", NULL, NULL , "Judeo-Persian" },
226 { "jrb", NULL, NULL , "Judeo-Arabic" },
227 { "kaa", NULL, NULL , "Kara-Kalpak" },
228 { "kab", NULL, NULL , "Kabyle" },
229 { "kac", NULL, NULL , "Kachin; Jingpho" },
230 { "kal", "kl", NULL , "Kalaallisut; Greenlandic" },
231 { "kam", NULL, NULL , "Kamba" },
232 { "kan", "kn", NULL , "Kannada" },
233 { "kar", NULL, NULL , "Karen languages" },
234 { "kas", "ks", NULL , "Kashmiri" },
235 { "kau", "kr", NULL , "Kanuri" },
236 { "kaw", NULL, NULL , "Kawi" },
237 { "kaz", "kk", NULL , "Kazakh" },
238 { "kbd", NULL, NULL , "Kabardian" },
239 { "kha", NULL, NULL , "Khasi" },
240 { "khi", NULL, NULL , "Khoisan languages" },
241 { "khm", "km", NULL , "Central Khmer" },
242 { "kho", NULL, NULL , "Khotanese; Sakan" },
243 { "kik", "ki", NULL , "Kikuyu; Gikuyu" },
244 { "kin", "rw", NULL , "Kinyarwanda" },
245 { "kir", "ky", NULL , "Kirghiz; Kyrgyz" },
246 { "kmb", NULL, NULL , "Kimbundu" },
247 { "kok", NULL, NULL , "Konkani" },
248 { "kom", "kv", NULL , "Komi" },
249 { "kon", "kg", NULL , "Kongo" },
250 { "kor", "ko", NULL , "Korean" },
251 { "kos", NULL, NULL , "Kosraean" },
252 { "kpe", NULL, NULL , "Kpelle" },
253 { "krc", NULL, NULL , "Karachay-Balkar" },
254 { "krl", NULL, NULL , "Karelian" },
255 { "kro", NULL, NULL , "Kru languages" },
256 { "kru", NULL, NULL , "Kurukh" },
257 { "kua", "kj", NULL , "Kuanyama; Kwanyama" },
258 { "kum", NULL, NULL , "Kumyk" },
259 { "kur", "ku", NULL , "Kurdish" },
260 { "kut", NULL, NULL , "Kutenai" },
261 { "lad", NULL, NULL , "Ladino" },
262 { "lah", NULL, NULL , "Lahnda" },
263 { "lam", NULL, NULL , "Lamba" },
264 { "lao", "lo", NULL , "Lao" },
265 { "lat", "la", NULL , "Latin" },
266 { "lav", "lv", NULL , "Latvian" },
267 { "lez", NULL, NULL , "Lezghian" },
268 { "lim", "li", NULL , "Limburgan; Limburger; Limburgish" },
269 { "lin", "ln", NULL , "Lingala" },
270 { "lit", "lt", NULL , "Lithuanian" },
271 { "lol", NULL, NULL , "Mongo" },
272 { "loz", NULL, NULL , "Lozi" },
273 { "ltz", "lb", NULL , "Luxembourgish; Letzeburgesch" },
274 { "lua", NULL, NULL , "Luba-Lulua" },
275 { "lub", "lu", NULL , "Luba-Katanga" },
276 { "lug", "lg", NULL , "Ganda" },
277 { "lui", NULL, NULL , "Luiseno" },
278 { "lun", NULL, NULL , "Lunda" },
279 { "luo", NULL, NULL , "Luo (Kenya and Tanzania)" },
280 { "lus", NULL, NULL , "Lushai" },
281 { "mac", "mk", "mkd", "Macedonian" },
282 { "mad", NULL, NULL , "Madurese" },
283 { "mag", NULL, NULL , "Magahi" },
284 { "mah", "mh", NULL , "Marshallese" },
285 { "mai", NULL, NULL , "Maithili" },
286 { "mak", NULL, NULL , "Makasar" },
287 { "mal", "ml", NULL , "Malayalam" },
288 { "man", NULL, NULL , "Mandingo" },
289 { "mao", "mi", "mri", "Maori" },
290 { "map", NULL, NULL , "Austronesian languages" },
291 { "mar", "mr", NULL , "Marathi" },
292 { "mas", NULL, NULL , "Masai" },
293 { "may", "ms", "msa", "Malay" },
294 { "mdf", NULL, NULL , "Moksha" },
295 { "mdr", NULL, NULL , "Mandar" },
296 { "men", NULL, NULL , "Mende" },
297 { "mic", NULL, NULL , "Mi'kmaq; Micmac" },
298 { "min", NULL, NULL , "Minangkabau" },
299 { "mis", NULL, NULL , "Uncoded languages" },
300 { "mkh", NULL, NULL , "Mon-Khmer languages" },
301 { "mlg", "mg", NULL , "Malagasy" },
302 { "mlt", "mt", NULL , "Maltese" },
303 { "mnc", NULL, NULL , "Manchu" },
304 { "mni", NULL, NULL , "Manipuri" },
305 { "mno", NULL, NULL , "Manobo languages" },
306 { "moh", NULL, NULL , "Mohawk" },
307 { "mon", "mn", NULL , "Mongolian" },
308 { "mos", NULL, NULL , "Mossi" },
309 { "mul", NULL, NULL , "Multiple languages" },
310 { "mun", NULL, NULL , "Munda languages" },
311 { "mus", NULL, NULL , "Creek" },
312 { "mwl", NULL, NULL , "Mirandese" },
313 { "mwr", NULL, NULL , "Marwari" },
314 { "myn", NULL, NULL , "Mayan languages" },
315 { "myv", NULL, NULL , "Erzya" },
316 { "nah", NULL, NULL , "Nahuatl languages" },
317 { "nai", NULL, NULL , "North American Indian languages" },
318 { "nap", NULL, NULL , "Neapolitan" },
319 { "nar", NULL, NULL , "Narration: (audio described)"},
320 // Note: above is not part of the ISO spec, but is used in DVB
321 { "nau", "na", NULL , "Nauru" },
322 { "nav", "nv", NULL , "Navajo; Navaho" },
323 { "ndo", "ng", NULL , "Ndonga" },
324 { "nep", "ne", NULL , "Nepali" },
325 { "new", NULL, NULL , "Nepal Bhasa; Newari" },
326 { "nia", NULL, NULL , "Nias" },
327 { "nic", NULL, NULL , "Niger-Kordofanian languages" },
328 { "niu", NULL, NULL , "Niuean" },
329 { "nog", NULL, NULL , "Nogai" },
330 { "nor", "no", NULL , "Norwegian" },
331 { "nqo", NULL, NULL , "N'Ko" },
332 { "nso", NULL, NULL , "Pedi; Sepedi; Northern Sotho" },
333 { "nub", NULL, NULL , "Nubian languages" },
334 { "nwc", NULL, NULL , "Classical Newari; Old Newari; Classical Nepal Bhasa" },
335 { "nya", "ny", NULL , "Chichewa; Chewa; Nyanja" },
336 { "nym", NULL, NULL , "Nyamwezi" },
337 { "nyn", NULL, NULL , "Nyankole" },
338 { "nyo", NULL, NULL , "Nyoro" },
339 { "nzi", NULL, NULL , "Nzima" },
340 { "oci", "oc", NULL , "Occitan (post 1500)" },
341 { "oji", "oj", NULL , "Ojibwa" },
342 { "ori", "or", NULL , "Oriya" },
343 { "orm", "om", NULL , "Oromo" },
344 { "osa", NULL, NULL , "Osage" },
345 { "oss", "os", NULL , "Ossetian; Ossetic" },
346 { "oto", NULL, NULL , "Otomian languages" },
347 { "paa", NULL, NULL , "Papuan languages" },
348 { "pag", NULL, NULL , "Pangasinan" },
349 { "pal", NULL, NULL , "Pahlavi" },
350 { "pam", NULL, NULL , "Pampanga; Kapampangan" },
351 { "pan", "pa", NULL , "Panjabi; Punjabi" },
352 { "pap", NULL, NULL , "Papiamento" },
353 { "pau", NULL, NULL , "Palauan" },
354 { "per", "fa", "fas", "Persian" },
355 { "phi", NULL, NULL , "Philippine languages" },
356 { "phn", NULL, NULL , "Phoenician" },
357 { "pli", "pi", NULL , "Pali" },
358 { "pol", "pl", NULL , "Polish" },
359 { "pon", NULL, NULL , "Pohnpeian" },
360 { "por", "pt", NULL , "Portuguese" },
361 { "pra", NULL, NULL , "Prakrit languages" },
362 { "pus", "ps", NULL , "Pushto; Pashto" },
363 { "qaa", NULL, NULL , "Reserved" },
364 // Note: above is actually range from qaa to qtz
365 { "que", "qu", NULL , "Quechua" },
366 { "raj", NULL, NULL , "Rajasthani" },
367 { "rap", NULL, NULL , "Rapanui" },
368 { "rar", NULL, NULL , "Rarotongan; Cook Islands Maori" },
369 { "roa", NULL, NULL , "Romance languages" },
370 { "roh", "rm", NULL , "Romansh" },
371 { "rom", NULL, NULL , "Romany" },
372 { "rum", "ro", "ron", "Romanian; Moldavian; Moldovan" },
373 { "run", "rn", NULL , "Rundi" },
374 { "rup", NULL, NULL , "Aromanian; Arumanian; Macedo-Romanian" },
375 { "rus", "ru", NULL , "Russian" },
376 { "sad", NULL, NULL , "Sandawe" },
377 { "sag", "sg", NULL , "Sango" },
378 { "sah", NULL, NULL , "Yakut" },
379 { "sai", NULL, NULL , "South American Indian languages" },
380 { "sal", NULL, NULL , "Salishan languages" },
381 { "sam", NULL, NULL , "Samaritan Aramaic" },
382 { "san", "sa", NULL , "Sanskrit" },
383 { "sas", NULL, NULL , "Sasak" },
384 { "sat", NULL, NULL , "Santali" },
385 { "scn", NULL, NULL , "Sicilian" },
386 { "sco", NULL, NULL , "Scots" },
387 { "sel", NULL, NULL , "Selkup" },
388 { "sem", NULL, NULL , "Semitic languages" },
389 { "sgn", NULL, NULL , "Sign Languages" },
390 { "shn", NULL, NULL , "Shan" },
391 { "sid", NULL, NULL , "Sidamo" },
392 { "sin", "si", NULL , "Sinhala; Sinhalese" },
393 { "sio", NULL, NULL , "Siouan languages" },
394 { "sit", NULL, NULL , "Sino-Tibetan languages" },
395 { "sla", NULL, NULL , "Slavic languages" },
396 { "slo", "sk", "slk", "Slovak" },
397 { "slv", "sl", NULL , "Slovenian" },
398 { "sma", NULL, NULL , "Southern Sami" },
399 { "sme", "se", NULL , "Northern Sami" },
400 { "smi", NULL, NULL , "Sami languages" },
401 { "smj", NULL, NULL , "Lule Sami" },
402 { "smn", NULL, NULL , "Inari Sami" },
403 { "smo", "sm", NULL , "Samoan" },
404 { "sms", NULL, NULL , "Skolt Sami" },
405 { "sna", "sn", NULL , "Shona" },
406 { "snd", "sd", NULL , "Sindhi" },
407 { "snk", NULL, NULL , "Soninke" },
408 { "sog", NULL, NULL , "Sogdian" },
409 { "som", "so", NULL , "Somali" },
410 { "son", NULL, NULL , "Songhai languages" },
411 { "spa", "es", NULL , "Spanish" },
412 { "srd", "sc", NULL , "Sardinian" },
413 { "srn", NULL, NULL , "Sranan Tongo" },
414 { "srp", "sr", NULL , "Serbian" },
415 { "srr", NULL, NULL , "Serer" },
416 { "ssa", NULL, NULL , "Nilo-Saharan languages" },
417 { "ssw", "ss", NULL , "Swati" },
418 { "suk", NULL, NULL , "Sukuma" },
419 { "sun", "su", NULL , "Sundanese" },
420 { "sus", NULL, NULL , "Susu" },
421 { "sux", NULL, NULL , "Sumerian" },
422 { "swa", "sw", NULL , "Swahili" },
423 { "swe", "sv", NULL , "Swedish" },
424 { "syc", NULL, NULL , "Classical Syriac" },
425 { "syn", NULL, NULL , "Narration: (sync audio described)"},
426 { "syr", NULL, NULL , "Syriac" },
427 { "tah", "ty", NULL , "Tahitian" },
428 { "tai", NULL, NULL , "Tai languages" },
429 { "tam", "ta", NULL , "Tamil" },
430 { "tat", "tt", NULL , "Tatar" },
431 { "tel", "te", NULL , "Telugu" },
432 { "tem", NULL, NULL , "Timne" },
433 { "ter", NULL, NULL , "Tereno" },
434 { "tet", NULL, NULL , "Tetum" },
435 { "tgk", "tg", NULL , "Tajik" },
436 { "tgl", "tl", NULL , "Tagalog" },
437 { "tha", "th", NULL , "Thai" },
438 { "tib", "bo", "bod", "Tibetan" },
439 { "tig", NULL, NULL , "Tigre" },
440 { "tir", "ti", NULL , "Tigrinya" },
441 { "tiv", NULL, NULL , "Tiv" },
442 { "tkl", NULL, NULL , "Tokelau" },
443 { "tlh", NULL, NULL , "Klingon; tlhIngan-Hol" },
444 { "tli", NULL, NULL , "Tlingit" },
445 { "tmh", NULL, NULL , "Tamashek" },
446 { "tog", NULL, NULL , "Tonga (Nyasa)" },
447 { "ton", "to", NULL , "Tonga (Tonga Islands)" },
448 { "tpi", NULL, NULL , "Tok Pisin" },
449 { "tsi", NULL, NULL , "Tsimshian" },
450 { "tsn", "tn", NULL , "Tswana" },
451 { "tso", "ts", NULL , "Tsonga" },
452 { "tuk", "tk", NULL , "Turkmen" },
453 { "tum", NULL, NULL , "Tumbuka" },
454 { "tup", NULL, NULL , "Tupi languages" },
455 { "tur", "tr", NULL , "Turkish" },
456 { "tut", NULL, NULL , "Altaic languages" },
457 { "tvl", NULL, NULL , "Tuvalu" },
458 { "twi", "tw", NULL , "Twi" },
459 { "tyv", NULL, NULL , "Tuvinian" },
460 { "udm", NULL, NULL , "Udmurt" },
461 { "uga", NULL, NULL , "Ugaritic" },
462 { "uig", "ug", NULL , "Uighur; Uyghur" },
463 { "ukr", "uk", NULL , "Ukrainian" },
464 { "umb", NULL, NULL , "Umbundu" },
465 { "urd", "ur", NULL , "Urdu" },
466 { "uzb", "uz", NULL , "Uzbek" },
467 { "v.o", NULL, NULL , "Voice Original" },
468 { "vai", NULL, NULL , "Vai" },
469 { "ven", "ve", NULL , "Venda" },
470 { "vie", "vi", NULL , "Vietnamese" },
471 { "vol", "vo", NULL , "Volapük" },
472 { "vot", NULL, NULL , "Votic" },
473 { "wak", NULL, NULL , "Wakashan languages" },
474 { "wal", NULL, NULL , "Wolaitta; Wolaytta" },
475 { "war", NULL, NULL , "Waray" },
476 { "was", NULL, NULL , "Washo" },
477 { "wel", "cy", "cym", "Welsh" },
478 { "wen", NULL, NULL , "Sorbian languages" },
479 { "wln", "wa", NULL , "Walloon" },
480 { "wol", "wo", NULL , "Wolof" },
481 { "xal", NULL, NULL , "Kalmyk; Oirat" },
482 { "xho", "xh", NULL , "Xhosa" },
483 { "yao", NULL, NULL , "Yao" },
484 { "yap", NULL, NULL , "Yapese" },
485 { "yid", "yi", NULL , "Yiddish" },
486 { "yor", "yo", NULL , "Yoruba" },
487 { "ypk", NULL, NULL , "Yupik languages" },
488 { "zap", NULL, NULL , "Zapotec" },
489 { "zbl", NULL, NULL , "Blissymbols; Blissymbolics; Bliss" },
490 { "zen", NULL, NULL , "Zenaga" },
491 { "zha", "za", NULL , "Zhuang; Chuang" },
492 { "znd", NULL, NULL , "Zande languages" },
493 { "zul", "zu", NULL , "Zulu" },
494 { "zun", NULL, NULL , "Zuni" },
495 { "zza", NULL, NULL , "Zaza; Dimili; Dimli; Kirdki; Kirmanjki; Zazaki" },
496 { NULL, NULL, NULL, NULL }
497 };
498
499 lang_code_lookup_t* lang_codes_code2b = NULL;
500 lang_code_lookup_t* lang_codes_code1 = NULL;
501 lang_code_lookup_t* lang_codes_code2t = NULL;
502
503 /* **************************************************************************
504 * Functions
505 * *************************************************************************/
506
507 /* Compare language codes */
_lang_code2b_cmp(void * a,void * b)508 static int _lang_code2b_cmp ( void *a, void *b )
509 {
510 return strcmp(((lang_code_lookup_element_t*)a)->lang_code->code2b,
511 ((lang_code_lookup_element_t*)b)->lang_code->code2b);
512 }
513
_lang_code1_cmp(void * a,void * b)514 static int _lang_code1_cmp ( void *a, void *b )
515 {
516 return strcmp(((lang_code_lookup_element_t*)a)->lang_code->code1,
517 ((lang_code_lookup_element_t*)b)->lang_code->code1);
518 }
519
_lang_code2t_cmp(void * a,void * b)520 static int _lang_code2t_cmp ( void *a, void *b )
521 {
522 return strcmp(((lang_code_lookup_element_t*)a)->lang_code->code2t,
523 ((lang_code_lookup_element_t*)b)->lang_code->code2t);
524 }
525
_lang_code_lookup_add(lang_code_lookup_t * lookup_table,const lang_code_t * code,int (* func)(void *,void *))526 static int _lang_code_lookup_add( lang_code_lookup_t* lookup_table, const lang_code_t *code, int (*func)(void*, void*) ) {
527 lang_code_lookup_element_t *element;
528 element = (lang_code_lookup_element_t *)calloc(1, sizeof(lang_code_lookup_element_t));
529 element->lang_code = code;
530 RB_INSERT_SORTED(lookup_table, element, link, func);
531 return 0;
532 }
533
_lang_code_get(const char * code,size_t len)534 static const lang_code_t *_lang_code_get ( const char *code, size_t len )
535 {
536 int i;
537 char tmp[4];
538
539 if (lang_codes_code2b == NULL) {
540 const lang_code_t *c = lang_codes;
541
542 lang_codes_code2b = (lang_code_lookup_t *)calloc(1, sizeof(lang_code_lookup_t));
543 lang_codes_code1 = (lang_code_lookup_t *)calloc(1, sizeof(lang_code_lookup_t));
544 lang_codes_code2t = (lang_code_lookup_t *)calloc(1, sizeof(lang_code_lookup_t));
545
546 while (c->code2b) {
547 _lang_code_lookup_add(lang_codes_code2b, c, _lang_code2b_cmp);
548 if (c->code1) _lang_code_lookup_add(lang_codes_code1, c, _lang_code1_cmp);
549 if (c->code2t) _lang_code_lookup_add(lang_codes_code2t, c, _lang_code2t_cmp);
550 c++;
551 }
552 }
553
554 if (code && *code && len) {
555
556 /* Extract the code (lowercase) */
557 i = 0;
558 while (i < 3 && *code && len) {
559 if (*code == ';' || *code == ',' || *code == '-') break;
560 if (*code != ' ')
561 tmp[i++] = *code | 0x20; // |0x20 = lower case
562 code++;
563 len--;
564 }
565 tmp[i] = '\0';
566
567 /* Convert special case (qaa..qtz) */
568 if (*tmp == 'q') {
569 if (tmp[1] >= 'a' && tmp[1] <= 'z' && tmp[2] >= 'a' && tmp[2] <= 'z') {
570 tmp[1] = 'a';
571 tmp[2] = 'a';
572 }
573 }
574
575 /* Search */
576 if (i) {
577 lang_code_lookup_element_t sample, *element;
578 lang_code_t lang_code;
579 lang_code.code1 = tmp;
580 lang_code.code2b = tmp;
581 lang_code.code2t = tmp;
582 sample.lang_code = &lang_code;
583 element = RB_FIND(lang_codes_code2b, &sample, link, _lang_code2b_cmp);
584 if (element != NULL) return element->lang_code;
585 element = RB_FIND(lang_codes_code1, &sample, link, _lang_code1_cmp);
586 if (element != NULL) return element->lang_code;
587 element = RB_FIND(lang_codes_code2t, &sample, link, _lang_code2t_cmp);
588 if (element != NULL) return element->lang_code;
589 }
590 }
591 return &lang_codes[0];
592 }
593
lang_code_get(const char * code)594 const char *lang_code_get ( const char *code )
595 {
596 return lang_code_get3(code)->code2b;
597 }
598
lang_code_get2(const char * code,size_t len)599 const char *lang_code_get2 ( const char *code, size_t len )
600 {
601 return _lang_code_get(code, len)->code2b;
602 }
603
lang_code_get3(const char * code)604 const lang_code_t *lang_code_get3 ( const char *code )
605 {
606 return _lang_code_get(code, strlen(code ?: ""));
607 }
608
lang_code_split(const char * codes)609 const char **lang_code_split ( const char *codes )
610 {
611 int i = 0;
612 const lang_code_t **lcs = lang_code_split2(codes);
613 const char **ret;
614
615 if(!lcs) return NULL;
616
617 while(lcs[i])
618 i++;
619
620 ret = calloc(1+i, sizeof(char*));
621
622 i = 0;
623 while(lcs[i]) {
624 ret[i] = lcs[i]->code2b;
625 i++;
626 }
627 ret[i] = NULL;
628 free(lcs);
629
630 return ret;
631 }
632
lang_code_split2(const char * codes)633 const lang_code_t **lang_code_split2 ( const char *codes )
634 {
635 int n;
636 const char *c, *p;
637 const lang_code_t **ret;
638 const lang_code_t *co;
639
640 /* Defaults */
641 if (!codes) codes = config_get_language();
642
643 /* No config */
644 if (!codes) return NULL;
645
646 /* Count entries */
647 n = 0;
648 c = codes;
649 while (*c) {
650 if (*c == ',') n++;
651 c++;
652 }
653 ret = calloc(2+n, sizeof(lang_code_t*));
654
655 /* Create list */
656 n = 0;
657 p = c = codes;
658 while (*c) {
659 if (*c == ',') {
660 co = lang_code_get3(p);
661 if(co)
662 ret[n++] = co;
663 p = c + 1;
664 }
665 c++;
666 }
667 if (*p) ret[n++] = lang_code_get3(p);
668 ret[n] = NULL;
669
670 return ret;
671 }
672
lang_code_free(lang_code_lookup_t * l)673 static void lang_code_free( lang_code_lookup_t *l )
674 {
675 lang_code_lookup_element_t *element;
676 if (l == NULL)
677 return;
678 while ((element = RB_FIRST(l)) != NULL) {
679 RB_REMOVE(l, element, link);
680 free(element);
681 }
682 free(l);
683 }
684
lang_code_preferred(void)685 const char *lang_code_preferred( void )
686 {
687 const char *codes = config_get_language(), *ret = "und";
688 const lang_code_t *co;
689
690 if (codes) {
691 co = lang_code_get3(codes);
692 if (co && co->code2b)
693 ret = co->code2b;
694 }
695
696 return ret;
697 }
698
lang_code_user(const char * ucode)699 char *lang_code_user( const char *ucode )
700 {
701 const char *codes = config_get_language(), *s;
702 char *ret;
703
704 if (!codes)
705 return ucode ? strdup(ucode) : NULL;
706 if (!ucode)
707 return strdup(codes);
708 ret = malloc(strlen(codes) + strlen(ucode) + 2);
709 strcpy(ret, ucode);
710 while (codes && *codes) {
711 s = codes;
712 while (*s && *s != ',')
713 s++;
714 if (strncmp(codes, ucode, s - codes)) {
715 strcat(ret, ",");
716 strncat(ret, codes, s - codes);
717 }
718 if (*s && *s == ',')
719 s++;
720 codes = s;
721 }
722 return ret;
723 }
724
lang_code_done(void)725 void lang_code_done( void )
726 {
727 lang_code_free(lang_codes_code2b);
728 lang_code_free(lang_codes_code1);
729 lang_code_free(lang_codes_code2t);
730 }
731