GoogleLanguages.cs 39 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648
  1. using System;
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4. namespace I2.Loc
  5. {
  6. public enum ePluralType { Zero, One, Two, Few, Many, Plural }
  7. public static class GoogleLanguages
  8. {
  9. public static string GetLanguageCode(string Filter, bool ShowWarnings = false)
  10. {
  11. if (string.IsNullOrEmpty(Filter))
  12. return string.Empty;
  13. string[] Filters = Filter.ToLowerInvariant().Split(" /(),".ToCharArray());
  14. foreach (var kvp in mLanguageDef)
  15. if (LanguageMatchesFilter(kvp.Key, Filters))
  16. return kvp.Value.Code;
  17. if (ShowWarnings)
  18. Debug.Log($"Language '{Filter}' not recognized. Please, add the language code to GoogleTranslation.cs");
  19. return string.Empty;
  20. }
  21. public static List<string> GetLanguagesForDropdown(string Filter, string CodesToExclude)
  22. {
  23. string[] Filters = Filter.ToLowerInvariant().Split(" /(),".ToCharArray());
  24. List<string> Languages = new List<string>();
  25. foreach (var kvp in mLanguageDef)
  26. if (string.IsNullOrEmpty(Filter) || LanguageMatchesFilter(kvp.Key, Filters))
  27. {
  28. string code = string.Concat("[" + kvp.Value.Code + "]");
  29. if (!CodesToExclude.Contains(code))
  30. Languages.Add(kvp.Key + " " + code);
  31. }
  32. // Add headers to variants (e.g. "English/English" before all English variants
  33. for (int i = Languages.Count - 2; i >= 0; --i)
  34. {
  35. string Prefix = Languages[i].Substring(0, Languages[i].IndexOf(" ["));
  36. if (Languages[i + 1].StartsWith(Prefix, StringComparison.Ordinal))
  37. {
  38. Languages[i] = Prefix + "/" + Languages[i];
  39. Languages.Insert(i + 1, Prefix + "/");
  40. }
  41. }
  42. return Languages;
  43. }
  44. // "Engl Unit" matches "English/United States"
  45. static bool LanguageMatchesFilter(string Language, string[] Filters)
  46. {
  47. Language = Language.ToLowerInvariant();
  48. for (int i = 0, imax = Filters.Length; i < imax; ++i)
  49. if (Filters[i] != "")
  50. {
  51. if (!Language.Contains(Filters[i].ToLower()))
  52. return false;
  53. Language = Language.Remove(Language.IndexOf(Filters[i], StringComparison.Ordinal), Filters[i].Length);
  54. }
  55. return true;
  56. }
  57. // "Arabic/Algeria [ar-XX]" returns "Arabic (Algeria)"
  58. // "English/English [en]" returns "English"
  59. public static string GetFormatedLanguageName(string Language)
  60. {
  61. string BaseLanguage = string.Empty;
  62. //-- Remove code --------
  63. int Index = Language.IndexOf(" [", StringComparison.Ordinal);
  64. if (Index > 0)
  65. Language = Language.Substring(0, Index);
  66. //-- Check for main language: "English/English [en]" returns "English" -----------
  67. Index = Language.IndexOf('/');
  68. if (Index > 0)
  69. {
  70. BaseLanguage = Language.Substring(0, Index);
  71. if (Language == BaseLanguage + "/" + BaseLanguage)
  72. return BaseLanguage;
  73. //-- Convert variants into right format
  74. Language = Language.Replace("/", " (") + ")";
  75. }
  76. return Language;
  77. }
  78. // English British -> "English Canada [en-CA]"
  79. public static string GetCodedLanguage(string Language, string code)
  80. {
  81. string DefaultCode = GetLanguageCode(Language);
  82. if (string.Compare(code, DefaultCode, StringComparison.OrdinalIgnoreCase) == 0)
  83. return Language;
  84. return string.Concat(Language, " [", code, "]");
  85. }
  86. // "English Canada [en-CA]" -> "English Canada", "en-CA"
  87. public static void UnPackCodeFromLanguageName(string CodedLanguage, out string Language, out string code)
  88. {
  89. if (string.IsNullOrEmpty(CodedLanguage))
  90. {
  91. Language = string.Empty;
  92. code = string.Empty;
  93. return;
  94. }
  95. int Index = CodedLanguage.IndexOf("[", StringComparison.Ordinal);
  96. if (Index < 0)
  97. {
  98. Language = CodedLanguage;
  99. code = GetLanguageCode(Language);
  100. }
  101. else
  102. {
  103. Language = CodedLanguage.Substring(0, Index).Trim();
  104. code = CodedLanguage.Substring(Index + 1, CodedLanguage.IndexOf("]", Index, StringComparison.Ordinal) - Index - 1);
  105. }
  106. }
  107. public static string GetGoogleLanguageCode(string InternationalCode)
  108. {
  109. foreach (var kvp in mLanguageDef)
  110. if (InternationalCode == kvp.Value.Code)
  111. {
  112. if (kvp.Value.GoogleCode == "-")
  113. return null;
  114. return !string.IsNullOrEmpty(kvp.Value.GoogleCode) ? kvp.Value.GoogleCode : InternationalCode;
  115. }
  116. return InternationalCode;
  117. }
  118. public static string GetLanguageName(string code, bool useParenthesesForRegion=false, bool allowDiscardRegion=true)
  119. {
  120. foreach (var kvp in mLanguageDef)
  121. if (code == kvp.Value.Code)
  122. {
  123. var langName = kvp.Key;
  124. if (useParenthesesForRegion)
  125. {
  126. int idx = langName.IndexOf('/');
  127. if (idx > 0)
  128. langName = langName.Substring(0, idx) + " (" + langName.Substring(idx + 1) + ")";
  129. }
  130. return langName;
  131. }
  132. if (allowDiscardRegion)
  133. {
  134. int iCode = code.IndexOf("-", StringComparison.Ordinal);
  135. if (iCode > 0)
  136. return GetLanguageName(code.Substring(0,iCode), useParenthesesForRegion, false);
  137. }
  138. return null;
  139. }
  140. public static List<string> GetAllInternationalCodes()
  141. {
  142. var set = new HashSet<string>(StringComparer.Ordinal);
  143. foreach (var kvp in mLanguageDef)
  144. set.Add(kvp.Value.Code);
  145. return new List<string>(set);
  146. }
  147. public static bool LanguageCode_HasJoinedWord(string languageCode)
  148. {
  149. foreach (var kvp in mLanguageDef)
  150. if (languageCode == kvp.Value.GoogleCode || languageCode==kvp.Value.Code )
  151. return kvp.Value.HasJoinedWords;
  152. return false;
  153. }
  154. public struct LanguageCodeDef
  155. {
  156. public string Code; // Language International Code
  157. public string GoogleCode; // Google Translator doesn't support all languages, this is the code of closest supported language
  158. public bool HasJoinedWords; // Some languages (e.g. Chinese, Japanese and Thai) don't add spaces to their words (all characters are placed toguether)
  159. public int PluralRule;
  160. }
  161. public static Dictionary<string, LanguageCodeDef> mLanguageDef = new Dictionary<string, LanguageCodeDef>(StringComparer.Ordinal)
  162. {
  163. /**/{"Abkhazian", new LanguageCodeDef {PluralRule=1, Code="ab", GoogleCode="-"}},
  164. /**/{"Afar", new LanguageCodeDef {PluralRule=1, Code="aa", GoogleCode="-"}},
  165. {"Afrikaans", new LanguageCodeDef {PluralRule=1, Code="af"}},
  166. /**/{"Akan", new LanguageCodeDef {PluralRule=1, Code="ak", GoogleCode="-"}},
  167. {"Albanian", new LanguageCodeDef {PluralRule=1, Code="sq"}},
  168. /**/{"Amharic", new LanguageCodeDef {PluralRule=1, Code="am"}},
  169. {"Arabic", new LanguageCodeDef {PluralRule=11, Code="ar"}},
  170. {"Arabic/Algeria", new LanguageCodeDef {PluralRule=11, Code="ar-DZ", GoogleCode="ar"}},
  171. {"Arabic/Bahrain", new LanguageCodeDef {PluralRule=11, Code="ar-BH", GoogleCode="ar"}},
  172. {"Arabic/Egypt", new LanguageCodeDef {PluralRule=11, Code="ar-EG", GoogleCode="ar"}},
  173. {"Arabic/Iraq", new LanguageCodeDef {PluralRule=11, Code="ar-IQ", GoogleCode="ar"}},
  174. {"Arabic/Jordan", new LanguageCodeDef {PluralRule=11, Code="ar-JO", GoogleCode="ar"}},
  175. {"Arabic/Kuwait", new LanguageCodeDef {PluralRule=11, Code="ar-KW", GoogleCode="ar"}},
  176. {"Arabic/Lebanon", new LanguageCodeDef {PluralRule=11, Code="ar-LB", GoogleCode="ar"}},
  177. {"Arabic/Libya", new LanguageCodeDef {PluralRule=11, Code="ar-LY", GoogleCode="ar"}},
  178. {"Arabic/Morocco", new LanguageCodeDef {PluralRule=11, Code="ar-MA", GoogleCode="ar"}},
  179. {"Arabic/Oman", new LanguageCodeDef {PluralRule=11, Code="ar-OM", GoogleCode="ar"}},
  180. {"Arabic/Qatar", new LanguageCodeDef {PluralRule=11, Code="ar-QA", GoogleCode="ar"}},
  181. {"Arabic/Saudi Arabia", new LanguageCodeDef {PluralRule=11, Code="ar-SA", GoogleCode="ar"}},
  182. {"Arabic/Syria", new LanguageCodeDef {PluralRule=11, Code="ar-SY", GoogleCode="ar"}},
  183. {"Arabic/Tunisia", new LanguageCodeDef {PluralRule=11, Code="ar-TN", GoogleCode="ar"}},
  184. {"Arabic/U.A.E.", new LanguageCodeDef {PluralRule=11, Code="ar-AE", GoogleCode="ar"}},
  185. {"Arabic/Yemen", new LanguageCodeDef {PluralRule=11, Code="ar-YE", GoogleCode="ar"}},
  186. /**/{"Aragonese", new LanguageCodeDef {PluralRule=1, Code="an", GoogleCode="-"}},
  187. {"Armenian", new LanguageCodeDef {PluralRule=1, Code="hy"}},
  188. /**/{"Assamese", new LanguageCodeDef {PluralRule=1, Code="as", GoogleCode="-"}},
  189. /**/{"Avaric", new LanguageCodeDef {PluralRule=1, Code="av", GoogleCode="-"}},
  190. /**/{"Avestan", new LanguageCodeDef {PluralRule=1, Code="ae", GoogleCode="-"}},
  191. /**/{"Aymara", new LanguageCodeDef {PluralRule=1, Code="ay", GoogleCode="-"}},
  192. {"Azerbaijani", new LanguageCodeDef {PluralRule=1, Code="az"}},
  193. /**/{"Bambara", new LanguageCodeDef {PluralRule=1, Code="bm", GoogleCode="-"}},
  194. /**/{"Bashkir", new LanguageCodeDef {PluralRule=1, Code="ba", GoogleCode="-"}},
  195. {"Basque", new LanguageCodeDef {PluralRule=1, Code="eu"}},
  196. {"Basque/Spain", new LanguageCodeDef {PluralRule=1, Code="eu-ES", GoogleCode="eu"}},
  197. {"Belarusian", new LanguageCodeDef {PluralRule=6, Code="be"}},
  198. /**/{"Bengali", new LanguageCodeDef {PluralRule=1, Code="bn"}},
  199. /**/{"Bihari", new LanguageCodeDef {PluralRule=1, Code="bh", GoogleCode="-"}},
  200. /**/{"Bislama", new LanguageCodeDef {PluralRule=1, Code="bi", GoogleCode="-"}},
  201. {"Bosnian", new LanguageCodeDef {PluralRule=6, Code="bs"}},
  202. /**/{"Breton", new LanguageCodeDef {PluralRule=1, Code="br", GoogleCode="-"}},
  203. {"Bulgariaa", new LanguageCodeDef {PluralRule=1, Code="bg"}},
  204. /**/{"Burmese", new LanguageCodeDef {PluralRule=1, Code="my"}},
  205. {"Catalan", new LanguageCodeDef {PluralRule=1, Code="ca"}},
  206. /**/{"Chamorro", new LanguageCodeDef {PluralRule=1, Code="ch", GoogleCode="-"}},
  207. /**/{"Chechen", new LanguageCodeDef {PluralRule=1, Code="ce", GoogleCode="-"}},
  208. /**/{"Chichewa", new LanguageCodeDef {PluralRule=1, Code="ny"}},
  209. {"Chinese", new LanguageCodeDef {PluralRule=0, Code="zh", GoogleCode="zh-CN", HasJoinedWords=true}},
  210. {"Chinese/Hong Kong", new LanguageCodeDef {PluralRule=0, Code="zh-HK", GoogleCode="zh-TW", HasJoinedWords=true}},
  211. {"Chinese/Macau", new LanguageCodeDef {PluralRule=0, Code="zh-MO", GoogleCode="zh-CN", HasJoinedWords=true}},
  212. {"Chinese/PRC", new LanguageCodeDef {PluralRule=0, Code="zh-CN", GoogleCode="zh-CN", HasJoinedWords=true}},
  213. {"Chinese/Simplified", new LanguageCodeDef {PluralRule=0, Code="zh-CN", GoogleCode="zh-CN", HasJoinedWords=true}},
  214. {"Chinese/Singapore", new LanguageCodeDef {PluralRule=0, Code="zh-SG", GoogleCode="zh-CN", HasJoinedWords=true}},
  215. {"Chinese/Taiwan", new LanguageCodeDef {PluralRule=0, Code="zh-TW", GoogleCode="zh-TW", HasJoinedWords=true}},
  216. {"Chinese/Traditional", new LanguageCodeDef {PluralRule=0, Code="zh-TW", GoogleCode="zh-TW", HasJoinedWords=true}},
  217. /**/{"Chuvash", new LanguageCodeDef {PluralRule=1, Code="cv", GoogleCode="-"}},
  218. /**/{"Cornish", new LanguageCodeDef {PluralRule=1, Code="kw", GoogleCode="-"}}, // Check plural
  219. /**/{"Corsican", new LanguageCodeDef {PluralRule=1, Code="co"}},
  220. /**/{"Cree", new LanguageCodeDef {PluralRule=1, Code="cr", GoogleCode="-"}},
  221. {"Croatian", new LanguageCodeDef {PluralRule=6, Code="hr"}},
  222. {"Croatian/Bosnia and Herzegovina", new LanguageCodeDef {PluralRule=5, Code="hr-BA", GoogleCode="hr"}},
  223. {"Czech", new LanguageCodeDef {PluralRule=7, Code="cs"}},
  224. {"Danish", new LanguageCodeDef {PluralRule=1, Code="da"}},
  225. /**/{"Divehi", new LanguageCodeDef {PluralRule=1, Code="dv", GoogleCode="-"}},
  226. {"Dutch", new LanguageCodeDef {PluralRule=1, Code="nl"}},
  227. {"Dutch/Belgium", new LanguageCodeDef {PluralRule=1, Code="nl-BE", GoogleCode="nl"}},
  228. {"Dutch/Netherlands", new LanguageCodeDef {PluralRule=1, Code="nl-NL", GoogleCode="nl"}},
  229. /**/{"Dzongkha", new LanguageCodeDef {PluralRule=1, Code="dz", GoogleCode="-"}},
  230. {"English", new LanguageCodeDef {PluralRule=1, Code="en"}},
  231. {"English/Australia", new LanguageCodeDef {PluralRule=1, Code="en-AU", GoogleCode="en"}},
  232. {"English/Belize", new LanguageCodeDef {PluralRule=1, Code="en-BZ", GoogleCode="en"}},
  233. {"English/Canada", new LanguageCodeDef {PluralRule=1, Code="en-CA", GoogleCode="en"}},
  234. {"English/Caribbean", new LanguageCodeDef {PluralRule=1, Code="en-CB", GoogleCode="en"}},
  235. {"English/Ireland", new LanguageCodeDef {PluralRule=1, Code="en-IE", GoogleCode="en"}},
  236. {"English/Jamaica", new LanguageCodeDef {PluralRule=1, Code="en-JM", GoogleCode="en"}},
  237. {"English/New Zealand", new LanguageCodeDef {PluralRule=1, Code="en-NZ", GoogleCode="en"}},
  238. {"English/Republic of the Philippines", new LanguageCodeDef {PluralRule=1, Code="en-PH", GoogleCode="en"}},
  239. {"English/South Africa",new LanguageCodeDef {PluralRule=1, Code="en-ZA", GoogleCode="en"}},
  240. {"English/Trinidad", new LanguageCodeDef {PluralRule=1, Code="en-TT", GoogleCode="en"}},
  241. {"English/United Kingdom",new LanguageCodeDef {PluralRule=1, Code="en-GB", GoogleCode="en"}},
  242. {"English/United States",new LanguageCodeDef {PluralRule=1, Code="en-US", GoogleCode="en"}},
  243. {"English/Zimbabwe", new LanguageCodeDef {PluralRule=1, Code="en-ZW", GoogleCode="en"}},
  244. {"Esperanto", new LanguageCodeDef {PluralRule=1, Code="eo"}},
  245. {"Estonian", new LanguageCodeDef {PluralRule=1, Code="et"}},
  246. /**/{"Ewe", new LanguageCodeDef {PluralRule=1, Code="ee", GoogleCode="-"}},
  247. {"Faeroese", new LanguageCodeDef {PluralRule=1, Code="fo", GoogleCode="-"}},
  248. /**/{"Fijian", new LanguageCodeDef {PluralRule=1, Code="fj", GoogleCode="-"}},
  249. //{"Filipino", new LanguageCodeDef(){PluralRule=2, Code="tl"}},
  250. {"Finnish", new LanguageCodeDef {PluralRule=1, Code="fi"}},
  251. {"French", new LanguageCodeDef {PluralRule=2, Code="fr"}},
  252. {"French/Belgium", new LanguageCodeDef {PluralRule=2, Code="fr-BE", GoogleCode="fr"}},
  253. {"French/Canada", new LanguageCodeDef {PluralRule=2, Code="fr-CA", GoogleCode="fr"}},
  254. {"French/France", new LanguageCodeDef {PluralRule=2, Code="fr-FR", GoogleCode="fr"}},
  255. {"French/Luxembourg", new LanguageCodeDef {PluralRule=2, Code="fr-LU", GoogleCode="fr"}},
  256. {"French/Principality of Monaco", new LanguageCodeDef {PluralRule=2, Code="fr-MC", GoogleCode="fr"}},
  257. {"French/Switzerland", new LanguageCodeDef {PluralRule=2, Code="fr-CH", GoogleCode="fr"}},
  258. /**/{"Fulah", new LanguageCodeDef {PluralRule=1, Code="ff", GoogleCode="-"}},
  259. {"Galician", new LanguageCodeDef {PluralRule=1, Code="gl"}},
  260. {"Galician/Spain", new LanguageCodeDef {PluralRule=1, Code="gl-ES", GoogleCode="gl"}},
  261. {"Georgian", new LanguageCodeDef {PluralRule=0, Code="ka"}},
  262. {"German", new LanguageCodeDef {PluralRule=1, Code="de"}},
  263. {"German/Austria", new LanguageCodeDef {PluralRule=1, Code="de-AT", GoogleCode="de"}},
  264. {"German/Germany", new LanguageCodeDef {PluralRule=1, Code="de-DE", GoogleCode="de"}},
  265. {"German/Liechtenstein",new LanguageCodeDef {PluralRule=1, Code="de-LI", GoogleCode="de"}},
  266. {"German/Luxembourg", new LanguageCodeDef {PluralRule=1, Code="de-LU", GoogleCode="de"}},
  267. {"German/Switzerland", new LanguageCodeDef {PluralRule=1, Code="de-CH", GoogleCode="de"}},
  268. {"Greek", new LanguageCodeDef {PluralRule=1, Code="el"}},
  269. /**/{"Guaraní", new LanguageCodeDef {PluralRule=1, Code="gn", GoogleCode="-"}},
  270. {"Gujarati", new LanguageCodeDef {PluralRule=1, Code="gu"}},
  271. /**/{"Haitian", new LanguageCodeDef {PluralRule=1, Code="ht"}},
  272. /**/{"Hausa", new LanguageCodeDef {PluralRule=1, Code="ha"}},
  273. {"Hebrew", new LanguageCodeDef {PluralRule=1, Code="he", GoogleCode="iw"}},
  274. /**/{"Herero", new LanguageCodeDef {PluralRule=1, Code="hz", GoogleCode="-"}},
  275. {"Hindi", new LanguageCodeDef {PluralRule=1, Code="hi"}},
  276. /**/{"Hiri Motu", new LanguageCodeDef {PluralRule=1, Code="ho", GoogleCode="-"}},
  277. {"Hungarian", new LanguageCodeDef {PluralRule=1, Code="hu"}},
  278. /**/{"Interlingua", new LanguageCodeDef {PluralRule=1, Code="ia", GoogleCode="-"}},
  279. {"Indonesian", new LanguageCodeDef {PluralRule=0, Code="id"}},
  280. /**/{"Interlingue", new LanguageCodeDef {PluralRule=1, Code="ie", GoogleCode="-"}},
  281. {"Irish", new LanguageCodeDef {PluralRule=10, Code="ga"}},
  282. /**/{"Igbo", new LanguageCodeDef {PluralRule=1, Code="ig"}},
  283. /**/{"Inupiaq", new LanguageCodeDef {PluralRule=1, Code="ik", GoogleCode="-"}},
  284. /**/{"Ido", new LanguageCodeDef {PluralRule=1, Code="io", GoogleCode="-"}},
  285. {"Icelandic", new LanguageCodeDef {PluralRule=14, Code="is"}},
  286. {"Italian", new LanguageCodeDef {PluralRule=1, Code="it"}},
  287. {"Italian/Italy", new LanguageCodeDef {PluralRule=1, Code="it-IT", GoogleCode="it"}},
  288. {"Italian/Switzerland", new LanguageCodeDef {PluralRule=1, Code="it-CH", GoogleCode="it"}},
  289. /**/{"Inuktitut", new LanguageCodeDef {PluralRule=1, Code="iu", GoogleCode="-"}},
  290. {"Japanese", new LanguageCodeDef {PluralRule=0, Code="ja", HasJoinedWords=true}},
  291. /**/{"Javanese", new LanguageCodeDef {PluralRule=1, Code="jv"}},
  292. /**/{"Kalaallisut", new LanguageCodeDef {PluralRule=1, Code="kl", GoogleCode="-"}},
  293. {"Kannada", new LanguageCodeDef {PluralRule=1, Code="kn"}},
  294. /**/{"Kanuri", new LanguageCodeDef {PluralRule=1, Code="kr", GoogleCode="-"}},
  295. /**/{"Kashmiri", new LanguageCodeDef {PluralRule=1, Code="ks", GoogleCode="-"}},
  296. {"Kazakh", new LanguageCodeDef {PluralRule=1, Code="kk"}},
  297. /**/{"Central Khmer", new LanguageCodeDef {PluralRule=1, Code="km"}},
  298. /**/{"Kikuyu", new LanguageCodeDef {PluralRule=1, Code="ki", GoogleCode="-"}},
  299. /**/{"Kinyarwanda", new LanguageCodeDef {PluralRule=1, Code="rw", GoogleCode="-"}},
  300. /**/{"Kirghiz", new LanguageCodeDef {PluralRule=1, Code="ky"}},
  301. /**/{"Komi", new LanguageCodeDef {PluralRule=1, Code="kv", GoogleCode="-"}},
  302. /**/{"Kongo", new LanguageCodeDef {PluralRule=1, Code="kg", GoogleCode="-"}},
  303. {"Korean", new LanguageCodeDef {PluralRule=0, Code="ko"}},
  304. {"Kurdish", new LanguageCodeDef {PluralRule=1, Code="ku"}},
  305. /**/{"Kuanyama", new LanguageCodeDef {PluralRule=1, Code="kj", GoogleCode="-"}},
  306. {"Latin", new LanguageCodeDef {PluralRule=1, Code="la"}},
  307. /**/{"Luxembourgish", new LanguageCodeDef {PluralRule=1, Code="lb"}},
  308. /**/{"Ganda", new LanguageCodeDef {PluralRule=1, Code="lg", GoogleCode="-"}},
  309. /**/{"Limburgan", new LanguageCodeDef {PluralRule=1, Code="li", GoogleCode="-"}},
  310. /**/{"Lingala", new LanguageCodeDef {PluralRule=1, Code="ln", GoogleCode="-"}},
  311. /**/{"Lao", new LanguageCodeDef {PluralRule=1, Code="lo"}},
  312. {"Latvian", new LanguageCodeDef {PluralRule=5, Code="lv"}},
  313. /**/{"Luba-Katanga", new LanguageCodeDef {PluralRule=1, Code="lu", GoogleCode="-"}},
  314. {"Lithuanian", new LanguageCodeDef {PluralRule=5, Code="lt"}},
  315. /**/{"Manx", new LanguageCodeDef {PluralRule=1, Code="gv", GoogleCode="-"}},
  316. {"Macedonian", new LanguageCodeDef {PluralRule=13, Code="mk"}},
  317. /**/{"Malagasy", new LanguageCodeDef {PluralRule=1, Code="mg"}},
  318. {"Malay", new LanguageCodeDef {PluralRule=0, Code="ms"}},
  319. {"Malay/Brunei Darussalam", new LanguageCodeDef {PluralRule=0, Code="ms-BN", GoogleCode="ms"}},
  320. {"Malay/Malaysia", new LanguageCodeDef {PluralRule=0, Code="ms-MY", GoogleCode="ms"}},
  321. {"Malayalam", new LanguageCodeDef {PluralRule=1, Code="ml"}},
  322. {"Maltese", new LanguageCodeDef {PluralRule=12, Code="mt"}},
  323. {"Maori", new LanguageCodeDef {PluralRule=2, Code="mi"}},
  324. {"Marathi", new LanguageCodeDef {PluralRule=1, Code="mr"}},
  325. /**/{"Marshallese", new LanguageCodeDef {PluralRule=1, Code="mh", GoogleCode="-"}},
  326. {"Mongolian", new LanguageCodeDef {PluralRule=1, Code="mn"}},
  327. /**/{"Nauru", new LanguageCodeDef {PluralRule=1, Code="na", GoogleCode="-"}},
  328. /**/{"Navajo", new LanguageCodeDef {PluralRule=1, Code="nv", GoogleCode="-"}},
  329. /**/{"North Ndebele", new LanguageCodeDef {PluralRule=1, Code="nd", GoogleCode="-"}},
  330. /**/{"Nepali", new LanguageCodeDef {PluralRule=1, Code="ne"}},
  331. /**/{"Ndonga", new LanguageCodeDef {PluralRule=1, Code="ng", GoogleCode="-"}},
  332. {"Northern Sotho", new LanguageCodeDef {PluralRule=1, Code="ns", GoogleCode="st"}},
  333. {"Norwegian", new LanguageCodeDef {PluralRule=1, Code="nb", GoogleCode="no"}},
  334. {"Norwegian/Nynorsk", new LanguageCodeDef {PluralRule=1, Code="nn", GoogleCode="no"}},
  335. /**/{"Sichuan Yi", new LanguageCodeDef {PluralRule=1, Code="ii", GoogleCode="-"}},
  336. /**/{"South Ndebele", new LanguageCodeDef {PluralRule=1, Code="nr", GoogleCode="-"}},
  337. /**/{"Occitan", new LanguageCodeDef {PluralRule=1, Code="oc", GoogleCode="-"}},
  338. /**/{"Ojibwa", new LanguageCodeDef {PluralRule=1, Code="oj", GoogleCode="-"}},
  339. /**/{"Church Slavic", new LanguageCodeDef {PluralRule=1, Code="cu", GoogleCode="-"}},
  340. /**/{"Oromo", new LanguageCodeDef {PluralRule=1, Code="om", GoogleCode="-"}},
  341. /**/{"Oriya", new LanguageCodeDef {PluralRule=1, Code="or", GoogleCode="-"}},
  342. /**/{"Ossetian", new LanguageCodeDef {PluralRule=1, Code="os", GoogleCode="-"}},
  343. /**/{"Pali", new LanguageCodeDef {PluralRule=1, Code="pi", GoogleCode="-"}},
  344. {"Pashto", new LanguageCodeDef {PluralRule=1, Code="ps"}},
  345. {"Persian", new LanguageCodeDef {PluralRule=0, Code="fa"}},
  346. {"Polish", new LanguageCodeDef {PluralRule=8, Code="pl"}},
  347. {"Portuguese", new LanguageCodeDef {PluralRule=1, Code="pt"}},
  348. {"Portuguese/Brazil", new LanguageCodeDef {PluralRule=2, Code="pt-BR", GoogleCode="pt"}},
  349. {"Portuguese/Portugal", new LanguageCodeDef {PluralRule=1, Code="pt-PT", GoogleCode="pt"}},
  350. {"Punjabi", new LanguageCodeDef {PluralRule=1, Code="pa"}},
  351. {"Quechua", new LanguageCodeDef {PluralRule=1, Code="qu", GoogleCode="-"}},
  352. {"Quechua/Bolivia", new LanguageCodeDef {PluralRule=1, Code="qu-BO", GoogleCode="-"}},
  353. {"Quechua/Ecuador", new LanguageCodeDef {PluralRule=1, Code="qu-EC", GoogleCode="-"}},
  354. {"Quechua/Peru", new LanguageCodeDef {PluralRule=1, Code="qu-PE", GoogleCode="-"}},
  355. {"Rhaeto-Romanic", new LanguageCodeDef {PluralRule=1, Code="rm", GoogleCode="ro"}},
  356. {"Romanian", new LanguageCodeDef {PluralRule=4, Code="ro"}},
  357. /**/{"Rundi", new LanguageCodeDef {PluralRule=1, Code="rn", GoogleCode="-"}},
  358. {"Russian", new LanguageCodeDef {PluralRule=6, Code="ru"}},
  359. {"Russian/Republic of Moldova", new LanguageCodeDef {PluralRule=6, Code="ru-MO", GoogleCode="ru"}},
  360. /**/{"Sanskrit", new LanguageCodeDef {PluralRule=1, Code="sa", GoogleCode="-"}},
  361. /**/{"Sardinian", new LanguageCodeDef {PluralRule=1, Code="sc", GoogleCode="-"}},
  362. /**/{"Sindhi", new LanguageCodeDef {PluralRule=1, Code="sd"}},
  363. /**/{"Northern Sami", new LanguageCodeDef {PluralRule=1, Code="se", GoogleCode="-"}},
  364. /**/{"Samoan", new LanguageCodeDef {PluralRule=1, Code="sm"}},
  365. /**/{"Sango", new LanguageCodeDef {PluralRule=1, Code="sg", GoogleCode="-"}},
  366. {"Serbian", new LanguageCodeDef {PluralRule=6, Code="sr"}},
  367. {"Serbian/Bosnia and Herzegovina", new LanguageCodeDef {PluralRule=5, Code="sr-BA", GoogleCode="sr"}},
  368. {"Serbian/Serbia and Montenegro", new LanguageCodeDef {PluralRule=5, Code="sr-SP", GoogleCode="sr"}},
  369. /**/{"Scottish Gaelic", new LanguageCodeDef {PluralRule=1, Code="gd"}},
  370. /**/{"Shona", new LanguageCodeDef {PluralRule=1, Code="sn"}},
  371. /**/{"Sinhala", new LanguageCodeDef {PluralRule=1, Code="si"}},
  372. {"Slovak", new LanguageCodeDef {PluralRule=7, Code="sk"}},
  373. {"Slovenian", new LanguageCodeDef {PluralRule=9, Code="sl"}},
  374. /**/{"Somali", new LanguageCodeDef {PluralRule=1, Code="so"}},
  375. /**/{"Southern Sotho", new LanguageCodeDef {PluralRule=1, Code="st"}},
  376. {"Spanish", new LanguageCodeDef {PluralRule=1, Code="es"}},
  377. {"Spanish/Argentina", new LanguageCodeDef {PluralRule=1, Code="es-AR", GoogleCode="es"}},
  378. {"Spanish/Bolivia", new LanguageCodeDef {PluralRule=1, Code="es-BO", GoogleCode="es"}},
  379. {"Spanish/Castilian", new LanguageCodeDef {PluralRule=1, Code="es-ES", GoogleCode="es"}},
  380. {"Spanish/Chile", new LanguageCodeDef {PluralRule=1, Code="es-CL", GoogleCode="es"}},
  381. {"Spanish/Colombia", new LanguageCodeDef {PluralRule=1, Code="es-CO", GoogleCode="es"}},
  382. {"Spanish/Costa Rica", new LanguageCodeDef {PluralRule=1, Code="es-CR", GoogleCode="es"}},
  383. {"Spanish/Dominican Republic", new LanguageCodeDef {PluralRule=1, Code="es-DO", GoogleCode="es"}},
  384. {"Spanish/Ecuador", new LanguageCodeDef {PluralRule=1, Code="es-EC", GoogleCode="es"}},
  385. {"Spanish/El Salvador", new LanguageCodeDef {PluralRule=1, Code="es-SV", GoogleCode="es"}},
  386. {"Spanish/Guatemala", new LanguageCodeDef {PluralRule=1, Code="es-GT", GoogleCode="es"}},
  387. {"Spanish/Honduras", new LanguageCodeDef {PluralRule=1, Code="es-HN", GoogleCode="es"}},
  388. {"Spanish/Mexico", new LanguageCodeDef {PluralRule=1, Code="es-MX", GoogleCode="es"}},
  389. {"Spanish/Nicaragua", new LanguageCodeDef {PluralRule=1, Code="es-NI", GoogleCode="es"}},
  390. {"Spanish/Panama", new LanguageCodeDef {PluralRule=1, Code="es-PA", GoogleCode="es"}},
  391. {"Spanish/Paraguay", new LanguageCodeDef {PluralRule=1, Code="es-PY", GoogleCode="es"}},
  392. {"Spanish/Peru", new LanguageCodeDef {PluralRule=1, Code="es-PE", GoogleCode="es"}},
  393. {"Spanish/Puerto Rico", new LanguageCodeDef {PluralRule=1, Code="es-PR", GoogleCode="es"}},
  394. {"Spanish/Spain", new LanguageCodeDef {PluralRule=1, Code="es-ES", GoogleCode="es"}},
  395. {"Spanish/Uruguay", new LanguageCodeDef {PluralRule=1, Code="es-UY", GoogleCode="es"}},
  396. {"Spanish/Venezuela", new LanguageCodeDef {PluralRule=1, Code="es-VE", GoogleCode="es"}},
  397. {"Spanish/Latin Americas", new LanguageCodeDef {PluralRule=1, Code="es-US", GoogleCode="es"}},
  398. /**/{"Sundanese", new LanguageCodeDef {PluralRule=1, Code="su"}},
  399. {"Swahili", new LanguageCodeDef {Code="sw"}},
  400. /**/{"Swati", new LanguageCodeDef {PluralRule=1, Code="ss", GoogleCode="-"}},
  401. {"Swedish", new LanguageCodeDef {PluralRule=1, Code="sv"}},
  402. {"Swedish/Finland", new LanguageCodeDef {PluralRule=1, Code="sv-FI", GoogleCode="sv"}},
  403. {"Swedish/Sweden", new LanguageCodeDef {PluralRule=1, Code="sv-SE", GoogleCode="sv"}},
  404. {"Tamil", new LanguageCodeDef {PluralRule=1, Code="ta"}},
  405. {"Tatar", new LanguageCodeDef {PluralRule=0, Code="tt", GoogleCode="-"}},
  406. {"Telugu", new LanguageCodeDef {PluralRule=1, Code="te"}},
  407. /**/{"Tajik", new LanguageCodeDef {PluralRule=1, Code="tg"}},
  408. {"Thai", new LanguageCodeDef {PluralRule=0, Code="th", HasJoinedWords=true}},
  409. /**/{"Tigrinya", new LanguageCodeDef {PluralRule=1, Code="ti", GoogleCode="-"}},
  410. /**/{"Tibetan", new LanguageCodeDef {PluralRule=1, Code="bo", GoogleCode="-"}},
  411. /**/{"Turkmen", new LanguageCodeDef {PluralRule=1, Code="tk", GoogleCode="-"}},
  412. /**/{"Tagalog", new LanguageCodeDef {PluralRule=1, Code="tl"}},
  413. /**/{"Tswana", new LanguageCodeDef {PluralRule=1, Code="tn", GoogleCode="-"}},
  414. /**/{"Tonga", new LanguageCodeDef {PluralRule=1, Code="to", GoogleCode="-"}},
  415. {"Turkish", new LanguageCodeDef {PluralRule=0, Code="tr"}},
  416. /**/{"Tsonga", new LanguageCodeDef {PluralRule=1, Code="ts", GoogleCode="-"}},
  417. /**/{"Twi", new LanguageCodeDef {PluralRule=1, Code="tw", GoogleCode="-"}},
  418. /**/{"Tahitian", new LanguageCodeDef {PluralRule=1, Code="ty", GoogleCode="-"}},
  419. /**/{"Uighur", new LanguageCodeDef {PluralRule=1, Code="ug", GoogleCode="-"}},
  420. {"Ukrainian", new LanguageCodeDef {PluralRule=6, Code="uk"}},
  421. {"Urdu", new LanguageCodeDef {PluralRule=1, Code="ur"}},
  422. {"Uzbek", new LanguageCodeDef {PluralRule=2, Code="uz"}},
  423. /**/{"Venda", new LanguageCodeDef {PluralRule=1, Code="ve", GoogleCode="-"}},
  424. {"Vietnamese", new LanguageCodeDef {PluralRule=1, Code="vi"}},
  425. /**/{"Volapük", new LanguageCodeDef {PluralRule=1, Code="vo", GoogleCode="-"}},
  426. /**/{"Walloon", new LanguageCodeDef {PluralRule=1, Code="wa", GoogleCode="-"}},
  427. {"Welsh", new LanguageCodeDef {PluralRule=16, Code="cy"}},
  428. /**/{"Wolof", new LanguageCodeDef {PluralRule=1, Code="wo", GoogleCode="-"}},
  429. /**/{"Frisian", new LanguageCodeDef {PluralRule=1, Code="fy"}},
  430. {"Xhosa", new LanguageCodeDef {PluralRule=1, Code="xh"}},
  431. {"Yiddish", new LanguageCodeDef {PluralRule=1, Code="yi"}},
  432. /**/{"Yoruba", new LanguageCodeDef {PluralRule=1, Code="yo"}},
  433. /**/{"Zhuang", new LanguageCodeDef {PluralRule=1, Code="za", GoogleCode="-"}},
  434. {"Zulu", new LanguageCodeDef {PluralRule=1, Code="zu"}}
  435. };
  436. static int GetPluralRule( string langCode )
  437. {
  438. if (langCode.Length > 2)
  439. langCode = langCode.Substring(0, 2);
  440. langCode = langCode.ToLower();
  441. foreach (var kvp in mLanguageDef)
  442. if (kvp.Value.Code == langCode)
  443. {
  444. return kvp.Value.PluralRule;
  445. }
  446. return 0;
  447. }
  448. //http://www.unicode.org/cldr/charts/latest/supplemental/language_plural_rules.html
  449. //http://cldr.unicode.org/cldr-features#TOC-Locale-specific-patterns-for-formatting-and-parsing:
  450. //http://cldr.unicode.org/index/cldr-spec/plural-rules
  451. public static bool LanguageHasPluralType( string langCode, string pluralType )
  452. {
  453. if (pluralType == "Plural" || pluralType=="Zero" || pluralType=="One")
  454. return true;
  455. int rule = GetPluralRule (langCode);
  456. switch (rule)
  457. {
  458. case 3: // Celtic (Scottish Gaelic)
  459. return pluralType=="Two" || pluralType=="Few";
  460. case 4: // Families: Romanic (Romanian)
  461. case 5: // Families: Baltic (Latvian, Lithuanian)
  462. case 6: // Families: Slavic (Belarusian, Bosnian, Croatian, Serbian, Russian, Ukrainian)
  463. case 7: // Families: Slavic (Slovak, Czech)
  464. case 8: // Families: Slavic (Polish)
  465. return pluralType=="Few";
  466. case 9: // Families: Slavic (Slovenian, Sorbian)
  467. return pluralType=="Two" || pluralType=="Few";
  468. case 10: // Families: Celtic (Irish Gaelic)
  469. case 11: // Families: Semitic (Arabic)
  470. case 15: // Families: Celtic (Breton)
  471. case 16: // Families: (Welsh)
  472. return pluralType=="Two" || pluralType=="Few" || pluralType=="Many";
  473. case 12: // Families: Semitic (Maltese)
  474. return pluralType=="Few" || pluralType=="Many";
  475. case 13: // Families: Slavic (Macedonian)
  476. return pluralType=="Two";
  477. }
  478. return false;
  479. }
  480. // https://developer.mozilla.org/en-US/docs/Mozilla/Localization/Localization_and_Plurals
  481. public static ePluralType GetPluralType( string langCode, int n )
  482. {
  483. if (n == 0) return ePluralType.Zero;
  484. if (n == 1) return ePluralType.One;
  485. int rule = GetPluralRule (langCode);
  486. switch (rule)
  487. {
  488. case 0: // Families: Asian (Chinese, Japanese, Korean), Persian, Turkic/Altaic (Turkish), Thai, Lao
  489. return ePluralType.Plural;
  490. case 1: // Families: Germanic (Danish, Dutch, English, Faroese, Frisian, German, Norwegian, Swedish), Finno-Ugric (Estonian, Finnish, Hungarian), Language isolate (Basque), Latin/Greek (Greek), Semitic (Hebrew), Romanic (Italian, Portuguese, Spanish, Catalan), Vietnamese
  491. return n==1 ? ePluralType.One : ePluralType.Plural;
  492. case 2: // Families: Romanic (French, Brazilian Portuguese)
  493. return n<=1 ? ePluralType.One : ePluralType.Plural;
  494. case 3: // Celtic (Scottish Gaelic)
  495. return n==1 || n==11 ? ePluralType.One :
  496. n==2 || n==12 ? ePluralType.Two :
  497. inRange(n,3,10) || inRange(n,13,19) ? ePluralType.Few : ePluralType.Plural;
  498. case 4: // Families: Romanic (Romanian)
  499. return n==1 ? ePluralType.One :
  500. inRange(n%100, 1, 19) ? ePluralType.Few : ePluralType.Plural;
  501. case 5: // Families: Baltic (Latvian, Lithuanian)
  502. return n%10==1 && n%100!=11 ? ePluralType.One :
  503. n%10>=2 && (n%100<10 || n%100>=20) ? ePluralType.Few : ePluralType.Plural;
  504. case 6: // Families: Slavic (Belarusian, Bosnian, Croatian, Serbian, Russian, Ukrainian)
  505. return n % 10 == 1 && n % 100 != 11 ? ePluralType.One :
  506. inRange (n%10,2,4) && !inRange (n%100,12,14) ? ePluralType.Few : ePluralType.Plural;
  507. case 7: // Families: Slavic (Slovak, Czech)
  508. return n==1 ? ePluralType.One :
  509. inRange(n,2,4) ? ePluralType.Few : ePluralType.Plural;
  510. case 8: // Families: Slavic (Polish)
  511. return n==1 ? ePluralType.One :
  512. inRange (n%10,2,4) && !inRange (n%100,12,14) ? ePluralType.Few : ePluralType.Plural;
  513. case 9: // Families: Slavic (Slovenian, Sorbian)
  514. return n%100==1 ? ePluralType.One :
  515. n%100==2 ? ePluralType.Two :
  516. inRange(n%100,3,4) ? ePluralType.Few : ePluralType.Plural;
  517. case 10: // Families: Celtic (Irish Gaelic)
  518. return n==1 ? ePluralType.One :
  519. n==2 ? ePluralType.Two :
  520. inRange(n, 3,6) ? ePluralType.Few :
  521. inRange(n, 7,10)? ePluralType.Many : ePluralType.Plural;
  522. case 11: // Families: Semitic (Arabic)
  523. return n==0 ? ePluralType.Zero :
  524. n==1 ? ePluralType.One :
  525. n==2 ? ePluralType.Two :
  526. inRange(n%100,3,10) ? ePluralType.Few :
  527. n%100>=11 ? ePluralType.Many : ePluralType.Plural;
  528. case 12: // Families: Semitic (Maltese)
  529. return n==1 ? ePluralType.One :
  530. inRange(n%100, 1, 10) ? ePluralType.Few :
  531. inRange(n%100, 11,19) ? ePluralType.Many : ePluralType.Plural;
  532. case 13: // Families: Slavic (Macedonian)
  533. return n % 10 == 1 ? ePluralType.One :
  534. n % 10 == 2 ? ePluralType.Two : ePluralType.Plural;
  535. case 14: // Plural rule #15 (2 forms)
  536. return n%10==1 && n%100!=11 ? ePluralType.One : ePluralType.Plural;
  537. case 15: // Families: Celtic (Breton)
  538. return n % 10 == 1 && n % 100 != 11 && n % 100 != 71 && n % 100 != 91 ? ePluralType.One :
  539. n % 10 == 2 && n % 100 != 12 && n % 100 != 72 && n % 100 != 92 ? ePluralType.Two :
  540. (n % 10 == 3 || n % 10 == 4 || n % 10 == 9) && n % 100 != 13 && n % 100 != 14 && n % 100 != 19 && n % 100 != 73 && n % 100 != 74 && n % 100 != 79 && n % 100 != 93 && n % 100 != 94 && n % 100 != 99 ? ePluralType.Few :
  541. n%1000000==0 ? ePluralType.Many : ePluralType.Plural;
  542. case 16: // Families: (Welsh)
  543. return n==0 ? ePluralType.Zero :
  544. n==1 ? ePluralType.One :
  545. n==2 ? ePluralType.Two :
  546. n==3 ? ePluralType.Few :
  547. n==6 ? ePluralType.Many : ePluralType.Plural;
  548. }
  549. return ePluralType.Plural;
  550. }
  551. // A number that belong to the pluralType form
  552. public static int GetPluralTestNumber( string langCode, ePluralType pluralType )
  553. {
  554. switch (pluralType)
  555. {
  556. case ePluralType.Zero:
  557. return 0;
  558. case ePluralType.One:
  559. return 1;
  560. case ePluralType.Few:
  561. return 3;
  562. case ePluralType.Many:
  563. {
  564. int rule = GetPluralRule (langCode);
  565. if (rule == 10) return 8;
  566. if (rule == 11 || rule==12) return 13;
  567. if (rule == 15) return 1000000;
  568. return 6;
  569. }
  570. default:
  571. return 936;
  572. }
  573. }
  574. static bool inRange(int amount, int min, int max)
  575. {
  576. return amount >= min && amount <= max;
  577. }
  578. }
  579. }