LocalizationManager_Language.cs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Globalization;
  4. using System.Linq;
  5. using System.Threading;
  6. namespace I2.Loc
  7. {
  8. public static partial class LocalizationManager
  9. {
  10. #region Variables: CurrentLanguage
  11. public static string CurrentLanguage
  12. {
  13. get {
  14. InitializeIfNeeded();
  15. return mCurrentLanguage;
  16. }
  17. set {
  18. InitializeIfNeeded();
  19. string SupportedLanguage = GetSupportedLanguage(value);
  20. if (!string.IsNullOrEmpty(SupportedLanguage) && mCurrentLanguage != SupportedLanguage)
  21. {
  22. SetLanguageAndCode(SupportedLanguage, GetLanguageCode(SupportedLanguage));
  23. }
  24. }
  25. }
  26. public static string CurrentLanguageCode
  27. {
  28. get {
  29. InitializeIfNeeded();
  30. return mLanguageCode; }
  31. set {
  32. InitializeIfNeeded();
  33. if (mLanguageCode != value)
  34. {
  35. string LanName = GetLanguageFromCode(value);
  36. if (!string.IsNullOrEmpty(LanName))
  37. SetLanguageAndCode(LanName, value);
  38. }
  39. }
  40. }
  41. // "English (United States)" (get returns "United States")
  42. // when set "Canada", the new language code will be "English (Canada)"
  43. public static string CurrentRegion
  44. {
  45. get {
  46. var Lan = CurrentLanguage;
  47. int idx = Lan.IndexOfAny("/\\".ToCharArray());
  48. if (idx > 0)
  49. return Lan.Substring(idx + 1);
  50. idx = Lan.IndexOfAny("[(".ToCharArray());
  51. int idx2 = Lan.LastIndexOfAny("])".ToCharArray());
  52. if (idx > 0 && idx != idx2)
  53. return Lan.Substring(idx + 1, idx2 - idx - 1);
  54. return string.Empty;
  55. }
  56. set {
  57. var Lan = CurrentLanguage;
  58. int idx = Lan.IndexOfAny("/\\".ToCharArray());
  59. if (idx > 0)
  60. {
  61. CurrentLanguage = Lan.Substring(idx + 1) + value;
  62. return;
  63. }
  64. idx = Lan.IndexOfAny("[(".ToCharArray());
  65. int idx2 = Lan.LastIndexOfAny("])".ToCharArray());
  66. if (idx > 0 && idx != idx2)
  67. Lan = Lan.Substring(idx);
  68. CurrentLanguage = Lan + "(" + value + ")";
  69. }
  70. }
  71. // "en-US" (get returns "US") (when set "CA", the new language code will be "en-CA")
  72. public static string CurrentRegionCode
  73. {
  74. get {
  75. var code = CurrentLanguageCode;
  76. int idx = code.IndexOfAny(" -_/\\".ToCharArray());
  77. return idx < 0 ? string.Empty : code.Substring(idx + 1);
  78. }
  79. set {
  80. var code = CurrentLanguageCode;
  81. int idx = code.IndexOfAny(" -_/\\".ToCharArray());
  82. if (idx > 0)
  83. code = code.Substring(0, idx);
  84. CurrentLanguageCode = code + "-" + value;
  85. }
  86. }
  87. public static CultureInfo CurrentCulture
  88. {
  89. get
  90. {
  91. return mCurrentCulture;
  92. }
  93. }
  94. static string mCurrentLanguage;
  95. static string mLanguageCode;
  96. static CultureInfo mCurrentCulture;
  97. static bool mChangeCultureInfo;
  98. public static bool IsRight2Left;
  99. public static bool HasJoinedWords; // Some languages (e.g. Chinese, Japanese and Thai) don't add spaces to their words (all characters are placed toguether)
  100. #endregion
  101. public static void SetLanguageAndCode(string LanguageName, string LanguageCode, bool RememberLanguage = true, bool Force = false)
  102. {
  103. if (mCurrentLanguage != LanguageName || mLanguageCode != LanguageCode || Force)
  104. {
  105. if (RememberLanguage)
  106. PersistentStorage.SetSetting_String("I2 Language", LanguageName);
  107. mCurrentLanguage = LanguageName;
  108. mLanguageCode = LanguageCode;
  109. mCurrentCulture = CreateCultureForCode(LanguageCode);
  110. if (mChangeCultureInfo)
  111. SetCurrentCultureInfo();
  112. IsRight2Left = IsRTL(mLanguageCode);
  113. HasJoinedWords = GoogleLanguages.LanguageCode_HasJoinedWord(mLanguageCode);
  114. LocalizeAll(Force);
  115. }
  116. }
  117. static CultureInfo CreateCultureForCode(string code)
  118. {
  119. #if !NETFX_CORE
  120. try
  121. {
  122. return CultureInfo.CreateSpecificCulture(code);
  123. }
  124. catch (Exception)
  125. {
  126. return CultureInfo.InvariantCulture;
  127. }
  128. #else
  129. return CultureInfo.InvariantCulture;
  130. #endif
  131. }
  132. public static void EnableChangingCultureInfo(bool bEnable)
  133. {
  134. if (!mChangeCultureInfo && bEnable)
  135. SetCurrentCultureInfo();
  136. mChangeCultureInfo = bEnable;
  137. }
  138. static void SetCurrentCultureInfo()
  139. {
  140. #if !NETFX_CORE
  141. Thread.CurrentThread.CurrentCulture = mCurrentCulture;
  142. #endif
  143. }
  144. static void SelectStartupLanguage()
  145. {
  146. if (Sources.Count == 0)
  147. return;
  148. // Use the system language if there is a source with that language,
  149. // or pick any of the languages provided by the sources
  150. string SavedLanguage = PersistentStorage.GetSetting_String("I2 Language", string.Empty);
  151. string SysLanguage = GetCurrentDeviceLanguage();
  152. // Try selecting the System Language
  153. // But fallback to the first language found if the System Language is not available in any source
  154. if (!string.IsNullOrEmpty(SavedLanguage) && HasLanguage(SavedLanguage, Initialize: false, SkipDisabled:true))
  155. {
  156. SetLanguageAndCode(SavedLanguage, GetLanguageCode(SavedLanguage));
  157. return;
  158. }
  159. if (!Sources [0].IgnoreDeviceLanguage)
  160. {
  161. // Check if the device language is supported.
  162. // Also recognize when not region is set ("English (United State") will be used if sysLanguage is "English")
  163. string ValidLanguage = GetSupportedLanguage (SysLanguage, true);
  164. if (!string.IsNullOrEmpty (ValidLanguage)) {
  165. SetLanguageAndCode (ValidLanguage, GetLanguageCode (ValidLanguage), false);
  166. return;
  167. }
  168. }
  169. //--[ Use first language that its not disabled ]-----------
  170. for (int i = 0, imax = Sources.Count; i < imax; ++i)
  171. if (Sources[i].mLanguages.Count > 0)
  172. {
  173. for (int j = 0; j < Sources[i].mLanguages.Count; ++j)
  174. if (Sources[i].mLanguages[j].IsEnabled())
  175. {
  176. SetLanguageAndCode(Sources[i].mLanguages[j].Name, Sources[i].mLanguages[j].Code, false);
  177. return;
  178. }
  179. }
  180. }
  181. public static bool HasLanguage( string Language, bool AllowDiscartingRegion = true, bool Initialize=true, bool SkipDisabled=true )
  182. {
  183. if (Initialize)
  184. InitializeIfNeeded();
  185. // First look for an exact match
  186. for (int i=0, imax=Sources.Count; i<imax; ++i)
  187. if (Sources[i].GetLanguageIndex(Language, false, SkipDisabled) >=0)
  188. return true;
  189. // Then allow matching "English (Canada)" to "english"
  190. if (AllowDiscartingRegion)
  191. {
  192. for (int i=0, imax=Sources.Count; i<imax; ++i)
  193. if (Sources[i].GetLanguageIndex(Language, true, SkipDisabled) >=0)
  194. return true;
  195. }
  196. return false;
  197. }
  198. // Returns the provided language or a similar one without the Region
  199. //(e.g. "English (Canada)" could be mapped to "english" or "English (United States)" if "English (Canada)" is not found
  200. public static string GetSupportedLanguage( string Language, bool ignoreDisabled=false )
  201. {
  202. // First try finding the language that matches one of the official languages
  203. string code = GoogleLanguages.GetLanguageCode(Language);
  204. if (!string.IsNullOrEmpty(code))
  205. {
  206. // First try finding if the exact language code is in one source
  207. for (int i = 0, imax = Sources.Count; i < imax; ++i)
  208. {
  209. int Idx = Sources[i].GetLanguageIndexFromCode(code, true, ignoreDisabled);
  210. if (Idx >= 0)
  211. return Sources[i].mLanguages[Idx].Name;
  212. }
  213. // If not, try checking without the region
  214. for (int i = 0, imax = Sources.Count; i < imax; ++i)
  215. {
  216. int Idx = Sources[i].GetLanguageIndexFromCode(code, false, ignoreDisabled);
  217. if (Idx >= 0)
  218. return Sources[i].mLanguages[Idx].Name;
  219. }
  220. }
  221. // If not found, then try finding an exact match for the name
  222. for (int i=0, imax=Sources.Count; i<imax; ++i)
  223. {
  224. int Idx = Sources[i].GetLanguageIndex(Language, false, ignoreDisabled);
  225. if (Idx>=0)
  226. return Sources[i].mLanguages[Idx].Name;
  227. }
  228. // Then allow matching "English (Canada)" to "english"
  229. for (int i=0, imax=Sources.Count; i<imax; ++i)
  230. {
  231. int Idx = Sources[i].GetLanguageIndex(Language, true, ignoreDisabled);
  232. if (Idx>=0)
  233. return Sources[i].mLanguages[Idx].Name;
  234. }
  235. return string.Empty;
  236. }
  237. public static string GetLanguageCode( string Language )
  238. {
  239. if (Sources.Count==0)
  240. UpdateSources();
  241. for (int i=0, imax=Sources.Count; i<imax; ++i)
  242. {
  243. int Idx = Sources[i].GetLanguageIndex(Language);
  244. if (Idx>=0)
  245. return Sources[i].mLanguages[Idx].Code;
  246. }
  247. return string.Empty;
  248. }
  249. public static string GetLanguageFromCode( string Code, bool exactMatch=true )
  250. {
  251. if (Sources.Count==0)
  252. UpdateSources();
  253. for (int i=0, imax=Sources.Count; i<imax; ++i)
  254. {
  255. int Idx = Sources[i].GetLanguageIndexFromCode(Code, exactMatch);
  256. if (Idx>=0)
  257. return Sources[i].mLanguages[Idx].Name;
  258. }
  259. return string.Empty;
  260. }
  261. public static List<string> GetAllLanguages ( bool SkipDisabled = true )
  262. {
  263. if (Sources.Count==0)
  264. UpdateSources();
  265. List<string> Languages = new List<string> ();
  266. for (int i=0, imax=Sources.Count; i<imax; ++i)
  267. {
  268. Languages.AddRange(Sources[i].GetLanguages(SkipDisabled).Where(x=>!Languages.Contains(x)));
  269. }
  270. return Languages;
  271. }
  272. public static List<string> GetAllLanguagesCode(bool allowRegions=true, bool SkipDisabled = true)
  273. {
  274. List<string> Languages = new List<string>();
  275. for (int i = 0, imax = Sources.Count; i < imax; ++i)
  276. {
  277. Languages.AddRange(Sources[i].GetLanguagesCode(allowRegions, SkipDisabled).Where(x => !Languages.Contains(x)));
  278. }
  279. return Languages;
  280. }
  281. public static bool IsLanguageEnabled(string Language)
  282. {
  283. for (int i = 0, imax = Sources.Count; i < imax; ++i)
  284. if (!Sources[i].IsLanguageEnabled(Language))
  285. return false;
  286. return true;
  287. }
  288. static void LoadCurrentLanguage()
  289. {
  290. for (int i = 0; i < Sources.Count; ++i)
  291. {
  292. var iCurrentLang = Sources[i].GetLanguageIndex(mCurrentLanguage, true, false);
  293. Sources[i].LoadLanguage(iCurrentLang, true, true, true, false);
  294. }
  295. }
  296. // This function should only be called from within the Localize Inspector to temporaly preview that Language
  297. public static void PreviewLanguage(string NewLanguage)
  298. {
  299. mCurrentLanguage = NewLanguage;
  300. mLanguageCode = GetLanguageCode(mCurrentLanguage);
  301. IsRight2Left = IsRTL(mLanguageCode);
  302. HasJoinedWords = GoogleLanguages.LanguageCode_HasJoinedWord(mLanguageCode);
  303. }
  304. }
  305. }