1 /*************************************************************************/
2 /* translation.cpp */
3 /*************************************************************************/
4 /* This file is part of: */
5 /* GODOT ENGINE */
6 /* https://godotengine.org */
7 /*************************************************************************/
8 /* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
9 /* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
10 /* */
11 /* Permission is hereby granted, free of charge, to any person obtaining */
12 /* a copy of this software and associated documentation files (the */
13 /* "Software"), to deal in the Software without restriction, including */
14 /* without limitation the rights to use, copy, modify, merge, publish, */
15 /* distribute, sublicense, and/or sell copies of the Software, and to */
16 /* permit persons to whom the Software is furnished to do so, subject to */
17 /* the following conditions: */
18 /* */
19 /* The above copyright notice and this permission notice shall be */
20 /* included in all copies or substantial portions of the Software. */
21 /* */
22 /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
23 /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
24 /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
25 /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
26 /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
27 /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
28 /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
29 /*************************************************************************/
30
31 #include "translation.h"
32
33 #include "core/io/resource_loader.h"
34 #include "core/os/os.h"
35 #include "core/project_settings.h"
36
37 // ISO 639-1 language codes, with the addition of glibc locales with their
38 // regional identifiers. This list must match the language names (in English)
39 // of locale_names.
40 //
41 // References:
42 // - https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes
43 // - https://lh.2xlibre.net/locales/
44
45 static const char *locale_list[] = {
46 "aa", // Afar
47 "aa_DJ", // Afar (Djibouti)
48 "aa_ER", // Afar (Eritrea)
49 "aa_ET", // Afar (Ethiopia)
50 "af", // Afrikaans
51 "af_ZA", // Afrikaans (South Africa)
52 "agr_PE", // Aguaruna (Peru)
53 "ak_GH", // Akan (Ghana)
54 "am_ET", // Amharic (Ethiopia)
55 "an_ES", // Aragonese (Spain)
56 "anp_IN", // Angika (India)
57 "ar", // Arabic
58 "ar_AE", // Arabic (United Arab Emirates)
59 "ar_BH", // Arabic (Bahrain)
60 "ar_DZ", // Arabic (Algeria)
61 "ar_EG", // Arabic (Egypt)
62 "ar_IN", // Arabic (India)
63 "ar_IQ", // Arabic (Iraq)
64 "ar_JO", // Arabic (Jordan)
65 "ar_KW", // Arabic (Kuwait)
66 "ar_LB", // Arabic (Lebanon)
67 "ar_LY", // Arabic (Libya)
68 "ar_MA", // Arabic (Morocco)
69 "ar_OM", // Arabic (Oman)
70 "ar_QA", // Arabic (Qatar)
71 "ar_SA", // Arabic (Saudi Arabia)
72 "ar_SD", // Arabic (Sudan)
73 "ar_SS", // Arabic (South Soudan)
74 "ar_SY", // Arabic (Syria)
75 "ar_TN", // Arabic (Tunisia)
76 "ar_YE", // Arabic (Yemen)
77 "as_IN", // Assamese (India)
78 "ast_ES", // Asturian (Spain)
79 "ayc_PE", // Southern Aymara (Peru)
80 "ay_PE", // Aymara (Peru)
81 "az_AZ", // Azerbaijani (Azerbaijan)
82 "be", // Belarusian
83 "be_BY", // Belarusian (Belarus)
84 "bem_ZM", // Bemba (Zambia)
85 "ber_DZ", // Berber languages (Algeria)
86 "ber_MA", // Berber languages (Morocco)
87 "bg", // Bulgarian
88 "bg_BG", // Bulgarian (Bulgaria)
89 "bhb_IN", // Bhili (India)
90 "bho_IN", // Bhojpuri (India)
91 "bi_TV", // Bislama (Tuvalu)
92 "bn", // Bengali
93 "bn_BD", // Bengali (Bangladesh)
94 "bn_IN", // Bengali (India)
95 "bo", // Tibetan
96 "bo_CN", // Tibetan (China)
97 "bo_IN", // Tibetan (India)
98 "br_FR", // Breton (France)
99 "brx_IN", // Bodo (India)
100 "bs_BA", // Bosnian (Bosnia and Herzegovina)
101 "byn_ER", // Bilin (Eritrea)
102 "ca", // Catalan
103 "ca_AD", // Catalan (Andorra)
104 "ca_ES", // Catalan (Spain)
105 "ca_FR", // Catalan (France)
106 "ca_IT", // Catalan (Italy)
107 "ce_RU", // Chechen (Russia)
108 "chr_US", // Cherokee (United States)
109 "cmn_TW", // Mandarin Chinese (Taiwan)
110 "crh_UA", // Crimean Tatar (Ukraine)
111 "csb_PL", // Kashubian (Poland)
112 "cs", // Czech
113 "cs_CZ", // Czech (Czech Republic)
114 "cv_RU", // Chuvash (Russia)
115 "cy_GB", // Welsh (United Kingdom)
116 "da", // Danish
117 "da_DK", // Danish (Denmark)
118 "de", // German
119 "de_AT", // German (Austria)
120 "de_BE", // German (Belgium)
121 "de_CH", // German (Switzerland)
122 "de_DE", // German (Germany)
123 "de_IT", // German (Italy)
124 "de_LU", // German (Luxembourg)
125 "doi_IN", // Dogri (India)
126 "dv_MV", // Dhivehi (Maldives)
127 "dz_BT", // Dzongkha (Bhutan)
128 "el", // Greek
129 "el_CY", // Greek (Cyprus)
130 "el_GR", // Greek (Greece)
131 "en", // English
132 "en_AG", // English (Antigua and Barbuda)
133 "en_AU", // English (Australia)
134 "en_BW", // English (Botswana)
135 "en_CA", // English (Canada)
136 "en_DK", // English (Denmark)
137 "en_GB", // English (United Kingdom)
138 "en_HK", // English (Hong Kong)
139 "en_IE", // English (Ireland)
140 "en_IL", // English (Israel)
141 "en_IN", // English (India)
142 "en_NG", // English (Nigeria)
143 "en_NZ", // English (New Zealand)
144 "en_PH", // English (Philippines)
145 "en_SG", // English (Singapore)
146 "en_US", // English (United States)
147 "en_ZA", // English (South Africa)
148 "en_ZM", // English (Zambia)
149 "en_ZW", // English (Zimbabwe)
150 "eo", // Esperanto
151 "es", // Spanish
152 "es_AR", // Spanish (Argentina)
153 "es_BO", // Spanish (Bolivia)
154 "es_CL", // Spanish (Chile)
155 "es_CO", // Spanish (Colombia)
156 "es_CR", // Spanish (Costa Rica)
157 "es_CU", // Spanish (Cuba)
158 "es_DO", // Spanish (Dominican Republic)
159 "es_EC", // Spanish (Ecuador)
160 "es_ES", // Spanish (Spain)
161 "es_GT", // Spanish (Guatemala)
162 "es_HN", // Spanish (Honduras)
163 "es_MX", // Spanish (Mexico)
164 "es_NI", // Spanish (Nicaragua)
165 "es_PA", // Spanish (Panama)
166 "es_PE", // Spanish (Peru)
167 "es_PR", // Spanish (Puerto Rico)
168 "es_PY", // Spanish (Paraguay)
169 "es_SV", // Spanish (El Salvador)
170 "es_US", // Spanish (United States)
171 "es_UY", // Spanish (Uruguay)
172 "es_VE", // Spanish (Venezuela)
173 "et", // Estonian
174 "et_EE", // Estonian (Estonia)
175 "eu", // Basque
176 "eu_ES", // Basque (Spain)
177 "fa", // Persian
178 "fa_IR", // Persian (Iran)
179 "ff_SN", // Fulah (Senegal)
180 "fi", // Finnish
181 "fi_FI", // Finnish (Finland)
182 "fil", // Filipino
183 "fil_PH", // Filipino (Philippines)
184 "fo_FO", // Faroese (Faroe Islands)
185 "fr", // French
186 "fr_BE", // French (Belgium)
187 "fr_CA", // French (Canada)
188 "fr_CH", // French (Switzerland)
189 "fr_FR", // French (France)
190 "fr_LU", // French (Luxembourg)
191 "fur_IT", // Friulian (Italy)
192 "fy_DE", // Western Frisian (Germany)
193 "fy_NL", // Western Frisian (Netherlands)
194 "ga", // Irish
195 "ga_IE", // Irish (Ireland)
196 "gd_GB", // Scottish Gaelic (United Kingdom)
197 "gez_ER", // Geez (Eritrea)
198 "gez_ET", // Geez (Ethiopia)
199 "gl_ES", // Galician (Spain)
200 "gu_IN", // Gujarati (India)
201 "gv_GB", // Manx (United Kingdom)
202 "hak_TW", // Hakka Chinese (Taiwan)
203 "ha_NG", // Hausa (Nigeria)
204 "he", // Hebrew
205 "he_IL", // Hebrew (Israel)
206 "hi", // Hindi
207 "hi_IN", // Hindi (India)
208 "hne_IN", // Chhattisgarhi (India)
209 "hr", // Croatian
210 "hr_HR", // Croatian (Croatia)
211 "hsb_DE", // Upper Sorbian (Germany)
212 "ht_HT", // Haitian (Haiti)
213 "hu", // Hungarian
214 "hu_HU", // Hungarian (Hungary)
215 "hus_MX", // Huastec (Mexico)
216 "hy_AM", // Armenian (Armenia)
217 "ia_FR", // Interlingua (France)
218 "id", // Indonesian
219 "id_ID", // Indonesian (Indonesia)
220 "ig_NG", // Igbo (Nigeria)
221 "ik_CA", // Inupiaq (Canada)
222 "is", // Icelandic
223 "is_IS", // Icelandic (Iceland)
224 "it", // Italian
225 "it_CH", // Italian (Switzerland)
226 "it_IT", // Italian (Italy)
227 "iu_CA", // Inuktitut (Canada)
228 "ja", // Japanese
229 "ja_JP", // Japanese (Japan)
230 "kab_DZ", // Kabyle (Algeria)
231 "ka", // Georgian
232 "ka_GE", // Georgian (Georgia)
233 "kk_KZ", // Kazakh (Kazakhstan)
234 "kl_GL", // Kalaallisut (Greenland)
235 "km_KH", // Central Khmer (Cambodia)
236 "kn_IN", // Kannada (India)
237 "kok_IN", // Konkani (India)
238 "ko", // Korean
239 "ko_KR", // Korean (South Korea)
240 "ks_IN", // Kashmiri (India)
241 "ku", // Kurdish
242 "ku_TR", // Kurdish (Turkey)
243 "kw_GB", // Cornish (United Kingdom)
244 "ky_KG", // Kirghiz (Kyrgyzstan)
245 "lb_LU", // Luxembourgish (Luxembourg)
246 "lg_UG", // Ganda (Uganda)
247 "li_BE", // Limburgan (Belgium)
248 "li_NL", // Limburgan (Netherlands)
249 "lij_IT", // Ligurian (Italy)
250 "ln_CD", // Lingala (Congo)
251 "lo_LA", // Lao (Laos)
252 "lt", // Lithuanian
253 "lt_LT", // Lithuanian (Lithuania)
254 "lv", // Latvian
255 "lv_LV", // Latvian (Latvia)
256 "lzh_TW", // Literary Chinese (Taiwan)
257 "mag_IN", // Magahi (India)
258 "mai_IN", // Maithili (India)
259 "mg_MG", // Malagasy (Madagascar)
260 "mh_MH", // Marshallese (Marshall Islands)
261 "mhr_RU", // Eastern Mari (Russia)
262 "mi", // Māori
263 "mi_NZ", // Māori (New Zealand)
264 "miq_NI", // Mískito (Nicaragua)
265 "mk", // Macedonian
266 "mk_MK", // Macedonian (Macedonia)
267 "ml", // Malayalam
268 "ml_IN", // Malayalam (India)
269 "mni_IN", // Manipuri (India)
270 "mn_MN", // Mongolian (Mongolia)
271 "mr_IN", // Marathi (India)
272 "ms", // Malay
273 "ms_MY", // Malay (Malaysia)
274 "mt", // Maltese
275 "mt_MT", // Maltese (Malta)
276 "my_MM", // Burmese (Myanmar)
277 "myv_RU", // Erzya (Russia)
278 "nah_MX", // Nahuatl languages (Mexico)
279 "nan_TW", // Min Nan Chinese (Taiwan)
280 "nb", // Norwegian Bokmål
281 "nb_NO", // Norwegian Bokmål (Norway)
282 "nds_DE", // Low German (Germany)
283 "nds_NL", // Low German (Netherlands)
284 "ne_NP", // Nepali (Nepal)
285 "nhn_MX", // Central Nahuatl (Mexico)
286 "niu_NU", // Niuean (Niue)
287 "niu_NZ", // Niuean (New Zealand)
288 "nl", // Dutch
289 "nl_AW", // Dutch (Aruba)
290 "nl_BE", // Dutch (Belgium)
291 "nl_NL", // Dutch (Netherlands)
292 "nn", // Norwegian Nynorsk
293 "nn_NO", // Norwegian Nynorsk (Norway)
294 "nr_ZA", // South Ndebele (South Africa)
295 "nso_ZA", // Pedi (South Africa)
296 "oc_FR", // Occitan (France)
297 "om", // Oromo
298 "om_ET", // Oromo (Ethiopia)
299 "om_KE", // Oromo (Kenya)
300 "or_IN", // Oriya (India)
301 "os_RU", // Ossetian (Russia)
302 "pa_IN", // Panjabi (India)
303 "pap", // Papiamento
304 "pap_AN", // Papiamento (Netherlands Antilles)
305 "pap_AW", // Papiamento (Aruba)
306 "pap_CW", // Papiamento (Curaçao)
307 "pa_PK", // Panjabi (Pakistan)
308 "pl", // Polish
309 "pl_PL", // Polish (Poland)
310 "pr", // Pirate
311 "ps_AF", // Pushto (Afghanistan)
312 "pt", // Portuguese
313 "pt_BR", // Portuguese (Brazil)
314 "pt_PT", // Portuguese (Portugal)
315 "quy_PE", // Ayacucho Quechua (Peru)
316 "quz_PE", // Cusco Quechua (Peru)
317 "raj_IN", // Rajasthani (India)
318 "ro", // Romanian
319 "ro_RO", // Romanian (Romania)
320 "ru", // Russian
321 "ru_RU", // Russian (Russia)
322 "ru_UA", // Russian (Ukraine)
323 "rw_RW", // Kinyarwanda (Rwanda)
324 "sa_IN", // Sanskrit (India)
325 "sat_IN", // Santali (India)
326 "sc_IT", // Sardinian (Italy)
327 "sco", // Scots
328 "sd_IN", // Sindhi (India)
329 "se_NO", // Northern Sami (Norway)
330 "sgs_LT", // Samogitian (Lithuania)
331 "shs_CA", // Shuswap (Canada)
332 "sid_ET", // Sidamo (Ethiopia)
333 "si", // Sinhala
334 "si_LK", // Sinhala (Sri Lanka)
335 "sk", // Slovak
336 "sk_SK", // Slovak (Slovakia)
337 "sl", // Slovenian
338 "sl_SI", // Slovenian (Slovenia)
339 "so", // Somali
340 "so_DJ", // Somali (Djibouti)
341 "so_ET", // Somali (Ethiopia)
342 "so_KE", // Somali (Kenya)
343 "so_SO", // Somali (Somalia)
344 "son_ML", // Songhai languages (Mali)
345 "sq", // Albanian
346 "sq_AL", // Albanian (Albania)
347 "sq_KV", // Albanian (Kosovo)
348 "sq_MK", // Albanian (Macedonia)
349 "sr", // Serbian
350 "sr_Cyrl", // Serbian (Cyrillic)
351 "sr_Latn", // Serbian (Latin)
352 "sr_ME", // Serbian (Montenegro)
353 "sr_RS", // Serbian (Serbia)
354 "ss_ZA", // Swati (South Africa)
355 "st_ZA", // Southern Sotho (South Africa)
356 "sv", // Swedish
357 "sv_FI", // Swedish (Finland)
358 "sv_SE", // Swedish (Sweden)
359 "sw_KE", // Swahili (Kenya)
360 "sw_TZ", // Swahili (Tanzania)
361 "szl_PL", // Silesian (Poland)
362 "ta", // Tamil
363 "ta_IN", // Tamil (India)
364 "ta_LK", // Tamil (Sri Lanka)
365 "tcy_IN", // Tulu (India)
366 "te", // Telugu
367 "te_IN", // Telugu (India)
368 "tg_TJ", // Tajik (Tajikistan)
369 "the_NP", // Chitwania Tharu (Nepal)
370 "th", // Thai
371 "th_TH", // Thai (Thailand)
372 "ti", // Tigrinya
373 "ti_ER", // Tigrinya (Eritrea)
374 "ti_ET", // Tigrinya (Ethiopia)
375 "tig_ER", // Tigre (Eritrea)
376 "tk_TM", // Turkmen (Turkmenistan)
377 "tl_PH", // Tagalog (Philippines)
378 "tn_ZA", // Tswana (South Africa)
379 "tr", // Turkish
380 "tr_CY", // Turkish (Cyprus)
381 "tr_TR", // Turkish (Turkey)
382 "ts_ZA", // Tsonga (South Africa)
383 "tt_RU", // Tatar (Russia)
384 "ug_CN", // Uighur (China)
385 "uk", // Ukrainian
386 "uk_UA", // Ukrainian (Ukraine)
387 "unm_US", // Unami (United States)
388 "ur", // Urdu
389 "ur_IN", // Urdu (India)
390 "ur_PK", // Urdu (Pakistan)
391 "uz", // Uzbek
392 "uz_UZ", // Uzbek (Uzbekistan)
393 "ve_ZA", // Venda (South Africa)
394 "vi", // Vietnamese
395 "vi_VN", // Vietnamese (Vietnam)
396 "wa_BE", // Walloon (Belgium)
397 "wae_CH", // Walser (Switzerland)
398 "wal_ET", // Wolaytta (Ethiopia)
399 "wo_SN", // Wolof (Senegal)
400 "xh_ZA", // Xhosa (South Africa)
401 "yi_US", // Yiddish (United States)
402 "yo_NG", // Yoruba (Nigeria)
403 "yue_HK", // Yue Chinese (Hong Kong)
404 "zh", // Chinese
405 "zh_CN", // Chinese (China)
406 "zh_HK", // Chinese (Hong Kong)
407 "zh_SG", // Chinese (Singapore)
408 "zh_TW", // Chinese (Taiwan)
409 "zu_ZA", // Zulu (South Africa)
410 0
411 };
412
413 static const char *locale_names[] = {
414 "Afar",
415 "Afar (Djibouti)",
416 "Afar (Eritrea)",
417 "Afar (Ethiopia)",
418 "Afrikaans",
419 "Afrikaans (South Africa)",
420 "Aguaruna (Peru)",
421 "Akan (Ghana)",
422 "Amharic (Ethiopia)",
423 "Aragonese (Spain)",
424 "Angika (India)",
425 "Arabic",
426 "Arabic (United Arab Emirates)",
427 "Arabic (Bahrain)",
428 "Arabic (Algeria)",
429 "Arabic (Egypt)",
430 "Arabic (India)",
431 "Arabic (Iraq)",
432 "Arabic (Jordan)",
433 "Arabic (Kuwait)",
434 "Arabic (Lebanon)",
435 "Arabic (Libya)",
436 "Arabic (Morocco)",
437 "Arabic (Oman)",
438 "Arabic (Qatar)",
439 "Arabic (Saudi Arabia)",
440 "Arabic (Sudan)",
441 "Arabic (South Soudan)",
442 "Arabic (Syria)",
443 "Arabic (Tunisia)",
444 "Arabic (Yemen)",
445 "Assamese (India)",
446 "Asturian (Spain)",
447 "Southern Aymara (Peru)",
448 "Aymara (Peru)",
449 "Azerbaijani (Azerbaijan)",
450 "Belarusian",
451 "Belarusian (Belarus)",
452 "Bemba (Zambia)",
453 "Berber languages (Algeria)",
454 "Berber languages (Morocco)",
455 "Bulgarian",
456 "Bulgarian (Bulgaria)",
457 "Bhili (India)",
458 "Bhojpuri (India)",
459 "Bislama (Tuvalu)",
460 "Bengali",
461 "Bengali (Bangladesh)",
462 "Bengali (India)",
463 "Tibetan",
464 "Tibetan (China)",
465 "Tibetan (India)",
466 "Breton (France)",
467 "Bodo (India)",
468 "Bosnian (Bosnia and Herzegovina)",
469 "Bilin (Eritrea)",
470 "Catalan",
471 "Catalan (Andorra)",
472 "Catalan (Spain)",
473 "Catalan (France)",
474 "Catalan (Italy)",
475 "Chechen (Russia)",
476 "Cherokee (United States)",
477 "Mandarin Chinese (Taiwan)",
478 "Crimean Tatar (Ukraine)",
479 "Kashubian (Poland)",
480 "Czech",
481 "Czech (Czech Republic)",
482 "Chuvash (Russia)",
483 "Welsh (United Kingdom)",
484 "Danish",
485 "Danish (Denmark)",
486 "German",
487 "German (Austria)",
488 "German (Belgium)",
489 "German (Switzerland)",
490 "German (Germany)",
491 "German (Italy)",
492 "German (Luxembourg)",
493 "Dogri (India)",
494 "Dhivehi (Maldives)",
495 "Dzongkha (Bhutan)",
496 "Greek",
497 "Greek (Cyprus)",
498 "Greek (Greece)",
499 "English",
500 "English (Antigua and Barbuda)",
501 "English (Australia)",
502 "English (Botswana)",
503 "English (Canada)",
504 "English (Denmark)",
505 "English (United Kingdom)",
506 "English (Hong Kong)",
507 "English (Ireland)",
508 "English (Israel)",
509 "English (India)",
510 "English (Nigeria)",
511 "English (New Zealand)",
512 "English (Philippines)",
513 "English (Singapore)",
514 "English (United States)",
515 "English (South Africa)",
516 "English (Zambia)",
517 "English (Zimbabwe)",
518 "Esperanto",
519 "Spanish",
520 "Spanish (Argentina)",
521 "Spanish (Bolivia)",
522 "Spanish (Chile)",
523 "Spanish (Colombia)",
524 "Spanish (Costa Rica)",
525 "Spanish (Cuba)",
526 "Spanish (Dominican Republic)",
527 "Spanish (Ecuador)",
528 "Spanish (Spain)",
529 "Spanish (Guatemala)",
530 "Spanish (Honduras)",
531 "Spanish (Mexico)",
532 "Spanish (Nicaragua)",
533 "Spanish (Panama)",
534 "Spanish (Peru)",
535 "Spanish (Puerto Rico)",
536 "Spanish (Paraguay)",
537 "Spanish (El Salvador)",
538 "Spanish (United States)",
539 "Spanish (Uruguay)",
540 "Spanish (Venezuela)",
541 "Estonian",
542 "Estonian (Estonia)",
543 "Basque",
544 "Basque (Spain)",
545 "Persian",
546 "Persian (Iran)",
547 "Fulah (Senegal)",
548 "Finnish",
549 "Finnish (Finland)",
550 "Filipino",
551 "Filipino (Philippines)",
552 "Faroese (Faroe Islands)",
553 "French",
554 "French (Belgium)",
555 "French (Canada)",
556 "French (Switzerland)",
557 "French (France)",
558 "French (Luxembourg)",
559 "Friulian (Italy)",
560 "Western Frisian (Germany)",
561 "Western Frisian (Netherlands)",
562 "Irish",
563 "Irish (Ireland)",
564 "Scottish Gaelic (United Kingdom)",
565 "Geez (Eritrea)",
566 "Geez (Ethiopia)",
567 "Galician (Spain)",
568 "Gujarati (India)",
569 "Manx (United Kingdom)",
570 "Hakka Chinese (Taiwan)",
571 "Hausa (Nigeria)",
572 "Hebrew",
573 "Hebrew (Israel)",
574 "Hindi",
575 "Hindi (India)",
576 "Chhattisgarhi (India)",
577 "Croatian",
578 "Croatian (Croatia)",
579 "Upper Sorbian (Germany)",
580 "Haitian (Haiti)",
581 "Hungarian",
582 "Hungarian (Hungary)",
583 "Huastec (Mexico)",
584 "Armenian (Armenia)",
585 "Interlingua (France)",
586 "Indonesian",
587 "Indonesian (Indonesia)",
588 "Igbo (Nigeria)",
589 "Inupiaq (Canada)",
590 "Icelandic",
591 "Icelandic (Iceland)",
592 "Italian",
593 "Italian (Switzerland)",
594 "Italian (Italy)",
595 "Inuktitut (Canada)",
596 "Japanese",
597 "Japanese (Japan)",
598 "Kabyle (Algeria)",
599 "Georgian",
600 "Georgian (Georgia)",
601 "Kazakh (Kazakhstan)",
602 "Kalaallisut (Greenland)",
603 "Central Khmer (Cambodia)",
604 "Kannada (India)",
605 "Konkani (India)",
606 "Korean",
607 "Korean (South Korea)",
608 "Kashmiri (India)",
609 "Kurdish",
610 "Kurdish (Turkey)",
611 "Cornish (United Kingdom)",
612 "Kirghiz (Kyrgyzstan)",
613 "Luxembourgish (Luxembourg)",
614 "Ganda (Uganda)",
615 "Limburgan (Belgium)",
616 "Limburgan (Netherlands)",
617 "Ligurian (Italy)",
618 "Lingala (Congo)",
619 "Lao (Laos)",
620 "Lithuanian",
621 "Lithuanian (Lithuania)",
622 "Latvian",
623 "Latvian (Latvia)",
624 "Literary Chinese (Taiwan)",
625 "Magahi (India)",
626 "Maithili (India)",
627 "Malagasy (Madagascar)",
628 "Marshallese (Marshall Islands)",
629 "Eastern Mari (Russia)",
630 "Māori",
631 "Māori (New Zealand)",
632 "Mískito (Nicaragua)",
633 "Macedonian",
634 "Macedonian (Macedonia)",
635 "Malayalam",
636 "Malayalam (India)",
637 "Manipuri (India)",
638 "Mongolian (Mongolia)",
639 "Marathi (India)",
640 "Malay",
641 "Malay (Malaysia)",
642 "Maltese",
643 "Maltese (Malta)",
644 "Burmese (Myanmar)",
645 "Erzya (Russia)",
646 "Nahuatl languages (Mexico)",
647 "Min Nan Chinese (Taiwan)",
648 "Norwegian Bokmål",
649 "Norwegian Bokmål (Norway)",
650 "Low German (Germany)",
651 "Low German (Netherlands)",
652 "Nepali (Nepal)",
653 "Central Nahuatl (Mexico)",
654 "Niuean (Niue)",
655 "Niuean (New Zealand)",
656 "Dutch",
657 "Dutch (Aruba)",
658 "Dutch (Belgium)",
659 "Dutch (Netherlands)",
660 "Norwegian Nynorsk",
661 "Norwegian Nynorsk (Norway)",
662 "South Ndebele (South Africa)",
663 "Pedi (South Africa)",
664 "Occitan (France)",
665 "Oromo",
666 "Oromo (Ethiopia)",
667 "Oromo (Kenya)",
668 "Oriya (India)",
669 "Ossetian (Russia)",
670 "Panjabi (India)",
671 "Papiamento",
672 "Papiamento (Netherlands Antilles)",
673 "Papiamento (Aruba)",
674 "Papiamento (Curaçao)",
675 "Panjabi (Pakistan)",
676 "Polish",
677 "Polish (Poland)",
678 "Pirate",
679 "Pushto (Afghanistan)",
680 "Portuguese",
681 "Portuguese (Brazil)",
682 "Portuguese (Portugal)",
683 "Ayacucho Quechua (Peru)",
684 "Cusco Quechua (Peru)",
685 "Rajasthani (India)",
686 "Romanian",
687 "Romanian (Romania)",
688 "Russian",
689 "Russian (Russia)",
690 "Russian (Ukraine)",
691 "Kinyarwanda (Rwanda)",
692 "Sanskrit (India)",
693 "Santali (India)",
694 "Sardinian (Italy)",
695 "Scots (Scotland)",
696 "Sindhi (India)",
697 "Northern Sami (Norway)",
698 "Samogitian (Lithuania)",
699 "Shuswap (Canada)",
700 "Sidamo (Ethiopia)",
701 "Sinhala",
702 "Sinhala (Sri Lanka)",
703 "Slovak",
704 "Slovak (Slovakia)",
705 "Slovenian",
706 "Slovenian (Slovenia)",
707 "Somali",
708 "Somali (Djibouti)",
709 "Somali (Ethiopia)",
710 "Somali (Kenya)",
711 "Somali (Somalia)",
712 "Songhai languages (Mali)",
713 "Albanian",
714 "Albanian (Albania)",
715 "Albanian (Kosovo)",
716 "Albanian (Macedonia)",
717 "Serbian",
718 "Serbian (Cyrillic)",
719 "Serbian (Latin)",
720 "Serbian (Montenegro)",
721 "Serbian (Serbia)",
722 "Swati (South Africa)",
723 "Southern Sotho (South Africa)",
724 "Swedish",
725 "Swedish (Finland)",
726 "Swedish (Sweden)",
727 "Swahili (Kenya)",
728 "Swahili (Tanzania)",
729 "Silesian (Poland)",
730 "Tamil",
731 "Tamil (India)",
732 "Tamil (Sri Lanka)",
733 "Tulu (India)",
734 "Telugu",
735 "Telugu (India)",
736 "Tajik (Tajikistan)",
737 "Chitwania Tharu (Nepal)",
738 "Thai",
739 "Thai (Thailand)",
740 "Tigrinya",
741 "Tigrinya (Eritrea)",
742 "Tigrinya (Ethiopia)",
743 "Tigre (Eritrea)",
744 "Turkmen (Turkmenistan)",
745 "Tagalog (Philippines)",
746 "Tswana (South Africa)",
747 "Turkish",
748 "Turkish (Cyprus)",
749 "Turkish (Turkey)",
750 "Tsonga (South Africa)",
751 "Tatar (Russia)",
752 "Uighur (China)",
753 "Ukrainian",
754 "Ukrainian (Ukraine)",
755 "Unami (United States)",
756 "Urdu",
757 "Urdu (India)",
758 "Urdu (Pakistan)",
759 "Uzbek",
760 "Uzbek (Uzbekistan)",
761 "Venda (South Africa)",
762 "Vietnamese",
763 "Vietnamese (Vietnam)",
764 "Walloon (Belgium)",
765 "Walser (Switzerland)",
766 "Wolaytta (Ethiopia)",
767 "Wolof (Senegal)",
768 "Xhosa (South Africa)",
769 "Yiddish (United States)",
770 "Yoruba (Nigeria)",
771 "Yue Chinese (Hong Kong)",
772 "Chinese",
773 "Chinese (China)",
774 "Chinese (Hong Kong)",
775 "Chinese (Singapore)",
776 "Chinese (Taiwan)",
777 "Zulu (South Africa)",
778 0
779 };
780
781 // Windows has some weird locale identifiers which do not honor the ISO 639-1
782 // standardized nomenclature. Whenever those don't conflict with existing ISO
783 // identifiers, we override them.
784 //
785 // Reference:
786 // - https://msdn.microsoft.com/en-us/library/windows/desktop/ms693062(v=vs.85).aspx
787
788 static const char *locale_renames[][2] = {
789 { "in", "id" }, // Indonesian
790 { "iw", "he" }, // Hebrew
791 { "no", "nb" }, // Norwegian Bokmål
792 { NULL, NULL }
793 };
794
795 ///////////////////////////////////////////////
796
_get_messages() const797 PoolVector<String> Translation::_get_messages() const {
798
799 PoolVector<String> msgs;
800 msgs.resize(translation_map.size() * 2);
801 int idx = 0;
802 for (const Map<StringName, StringName>::Element *E = translation_map.front(); E; E = E->next()) {
803
804 msgs.set(idx + 0, E->key());
805 msgs.set(idx + 1, E->get());
806 idx += 2;
807 }
808
809 return msgs;
810 }
811
_get_message_list() const812 PoolVector<String> Translation::_get_message_list() const {
813
814 PoolVector<String> msgs;
815 msgs.resize(translation_map.size());
816 int idx = 0;
817 for (const Map<StringName, StringName>::Element *E = translation_map.front(); E; E = E->next()) {
818
819 msgs.set(idx, E->key());
820 idx += 1;
821 }
822
823 return msgs;
824 }
825
_set_messages(const PoolVector<String> & p_messages)826 void Translation::_set_messages(const PoolVector<String> &p_messages) {
827
828 int msg_count = p_messages.size();
829 ERR_FAIL_COND(msg_count % 2);
830
831 PoolVector<String>::Read r = p_messages.read();
832
833 for (int i = 0; i < msg_count; i += 2) {
834
835 add_message(r[i + 0], r[i + 1]);
836 }
837 }
838
set_locale(const String & p_locale)839 void Translation::set_locale(const String &p_locale) {
840
841 String univ_locale = TranslationServer::standardize_locale(p_locale);
842
843 if (!TranslationServer::is_locale_valid(univ_locale)) {
844 String trimmed_locale = TranslationServer::get_language_code(univ_locale);
845
846 ERR_FAIL_COND_MSG(!TranslationServer::is_locale_valid(trimmed_locale), "Invalid locale: " + trimmed_locale + ".");
847
848 locale = trimmed_locale;
849 } else {
850 locale = univ_locale;
851 }
852
853 if (OS::get_singleton()->get_main_loop()) {
854 OS::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_TRANSLATION_CHANGED);
855 }
856 }
857
add_message(const StringName & p_src_text,const StringName & p_xlated_text)858 void Translation::add_message(const StringName &p_src_text, const StringName &p_xlated_text) {
859
860 translation_map[p_src_text] = p_xlated_text;
861 }
get_message(const StringName & p_src_text) const862 StringName Translation::get_message(const StringName &p_src_text) const {
863
864 const Map<StringName, StringName>::Element *E = translation_map.find(p_src_text);
865 if (!E)
866 return StringName();
867
868 return E->get();
869 }
870
erase_message(const StringName & p_src_text)871 void Translation::erase_message(const StringName &p_src_text) {
872
873 translation_map.erase(p_src_text);
874 }
875
get_message_list(List<StringName> * r_messages) const876 void Translation::get_message_list(List<StringName> *r_messages) const {
877
878 for (const Map<StringName, StringName>::Element *E = translation_map.front(); E; E = E->next()) {
879
880 r_messages->push_back(E->key());
881 }
882 }
883
get_message_count() const884 int Translation::get_message_count() const {
885
886 return translation_map.size();
887 };
888
_bind_methods()889 void Translation::_bind_methods() {
890
891 ClassDB::bind_method(D_METHOD("set_locale", "locale"), &Translation::set_locale);
892 ClassDB::bind_method(D_METHOD("get_locale"), &Translation::get_locale);
893 ClassDB::bind_method(D_METHOD("add_message", "src_message", "xlated_message"), &Translation::add_message);
894 ClassDB::bind_method(D_METHOD("get_message", "src_message"), &Translation::get_message);
895 ClassDB::bind_method(D_METHOD("erase_message", "src_message"), &Translation::erase_message);
896 ClassDB::bind_method(D_METHOD("get_message_list"), &Translation::_get_message_list);
897 ClassDB::bind_method(D_METHOD("get_message_count"), &Translation::get_message_count);
898 ClassDB::bind_method(D_METHOD("_set_messages"), &Translation::_set_messages);
899 ClassDB::bind_method(D_METHOD("_get_messages"), &Translation::_get_messages);
900
901 ADD_PROPERTY(PropertyInfo(Variant::POOL_STRING_ARRAY, "messages", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_messages", "_get_messages");
902 ADD_PROPERTY(PropertyInfo(Variant::STRING, "locale"), "set_locale", "get_locale");
903 }
904
Translation()905 Translation::Translation() :
906 locale("en") {
907 }
908
909 ///////////////////////////////////////////////
910
is_locale_valid(const String & p_locale)911 bool TranslationServer::is_locale_valid(const String &p_locale) {
912
913 const char **ptr = locale_list;
914
915 while (*ptr) {
916
917 if (*ptr == p_locale)
918 return true;
919 ptr++;
920 }
921
922 return false;
923 }
924
standardize_locale(const String & p_locale)925 String TranslationServer::standardize_locale(const String &p_locale) {
926
927 // Replaces '-' with '_' for macOS Sierra-style locales
928 String univ_locale = p_locale.replace("-", "_");
929
930 // Handles known non-ISO locale names used e.g. on Windows
931 int idx = 0;
932 while (locale_renames[idx][0] != NULL) {
933 if (locale_renames[idx][0] == univ_locale) {
934 univ_locale = locale_renames[idx][1];
935 break;
936 }
937 idx++;
938 }
939
940 return univ_locale;
941 }
942
get_language_code(const String & p_locale)943 String TranslationServer::get_language_code(const String &p_locale) {
944
945 ERR_FAIL_COND_V_MSG(p_locale.length() < 2, p_locale, "Invalid locale '" + p_locale + "'.");
946 // Most language codes are two letters, but some are three,
947 // so we have to look for a regional code separator ('_' or '-')
948 // to extract the left part.
949 // For example we get 'nah_MX' as input and should return 'nah'.
950 int split = p_locale.find("_");
951 if (split == -1) {
952 split = p_locale.find("-");
953 }
954 if (split == -1) { // No separator, so the locale is already only a language code.
955 return p_locale;
956 }
957 return p_locale.left(split);
958 }
959
set_locale(const String & p_locale)960 void TranslationServer::set_locale(const String &p_locale) {
961
962 String univ_locale = standardize_locale(p_locale);
963
964 if (!is_locale_valid(univ_locale)) {
965 String trimmed_locale = get_language_code(univ_locale);
966 print_verbose(vformat("Unsupported locale '%s', falling back to '%s'.", p_locale, trimmed_locale));
967
968 if (!is_locale_valid(trimmed_locale)) {
969 ERR_PRINTS(vformat("Unsupported locale '%s', falling back to 'en'.", trimmed_locale));
970 locale = "en";
971 } else {
972 locale = trimmed_locale;
973 }
974 } else {
975 locale = univ_locale;
976 }
977
978 if (OS::get_singleton()->get_main_loop()) {
979 OS::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_TRANSLATION_CHANGED);
980 }
981
982 ResourceLoader::reload_translation_remaps();
983 }
984
get_locale() const985 String TranslationServer::get_locale() const {
986
987 return locale;
988 }
989
get_locale_name(const String & p_locale) const990 String TranslationServer::get_locale_name(const String &p_locale) const {
991
992 if (!locale_name_map.has(p_locale)) return String();
993 return locale_name_map[p_locale];
994 }
995
get_loaded_locales() const996 Array TranslationServer::get_loaded_locales() const {
997 Array locales;
998 for (const Set<Ref<Translation> >::Element *E = translations.front(); E; E = E->next()) {
999
1000 const Ref<Translation> &t = E->get();
1001 ERR_FAIL_COND_V(t.is_null(), Array());
1002 String l = t->get_locale();
1003
1004 locales.push_back(l);
1005 }
1006
1007 return locales;
1008 }
1009
get_all_locales()1010 Vector<String> TranslationServer::get_all_locales() {
1011
1012 Vector<String> locales;
1013
1014 const char **ptr = locale_list;
1015
1016 while (*ptr) {
1017 locales.push_back(*ptr);
1018 ptr++;
1019 }
1020
1021 return locales;
1022 }
1023
get_all_locale_names()1024 Vector<String> TranslationServer::get_all_locale_names() {
1025
1026 Vector<String> locales;
1027
1028 const char **ptr = locale_names;
1029
1030 while (*ptr) {
1031 locales.push_back(String::utf8(*ptr));
1032 ptr++;
1033 }
1034
1035 return locales;
1036 }
1037
add_translation(const Ref<Translation> & p_translation)1038 void TranslationServer::add_translation(const Ref<Translation> &p_translation) {
1039
1040 translations.insert(p_translation);
1041 }
remove_translation(const Ref<Translation> & p_translation)1042 void TranslationServer::remove_translation(const Ref<Translation> &p_translation) {
1043
1044 translations.erase(p_translation);
1045 }
1046
clear()1047 void TranslationServer::clear() {
1048
1049 translations.clear();
1050 };
1051
translate(const StringName & p_message) const1052 StringName TranslationServer::translate(const StringName &p_message) const {
1053
1054 // Match given message against the translation catalog for the project locale.
1055
1056 if (!enabled)
1057 return p_message;
1058
1059 ERR_FAIL_COND_V_MSG(locale.length() < 2, p_message, "Could not translate message as configured locale '" + locale + "' is invalid.");
1060
1061 // Locale can be of the form 'll_CC', i.e. language code and regional code,
1062 // e.g. 'en_US', 'en_GB', etc. It might also be simply 'll', e.g. 'en'.
1063 // To find the relevant translation, we look for those with locale starting
1064 // with the language code, and then if any is an exact match for the long
1065 // form. If not found, we fall back to a near match (another locale with
1066 // same language code).
1067
1068 // Note: ResourceLoader::_path_remap reproduces this locale near matching
1069 // logic, so be sure to propagate changes there when changing things here.
1070
1071 StringName res;
1072 String lang = get_language_code(locale);
1073 bool near_match = false;
1074
1075 for (const Set<Ref<Translation> >::Element *E = translations.front(); E; E = E->next()) {
1076 const Ref<Translation> &t = E->get();
1077 ERR_FAIL_COND_V(t.is_null(), p_message);
1078 String l = t->get_locale();
1079
1080 bool exact_match = (l == locale);
1081 if (!exact_match) {
1082 if (near_match) {
1083 continue; // Only near-match once, but keep looking for exact matches.
1084 }
1085 if (get_language_code(l) != lang) {
1086 continue; // Language code does not match.
1087 }
1088 }
1089
1090 StringName r = t->get_message(p_message);
1091 if (!r) {
1092 continue;
1093 }
1094 res = r;
1095
1096 if (exact_match) {
1097 break;
1098 } else {
1099 near_match = true;
1100 }
1101 }
1102
1103 if (!res && fallback.length() >= 2) {
1104 // Try again with the fallback locale.
1105 String fallback_lang = get_language_code(fallback);
1106 near_match = false;
1107
1108 for (const Set<Ref<Translation> >::Element *E = translations.front(); E; E = E->next()) {
1109 const Ref<Translation> &t = E->get();
1110 ERR_FAIL_COND_V(t.is_null(), p_message);
1111 String l = t->get_locale();
1112
1113 bool exact_match = (l == fallback);
1114 if (!exact_match) {
1115 if (near_match) {
1116 continue; // Only near-match once, but keep looking for exact matches.
1117 }
1118 if (get_language_code(l) != fallback_lang) {
1119 continue; // Language code does not match.
1120 }
1121 }
1122
1123 StringName r = t->get_message(p_message);
1124 if (!r) {
1125 continue;
1126 }
1127 res = r;
1128
1129 if (exact_match) {
1130 break;
1131 } else {
1132 near_match = true;
1133 }
1134 }
1135 }
1136
1137 if (!res) {
1138 return p_message;
1139 }
1140
1141 return res;
1142 }
1143
1144 TranslationServer *TranslationServer::singleton = NULL;
1145
_load_translations(const String & p_from)1146 bool TranslationServer::_load_translations(const String &p_from) {
1147
1148 if (ProjectSettings::get_singleton()->has_setting(p_from)) {
1149 PoolVector<String> translations = ProjectSettings::get_singleton()->get(p_from);
1150
1151 int tcount = translations.size();
1152
1153 if (tcount) {
1154 PoolVector<String>::Read r = translations.read();
1155
1156 for (int i = 0; i < tcount; i++) {
1157
1158 Ref<Translation> tr = ResourceLoader::load(r[i]);
1159 if (tr.is_valid())
1160 add_translation(tr);
1161 }
1162 }
1163 return true;
1164 }
1165
1166 return false;
1167 }
1168
setup()1169 void TranslationServer::setup() {
1170
1171 String test = GLOBAL_DEF("locale/test", "");
1172 test = test.strip_edges();
1173 if (test != "")
1174 set_locale(test);
1175 else
1176 set_locale(OS::get_singleton()->get_locale());
1177 fallback = GLOBAL_DEF("locale/fallback", "en");
1178 #ifdef TOOLS_ENABLED
1179
1180 {
1181 String options = "";
1182 int idx = 0;
1183 while (locale_list[idx]) {
1184 if (idx > 0)
1185 options += ",";
1186 options += locale_list[idx];
1187 idx++;
1188 }
1189 ProjectSettings::get_singleton()->set_custom_property_info("locale/fallback", PropertyInfo(Variant::STRING, "locale/fallback", PROPERTY_HINT_ENUM, options));
1190 }
1191 #endif
1192 //load translations
1193 }
1194
set_tool_translation(const Ref<Translation> & p_translation)1195 void TranslationServer::set_tool_translation(const Ref<Translation> &p_translation) {
1196 tool_translation = p_translation;
1197 }
1198
tool_translate(const StringName & p_message) const1199 StringName TranslationServer::tool_translate(const StringName &p_message) const {
1200
1201 if (tool_translation.is_valid()) {
1202 StringName r = tool_translation->get_message(p_message);
1203
1204 if (r) {
1205 return r;
1206 }
1207 }
1208
1209 return p_message;
1210 }
1211
_bind_methods()1212 void TranslationServer::_bind_methods() {
1213
1214 ClassDB::bind_method(D_METHOD("set_locale", "locale"), &TranslationServer::set_locale);
1215 ClassDB::bind_method(D_METHOD("get_locale"), &TranslationServer::get_locale);
1216
1217 ClassDB::bind_method(D_METHOD("get_locale_name", "locale"), &TranslationServer::get_locale_name);
1218
1219 ClassDB::bind_method(D_METHOD("translate", "message"), &TranslationServer::translate);
1220
1221 ClassDB::bind_method(D_METHOD("add_translation", "translation"), &TranslationServer::add_translation);
1222 ClassDB::bind_method(D_METHOD("remove_translation", "translation"), &TranslationServer::remove_translation);
1223
1224 ClassDB::bind_method(D_METHOD("clear"), &TranslationServer::clear);
1225
1226 ClassDB::bind_method(D_METHOD("get_loaded_locales"), &TranslationServer::get_loaded_locales);
1227 }
1228
load_translations()1229 void TranslationServer::load_translations() {
1230
1231 String locale = get_locale();
1232 _load_translations("locale/translations"); //all
1233 _load_translations("locale/translations_" + locale.substr(0, 2));
1234
1235 if (locale.substr(0, 2) != locale) {
1236 _load_translations("locale/translations_" + locale);
1237 }
1238 }
1239
TranslationServer()1240 TranslationServer::TranslationServer() :
1241 locale("en"),
1242 enabled(true) {
1243 singleton = this;
1244
1245 for (int i = 0; locale_list[i]; ++i) {
1246
1247 locale_name_map.insert(locale_list[i], String::utf8(locale_names[i]));
1248 }
1249 }
1250