translation.cpp 36 KB

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