You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

722 lines
19 KiB

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Diagnostics;
  4. using System.Globalization;
  5. using System.IO;
  6. using CIG.Translation.Native;
  7. using UnityEngine;
  8. namespace CIG.Translation
  9. {
  10. public static class Localization
  11. {
  12. static Localization()
  13. {
  14. Localization.LoadCultures();
  15. Localization.LoadFallbackTranslation();
  16. }
  17. //[DebuggerBrowsable(DebuggerBrowsableState.Never)]
  18. public static event Localization.CultureEventHandler CurrentCultureChangedEvent;
  19. private static void FireCultureChangedEvent()
  20. {
  21. if (Localization.CurrentCultureChangedEvent != null)
  22. {
  23. Localization.CurrentCultureChangedEvent(Localization._currentCulture);
  24. }
  25. }
  26. public static Localization.Culture GetSystemDefaultCulture()
  27. {
  28. Localization.Culture culture = null;
  29. string[] defaultLanguages = SystemLocale.DefaultLanguages;
  30. int num = defaultLanguages.Length;
  31. for (int i = 0; i < num; i++)
  32. {
  33. string text = defaultLanguages[i];
  34. if (!string.IsNullOrEmpty(text))
  35. {
  36. string text2;
  37. string text3;
  38. Localization.SplitLocale(text, out text2, out text3);
  39. int count = Localization._availableCultures.Count;
  40. for (int j = 0; j < count; j++)
  41. {
  42. Localization.Culture culture2 = Localization._availableCultures[j];
  43. int count2 = culture2.Names.Count;
  44. for (int k = 0; k < count2; k++)
  45. {
  46. string value;
  47. string value2;
  48. Localization.SplitLocale(culture2.Names[k], out value, out value2);
  49. if (text2.Equals(value))
  50. {
  51. if (culture == null)
  52. {
  53. culture = culture2;
  54. }
  55. if (text3 == null || text3.Equals(value2))
  56. {
  57. UnityEngine.Debug.LogFormat("SUISS Localization: Found perfect lang-locale match: {0}", new object[]
  58. {
  59. text
  60. });
  61. return culture2;
  62. }
  63. }
  64. }
  65. }
  66. }
  67. }
  68. if (culture != null)
  69. {
  70. UnityEngine.Debug.LogFormat("SUISS Localization: Found partial lang-locale match: {0} (user's preferred languages: {1})", new object[]
  71. {
  72. culture.Identifier,
  73. string.Join(", ", defaultLanguages)
  74. });
  75. return culture;
  76. }
  77. UnityEngine.Debug.LogFormat("SUISS Localization: No lang-locale match; falling back to {0}. (user's preferred languages: {1})", new object[]
  78. {
  79. Localization._availableCultures[0].Identifier,
  80. string.Join(", ", defaultLanguages)
  81. });
  82. return Localization._availableCultures[0];
  83. }
  84. private static void LoadCultures()
  85. {
  86. List<Localization.Culture> list = new List<Localization.Culture>();
  87. try
  88. {
  89. TextAsset textAsset = Resources.Load<TextAsset>("Localization/Cultures");
  90. XMLParser xmlparser = new XMLParser(textAsset.text);
  91. XMLElement xmlelement = xmlparser.Parse();
  92. if (xmlelement.value != "Cultures")
  93. {
  94. throw new Exception("SUISS Localization: Unexpected document element: " + xmlelement.value);
  95. }
  96. int count = xmlelement.Children.Count;
  97. for (int i = 0; i < count; i++)
  98. {
  99. IXMLNode ixmlnode = xmlelement.Children[i];
  100. try
  101. {
  102. if (ixmlnode.type == XMLNodeType.Element)
  103. {
  104. if (ixmlnode.value != "Culture")
  105. {
  106. UnityEngine.Debug.LogWarning("SUISS Localization: Encountered an unexpected element in Cultures: " + ixmlnode.value);
  107. }
  108. else
  109. {
  110. List<string> list2 = new List<string>();
  111. string text = null;
  112. string text2 = null;
  113. int count2 = ixmlnode.Children.Count;
  114. for (int j = 0; j < count2; j++)
  115. {
  116. IXMLNode ixmlnode2 = ixmlnode.Children[j];
  117. string value = ixmlnode2.value;
  118. if (value != null)
  119. {
  120. if (!(value == "Name"))
  121. {
  122. if (!(value == "Identifier"))
  123. {
  124. if (value == "TextAsset")
  125. {
  126. if (text != null)
  127. {
  128. UnityEngine.Debug.LogWarningFormat("SUISS Localization: Encountered a second TextAsset node for a Culture (existing TextAsset '{0}')", new object[]
  129. {
  130. text
  131. });
  132. }
  133. text = ixmlnode2.Children[0].value;
  134. }
  135. }
  136. else
  137. {
  138. if (text2 != null)
  139. {
  140. UnityEngine.Debug.LogWarningFormat("SUISS Localization: Encountered a second Identifier node for a Culture (existing Identifier '{0}')", new object[]
  141. {
  142. text2
  143. });
  144. }
  145. text2 = ixmlnode2.Children[0].value;
  146. }
  147. }
  148. else
  149. {
  150. list2.Add(ixmlnode2.Children.Find((IXMLNode x) => x.type == XMLNodeType.Text).value);
  151. }
  152. }
  153. }
  154. if (list2.Count == 0)
  155. {
  156. UnityEngine.Debug.LogWarning("SUISS Localization: No Names encountered for a Culture (skipping)");
  157. }
  158. else
  159. {
  160. if (text == null)
  161. {
  162. UnityEngine.Debug.LogWarning("SUISS Localization: No TextAsset encountered for a Culture");
  163. }
  164. if (text2 == null)
  165. {
  166. UnityEngine.Debug.LogWarning("SUISS Localization: No Identifier encountered for a Culture");
  167. }
  168. Localization.Culture item = new Localization.Culture(text2, list2.AsReadOnly(), new CultureInfo(list2[0]), text);
  169. list.Add(item);
  170. }
  171. }
  172. }
  173. }
  174. catch (Exception exception)
  175. {
  176. UnityEngine.Debug.LogException(exception);
  177. }
  178. }
  179. Resources.UnloadAsset(textAsset);
  180. }
  181. catch (Exception exception2)
  182. {
  183. UnityEngine.Debug.LogException(exception2);
  184. }
  185. if (list.Count == 0)
  186. {
  187. list.Add(new Localization.Culture("English", new List<string>(1)
  188. {
  189. "en-US"
  190. }.AsReadOnly(), new CultureInfo("en-US"), null));
  191. }
  192. Localization._availableCultures = list.AsReadOnly();
  193. }
  194. private static void LoadFallbackTranslation()
  195. {
  196. int count = Localization._availableCultures.Count;
  197. for (int i = 0; i < count; i++)
  198. {
  199. if (Localization._availableCultures[i].Identifier == "English")
  200. {
  201. Localization.ReadTranslations(Localization._availableCultures[i].TextAssetName, Localization._fallbackTranslations);
  202. break;
  203. }
  204. }
  205. }
  206. private static void SplitLocale(string languageLocale, out string languageCode, out string countryCode)
  207. {
  208. languageCode = null;
  209. countryCode = null;
  210. int num = languageLocale.IndexOf('-');
  211. if (num == -1)
  212. {
  213. num = languageLocale.IndexOf('_');
  214. }
  215. if (num != -1)
  216. {
  217. languageCode = languageLocale.Substring(0, num);
  218. countryCode = languageLocale.Substring(num + 1);
  219. }
  220. else
  221. {
  222. languageCode = languageLocale;
  223. }
  224. }
  225. public static IList<Localization.Culture> AvailableCultures
  226. {
  227. get
  228. {
  229. return Localization._availableCultures;
  230. }
  231. }
  232. public static Localization.Culture CurrentCulture
  233. {
  234. get
  235. {
  236. return Localization._currentCulture;
  237. }
  238. set
  239. {
  240. if (value != Localization._currentCulture)
  241. {
  242. if (value == null)
  243. {
  244. throw new ArgumentNullException();
  245. }
  246. if (!Localization._availableCultures.Contains(value))
  247. {
  248. throw new ArgumentException("SUISS Localization: The specified Culture is not in the list of available cultures");
  249. }
  250. Localization._currentCulture = value;
  251. Localization._isCurrentCultureArabic = (Localization._currentCulture.Info.TwoLetterISOLanguageName == "ar" || Localization._currentCulture.Info.TwoLetterISOLanguageName == "fa");
  252. Localization.ReadTranslations(Localization._currentCulture.TextAssetName, Localization._translations);
  253. Localization.FireCultureChangedEvent();
  254. }
  255. }
  256. }
  257. public static bool IsCurrentCultureArabic
  258. {
  259. get
  260. {
  261. return Localization._isCurrentCultureArabic;
  262. }
  263. }
  264. public static ILocalizedString Literal(string literal)
  265. {
  266. return new RawLiteralString(literal);
  267. }
  268. public static ILocalizedString Colored(ILocalizedString original, Color color)
  269. {
  270. return new ColorizedString(original, color);
  271. }
  272. public static ILocalizedString Key(string key)
  273. {
  274. return new Localization.RawKeyString(key, long.MinValue);
  275. }
  276. public static ILocalizedString ToUpper(ILocalizedString original)
  277. {
  278. return new RawCapitalizedString(original);
  279. }
  280. public static ILocalizedString ToLower(ILocalizedString original)
  281. {
  282. return new RawLowercasedString(original);
  283. }
  284. public static ILocalizedString FirstCharToUpper(ILocalizedString original)
  285. {
  286. return new RawFirstCharCapitalizedString(original);
  287. }
  288. public static ILocalizedString ShortDateTime(DateTime time)
  289. {
  290. return new RawShortDateTimeString(time);
  291. }
  292. public static ILocalizedString ShortTimeSpan(TimeSpan timeSpan)
  293. {
  294. return new RawTimeSpanString(timeSpan, false, 1);
  295. }
  296. public static ILocalizedString TimeSpan(TimeSpan timeSpan, bool hideSecondPartWhenZero)
  297. {
  298. return new RawTimeSpanString(timeSpan, hideSecondPartWhenZero, 2);
  299. }
  300. public static ILocalizedString FullTimeSpan(TimeSpan timeSpan, bool hidePartWhenZero)
  301. {
  302. return new RawTimeSpanString(timeSpan, hidePartWhenZero, 4);
  303. }
  304. public static ILocalizedString PluralKey(string key, long count)
  305. {
  306. return new Localization.RawKeyString(key, count);
  307. }
  308. public static ILocalizedString Integer(int i)
  309. {
  310. return new RawIntegerString(i);
  311. }
  312. public static ILocalizedString Integer(long l)
  313. {
  314. return new RawLongString(l);
  315. }
  316. public static ILocalizedString Integer(decimal m)
  317. {
  318. return new RawDecimalString(m, 0, true);
  319. }
  320. public static ILocalizedString Float(float f, int decimals, bool showTrailingZeroes)
  321. {
  322. return new RawFloatString(f, decimals, showTrailingZeroes);
  323. }
  324. public static ILocalizedString Float(double d, int decimals, bool showTrailingZeroes)
  325. {
  326. return new RawDoubleString(d, decimals, showTrailingZeroes);
  327. }
  328. public static ILocalizedString Float(decimal m, int decimals, bool showTrailingZeroes)
  329. {
  330. return new RawDecimalString(m, decimals, showTrailingZeroes);
  331. }
  332. public static ILocalizedString Percentage(int p)
  333. {
  334. return new RawPercentageString((float)p, 0);
  335. }
  336. public static ILocalizedString Percentage(float p, int decimals)
  337. {
  338. return new RawPercentageString(p * 100f, decimals);
  339. }
  340. public static ILocalizedString Price(string currencySymbol, decimal price)
  341. {
  342. return new RawPriceString(currencySymbol, price);
  343. }
  344. public static ILocalizedString Format(string literal, params ILocalizedString[] args)
  345. {
  346. return new FormatString(new RawLiteralString(literal), args);
  347. }
  348. public static ILocalizedString Format(ILocalizedString format, params ILocalizedString[] args)
  349. {
  350. return new FormatString(format, args);
  351. }
  352. public static ILocalizedString Concat(params ILocalizedString[] args)
  353. {
  354. return new LocalizedConcat(args);
  355. }
  356. public static bool IsNullOrEmpty(ILocalizedString str)
  357. {
  358. return str == null || str == Localization.EmptyLocalizedString;
  359. }
  360. private static string TranslateInternal(string key)
  361. {
  362. if (key == null)
  363. {
  364. throw new ArgumentNullException("SUISS Localization: key");
  365. }
  366. string result;
  367. if (!Localization._translations.TryGetValue(key, out result))
  368. {
  369. if (!Localization._fallbackTranslations.TryGetValue(key, out result))
  370. {
  371. UnityEngine.Debug.LogErrorFormat("SUISS Localization: Not even {0} has a translation for {1}", new object[]
  372. {
  373. "English",
  374. key
  375. });
  376. result = key;
  377. }
  378. else
  379. {
  380. UnityEngine.Debug.LogWarningFormat("SUISS Localization: No translation found for '{0}'; falling back to {1}", new object[]
  381. {
  382. key,
  383. "English"
  384. });
  385. }
  386. }
  387. return result;
  388. }
  389. private static string TranslatePluralInternal(string key, long count)
  390. {
  391. if (key == null)
  392. {
  393. throw new ArgumentNullException("SUISS Localization: key");
  394. }
  395. string result;
  396. if (!Localization._translations.TryGetValue(key + "$" + count.ToString(CultureInfo.InvariantCulture), out result) && !Localization._translations.TryGetValue(key + "$n", out result) && !Localization._translations.TryGetValue(key, out result))
  397. {
  398. if (!Localization._fallbackTranslations.TryGetValue(key + "$" + count.ToString(CultureInfo.InvariantCulture), out result) && !Localization._fallbackTranslations.TryGetValue(key + "$n", out result) && !Localization._fallbackTranslations.TryGetValue(key, out result))
  399. {
  400. UnityEngine.Debug.LogErrorFormat("SUISS Localization: Not even {0} has a plural translation for {1}", new object[]
  401. {
  402. "English",
  403. key
  404. });
  405. result = key;
  406. }
  407. else
  408. {
  409. UnityEngine.Debug.LogWarningFormat("SUISS Localization: No plural translation found for '{0}'; falling back to {1}", new object[]
  410. {
  411. key,
  412. "English"
  413. });
  414. }
  415. }
  416. return result;
  417. }
  418. private static void ReadTranslations(string textAssetName, Dictionary<string, string> translationDict)
  419. {
  420. translationDict.Clear();
  421. if (string.IsNullOrEmpty(textAssetName))
  422. {
  423. return;
  424. }
  425. TextAsset textAsset = Resources.Load<TextAsset>(textAssetName);
  426. if (textAsset == null)
  427. {
  428. UnityEngine.Debug.LogWarning("SUISS Localization: Could not find translations at \"" + textAssetName + "\"");
  429. return;
  430. }
  431. try
  432. {
  433. using (StringReader stringReader = new StringReader(textAsset.text))
  434. {
  435. int num = 0;
  436. string text;
  437. while ((text = stringReader.ReadLine()) != null)
  438. {
  439. num++;
  440. if (text.Length != 0)
  441. {
  442. int num2 = text.IndexOf('=');
  443. if (num2 < 0)
  444. {
  445. UnityEngine.Debug.LogWarning(string.Concat(new object[]
  446. {
  447. "SUISS Localization: No equals character found in translation (",
  448. textAssetName,
  449. " at line ",
  450. num,
  451. ")"
  452. }));
  453. }
  454. else
  455. {
  456. string text2 = text.Substring(0, num2).Trim();
  457. string text3 = text.Substring(num2 + 1).Trim();
  458. if (translationDict.ContainsKey(text2))
  459. {
  460. UnityEngine.Debug.LogWarning(string.Concat(new object[]
  461. {
  462. "SUISS Localization: Duplicate translation found for '",
  463. text2,
  464. "' (",
  465. textAssetName,
  466. " at line ",
  467. num,
  468. ")"
  469. }));
  470. }
  471. int i = text3.IndexOf('\\');
  472. if (i >= 0)
  473. {
  474. char[] array = text3.ToCharArray();
  475. int num3 = array.Length;
  476. while (i < num3 - 1)
  477. {
  478. if (array[i] == '\\')
  479. {
  480. char c = '\0';
  481. char c2 = array[i + 1];
  482. if (c2 != '\\')
  483. {
  484. if (c2 != 'n')
  485. {
  486. if (c2 != 't')
  487. {
  488. UnityEngine.Debug.LogWarning(string.Concat(new object[]
  489. {
  490. "SUISS Localization: Found unknown escape sequence \\",
  491. array[i + 1],
  492. " (",
  493. textAssetName,
  494. " at line ",
  495. num,
  496. ")"
  497. }));
  498. }
  499. else
  500. {
  501. c = '\t';
  502. }
  503. }
  504. else
  505. {
  506. c = '\n';
  507. }
  508. }
  509. else
  510. {
  511. c = '\\';
  512. }
  513. if (c != '\0')
  514. {
  515. array[i] = c;
  516. for (int j = i + 2; j < num3; j++)
  517. {
  518. array[j - 1] = array[j];
  519. }
  520. num3--;
  521. }
  522. }
  523. i++;
  524. }
  525. text3 = new string(array, 0, num3);
  526. }
  527. translationDict[text2] = text3;
  528. }
  529. }
  530. }
  531. }
  532. }
  533. catch (Exception exception)
  534. {
  535. UnityEngine.Debug.LogException(exception);
  536. }
  537. Resources.UnloadAsset(textAsset);
  538. }
  539. public static readonly ILocalizedString EmptyLocalizedString = new RawLiteralString(string.Empty);
  540. public static readonly ILocalizedString LiteralWhiteSpace = new RawLiteralString(" ");
  541. public static readonly ILocalizedString LiteralNewLineString = new RawLiteralString("\n");
  542. public static readonly ILocalizedString LiteralDoubleNewLineString = new RawLiteralString("\n\n");
  543. public static readonly ILocalizedString LiteralSemiColonSpaceString = new RawLiteralString(": ");
  544. private const string CulturesFile = "Localization/Cultures";
  545. private const string CulturesRootNodeName = "Cultures";
  546. private const string CultureNodeName = "Culture";
  547. private const string CultureNameNodeName = "Name";
  548. private const string CultureIdentifierNodeName = "Identifier";
  549. private const string CultureTextAssetNodeName = "TextAsset";
  550. private const string FallbackLanguageIdentifier = "English";
  551. private const string FallbackLanguageCulture = "en-US";
  552. public const string EnglishTwoLetterISOIdentifier = "en";
  553. public const string FarsiTwoLetterISOIdentifier = "fa";
  554. public const string ArabicTwoLetterISOIdentifier = "ar";
  555. private static IList<Localization.Culture> _availableCultures;
  556. private static Localization.Culture _currentCulture;
  557. private static bool _isCurrentCultureArabic;
  558. private static Dictionary<string, string> _translations = new Dictionary<string, string>();
  559. private static Dictionary<string, string> _fallbackTranslations = new Dictionary<string, string>();
  560. public delegate void CultureEventHandler(Localization.Culture culture);
  561. public sealed class Culture
  562. {
  563. public Culture(string identifier, IList<string> names, CultureInfo info, string textAssetName)
  564. {
  565. this._identifier = identifier;
  566. this._names = names;
  567. this._info = info;
  568. this._textAssetName = textAssetName;
  569. }
  570. public string Identifier
  571. {
  572. get
  573. {
  574. return this._identifier;
  575. }
  576. }
  577. public IList<string> Names
  578. {
  579. get
  580. {
  581. return this._names;
  582. }
  583. }
  584. public CultureInfo Info
  585. {
  586. get
  587. {
  588. return this._info;
  589. }
  590. }
  591. public string TextAssetName
  592. {
  593. get
  594. {
  595. return this._textAssetName;
  596. }
  597. }
  598. public override string ToString()
  599. {
  600. return string.Format("[Culture: Name=\"{0}\", TextAssetName=\"{1}\", Identifier=\"{2}\"]", this._info.Name, this._textAssetName, this._identifier);
  601. }
  602. private IList<string> _names;
  603. private CultureInfo _info;
  604. private string _textAssetName;
  605. private string _identifier;
  606. }
  607. private class RawKeyString : ILocalizedString
  608. {
  609. public RawKeyString(string key, long count)
  610. {
  611. if (key == null)
  612. {
  613. throw new ArgumentNullException("SUISS Localization: key");
  614. }
  615. this._key = key;
  616. this._count = count;
  617. }
  618. public override string ToString()
  619. {
  620. if (this._count == -9223372036854775808L)
  621. {
  622. return "[KeyString=" + this._key + "]";
  623. }
  624. return string.Concat(new object[]
  625. {
  626. "[KeyString=",
  627. this._key,
  628. ",Count=",
  629. this._count,
  630. "]"
  631. });
  632. }
  633. public string Translate()
  634. {
  635. if (this._count == -9223372036854775808L)
  636. {
  637. return Localization.TranslateInternal(this._key);
  638. }
  639. return Localization.TranslatePluralInternal(this._key, this._count);
  640. }
  641. public const long NoCount = -9223372036854775808L;
  642. private string _key;
  643. private long _count;
  644. }
  645. }
  646. }