GoogleTranslation_Queries.cs 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376
  1. using UnityEngine;
  2. using System;
  3. using System.Collections;
  4. using System.Collections.Generic;
  5. using System.Text;
  6. using System.Text.RegularExpressions;
  7. using System.Linq;
  8. namespace I2.Loc
  9. {
  10. using TranslationDictionary = Dictionary<string, TranslationQuery>;
  11. public struct TranslationQuery
  12. {
  13. public string OrigText;
  14. public string Text; // Text without Tags
  15. public string LanguageCode;
  16. public string[] TargetLanguagesCode;
  17. public string[] Results; // This is filled google returns the translations
  18. public string[] Tags; // This are the sections of the orignal text that shoudn't be translated
  19. }
  20. public static partial class GoogleTranslation
  21. {
  22. public static void CreateQueries(string text, string LanguageCodeFrom, string LanguageCodeTo, TranslationDictionary dict)
  23. {
  24. if (!text.Contains("[i2s_"))
  25. {
  26. CreateQueries_Plurals(text, LanguageCodeFrom, LanguageCodeTo, dict);
  27. return;
  28. }
  29. var variants = SpecializationManager.GetSpecializations(text);
  30. foreach (var kvp in variants)
  31. {
  32. CreateQueries_Plurals(kvp.Value, LanguageCodeFrom, LanguageCodeTo, dict);
  33. }
  34. }
  35. static void CreateQueries_Plurals(string text, string LanguageCodeFrom, string LanguageCodeTo, TranslationDictionary dict)
  36. {
  37. bool hasPluralParams = text.Contains("{[#");
  38. bool hasPluralTypes = text.Contains("[i2p_");
  39. if (!HasParameters(text) || (!hasPluralParams && !hasPluralTypes))
  40. {
  41. AddQuery(text, LanguageCodeFrom, LanguageCodeTo, dict);
  42. return;
  43. }
  44. bool forcePluralParam = hasPluralParams;
  45. for (var i = (ePluralType)0; i <= ePluralType.Plural; ++i)
  46. {
  47. var pluralType = i.ToString();
  48. if (!GoogleLanguages.LanguageHasPluralType(LanguageCodeTo, pluralType))
  49. continue;
  50. var newText = GetPluralText(text, pluralType);
  51. int testNumber = GoogleLanguages.GetPluralTestNumber(LanguageCodeTo, i);
  52. var parameter = GetPluralParameter(newText, forcePluralParam);
  53. if (!string.IsNullOrEmpty(parameter))
  54. newText = newText.Replace(parameter, testNumber.ToString());
  55. //Debug.Log("Translate: " + newText);
  56. AddQuery(newText, LanguageCodeFrom, LanguageCodeTo, dict);
  57. }
  58. }
  59. public static void AddQuery(string text, string LanguageCodeFrom, string LanguageCodeTo, TranslationDictionary dict)
  60. {
  61. if (string.IsNullOrEmpty(text))
  62. return;
  63. if (!dict.ContainsKey(text))
  64. {
  65. var query = new TranslationQuery() { OrigText = text, LanguageCode = LanguageCodeFrom, TargetLanguagesCode = new string[] { LanguageCodeTo } };
  66. query.Text = text;
  67. ParseNonTranslatableElements(ref query);
  68. dict[text] = query;
  69. }
  70. else
  71. {
  72. var query = dict[text];
  73. if (System.Array.IndexOf(query.TargetLanguagesCode, LanguageCodeTo) < 0)
  74. {
  75. query.TargetLanguagesCode = query.TargetLanguagesCode.Concat(new string[] { LanguageCodeTo }).Distinct().ToArray();
  76. }
  77. dict[text] = query;
  78. }
  79. }
  80. static string GetTranslation(string text, string LanguageCodeTo, TranslationDictionary dict)
  81. {
  82. if (!dict.ContainsKey(text))
  83. return null;
  84. var query = dict[text];
  85. int langIdx = System.Array.IndexOf(query.TargetLanguagesCode, LanguageCodeTo);
  86. if (langIdx < 0)
  87. return "";
  88. if (query.Results == null)
  89. return "";
  90. return query.Results[langIdx];
  91. }
  92. static TranslationQuery FindQueryFromOrigText(string origText, TranslationDictionary dict)
  93. {
  94. foreach (var kvp in dict)
  95. {
  96. if (kvp.Value.OrigText == origText)
  97. return kvp.Value;
  98. }
  99. return default(TranslationQuery);
  100. }
  101. public static bool HasParameters( string text )
  102. {
  103. int idx = text.IndexOf("{[");
  104. if (idx < 0) return false;
  105. return text.IndexOf("]}", idx) > 0;
  106. }
  107. public static string GetPluralParameter(string text, bool forceTag) // force tag requires that the parameter has the form {[#param]}
  108. {
  109. // Try finding the "plural parameter" that has the form {[#name]}
  110. // this allows using the second parameter as plural: "Player {[name1]} has {[#value]} points"
  111. int idx0 = text.IndexOf("{[#");
  112. if (idx0 < 0)
  113. {
  114. if (forceTag) return null;
  115. idx0 = text.IndexOf("{["); // fallback to the first paremeter if no one has the # tag
  116. }
  117. if (idx0 < 0)
  118. return null;
  119. int idx1 = text.IndexOf("]}", idx0+2);
  120. if (idx1 < 0)
  121. return null; // no closing parameter tag
  122. return text.Substring(idx0, idx1 - idx0 + 2);
  123. }
  124. public static string GetPluralText( string text, string pluralType )
  125. {
  126. pluralType = "[i2p_" + pluralType + "]";
  127. int idx0 = text.IndexOf(pluralType);
  128. if (idx0>=0)
  129. {
  130. idx0 += pluralType.Length;
  131. int idx1 = text.IndexOf("[i2p_",idx0);
  132. if (idx1 < 0) idx1 = text.Length;
  133. return text.Substring(idx0, idx1 - idx0);
  134. }
  135. // PluralType not found, fallback to the first one
  136. idx0 = text.IndexOf("[i2p_");
  137. if (idx0 < 0)
  138. return text; // No plural tags: "my text"
  139. if (idx0>0)
  140. return text.Substring(0, idx0); // Case: "my text[i2p_zero]hello"
  141. // Case: "[i2p_plural]my text[i2p_zero]hello"
  142. idx0 = text.IndexOf("]");
  143. if (idx0 < 0) return text; // starts like a plural, but has none
  144. idx0 += 1;
  145. int idx2 = text.IndexOf("[i2p_", idx0);
  146. if (idx2 < 0) idx2 = text.Length;
  147. return text.Substring(idx0, idx2 - idx0);
  148. }
  149. static int FindClosingTag(string tag, MatchCollection matches, int startIndex)
  150. {
  151. for (int i = startIndex, imax = matches.Count; i < imax; ++i)
  152. {
  153. var newTag = I2Utils.GetCaptureMatch(matches[i]);
  154. if (newTag[0]=='/' && tag.StartsWith(newTag.Substring(1)))
  155. return i;
  156. }
  157. return -1;
  158. }
  159. static string GetGoogleNoTranslateTag(int tagNumber)
  160. {
  161. //return " I2NT" + tagNumber;
  162. if (tagNumber < 70)
  163. return "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++".Substring(0, tagNumber+1);
  164. string s = "";
  165. for (int i = -1; i < tagNumber; ++i)
  166. s += "+";
  167. return s;
  168. }
  169. static void ParseNonTranslatableElements( ref TranslationQuery query )
  170. {
  171. //\[i2nt].*\[\/i2nt]
  172. var matches = Regex.Matches( query.Text, @"\{\[(.*?)]}|\[(.*?)]|\<(.*?)>");
  173. if (matches == null || matches.Count == 0)
  174. return;
  175. string finalText = query.Text;
  176. List<string> finalTags = new List<string>();
  177. for (int i=0, imax=matches.Count; i<imax; ++i)
  178. {
  179. var tag = I2Utils.GetCaptureMatch( matches[i] );
  180. int iClosingTag = FindClosingTag(tag, matches, i); // find [/tag] or </tag>
  181. if (iClosingTag < 0)
  182. {
  183. // Its not a tag, its a parameter
  184. var fulltag = matches[i].ToString();
  185. if (fulltag.StartsWith("{[") && fulltag.EndsWith("]}"))
  186. {
  187. finalText = finalText.Replace(fulltag, GetGoogleNoTranslateTag(finalTags.Count)+" "); // 0x2600 is the start of the UNICODE Miscellaneous Symbols table, so they are not going to be translated by google
  188. //finalText = finalText.Replace(fulltag, /*"{[" + finalTags.Count + "]}"*/ ((char)(0x2600 + finalTags.Count)).ToString()); // 0x2600 is the start of the UNICODE Miscellaneous Symbols table, so they are not going to be translated by google
  189. finalTags.Add(fulltag);
  190. }
  191. continue;
  192. }
  193. if (tag == "i2nt")
  194. {
  195. var tag1 = query.Text.Substring(matches[i].Index, (matches[iClosingTag].Index-matches[i].Index) + matches[iClosingTag].Length);
  196. finalText = finalText.Replace(tag1, GetGoogleNoTranslateTag(finalTags.Count)+" ");
  197. //finalText = finalText.Replace(tag1, /*"{[" + finalTags.Count + "]}"*/ ((char)(0x2600 + finalTags.Count)).ToString());
  198. finalTags.Add(tag1);
  199. }
  200. else
  201. {
  202. var tag1 = matches[i].ToString();
  203. finalText = finalText.Replace(tag1, GetGoogleNoTranslateTag(finalTags.Count)+" ");
  204. //finalText = finalText.Replace(tag1, /*"{[" + finalTags.Count + "]}"*/ ((char)(0x2600 + finalTags.Count)).ToString());
  205. finalTags.Add(tag1);
  206. var tag2 = matches[iClosingTag].ToString();
  207. finalText = finalText.Replace(tag2, GetGoogleNoTranslateTag(finalTags.Count)+" ");
  208. //finalText = finalText.Replace(tag2, /*"{[" + finalTags.Count + "]}"*/ ((char)(0x2600 + finalTags.Count)).ToString());
  209. finalTags.Add(tag2);
  210. }
  211. }
  212. query.Text = finalText;
  213. query.Tags = finalTags.ToArray();
  214. }
  215. public static string GetQueryResult(string text, string LanguageCodeTo, TranslationDictionary dict)
  216. {
  217. if (!dict.ContainsKey(text))
  218. return null;
  219. var query = dict[text];
  220. if (query.Results == null || query.Results.Length < 0)
  221. return null;
  222. if (string.IsNullOrEmpty(LanguageCodeTo))
  223. return query.Results[0];
  224. int idx = System.Array.IndexOf(query.TargetLanguagesCode, LanguageCodeTo);
  225. if (idx < 0)
  226. return null;
  227. return query.Results[idx];
  228. }
  229. public static string RebuildTranslation(string text, TranslationDictionary dict, string LanguageCodeTo)
  230. {
  231. if (!text.Contains("[i2s_"))
  232. {
  233. return RebuildTranslation_Plural(text, dict, LanguageCodeTo);
  234. }
  235. var variants = SpecializationManager.GetSpecializations(text);
  236. var results = new Dictionary<string,string>();
  237. foreach (var kvp in variants)
  238. {
  239. results[kvp.Key] = RebuildTranslation_Plural(kvp.Value, dict, LanguageCodeTo);
  240. }
  241. return SpecializationManager.SetSpecializedText(results);
  242. }
  243. static string RebuildTranslation_Plural( string text, TranslationDictionary dict, string LanguageCodeTo )
  244. {
  245. bool hasPluralParams = text.Contains("{[#");
  246. bool hasPluralTypes = text.Contains("[i2p_");
  247. if (!HasParameters(text) || (!hasPluralParams && !hasPluralTypes))
  248. {
  249. return GetTranslation (text, LanguageCodeTo, dict);
  250. }
  251. var sb = new System.Text.StringBuilder();
  252. string pluralTranslation = null;
  253. bool forcePluralParam = hasPluralParams;
  254. for (var i = ePluralType.Plural; i >= (ePluralType)0; --i)
  255. {
  256. var pluralType = i.ToString();
  257. if (!GoogleLanguages.LanguageHasPluralType(LanguageCodeTo, pluralType))
  258. continue;
  259. var newText = GetPluralText(text, pluralType);
  260. int testNumber = GoogleLanguages.GetPluralTestNumber(LanguageCodeTo, i);
  261. var parameter = GetPluralParameter(newText, forcePluralParam);
  262. if (!string.IsNullOrEmpty(parameter))
  263. newText = newText.Replace(parameter, testNumber.ToString());
  264. var translation = GetTranslation(newText, LanguageCodeTo, dict);
  265. //Debug.LogFormat("from: {0} -> {1}", newText, translation);
  266. if (!string.IsNullOrEmpty(parameter))
  267. translation = translation.Replace(testNumber.ToString(), parameter);
  268. if (i==ePluralType.Plural)
  269. {
  270. pluralTranslation = translation;
  271. }
  272. else
  273. {
  274. if (translation == pluralTranslation)
  275. continue;
  276. sb.AppendFormat("[i2p_{0}]", pluralType);
  277. }
  278. sb.Append(translation);
  279. }
  280. return sb.ToString ();
  281. }
  282. public static string UppercaseFirst(string s)
  283. {
  284. if (string.IsNullOrEmpty(s))
  285. {
  286. return string.Empty;
  287. }
  288. char[] a = s.ToLower().ToCharArray();
  289. a[0] = char.ToUpper(a[0]);
  290. return new string(a);
  291. }
  292. public static string TitleCase(string s)
  293. {
  294. if (string.IsNullOrEmpty(s))
  295. {
  296. return string.Empty;
  297. }
  298. #if NETFX_CORE
  299. var sb = new StringBuilder(s);
  300. sb[0] = char.ToUpper(sb[0]);
  301. for (int i = 1, imax=s.Length; i<imax; ++i)
  302. {
  303. if (char.IsWhiteSpace(sb[i - 1]))
  304. sb[i] = char.ToUpper(sb[i]);
  305. else
  306. sb[i] = char.ToLower(sb[i]);
  307. }
  308. return sb.ToString();
  309. #else
  310. return System.Globalization.CultureInfo.CurrentCulture.TextInfo.ToTitleCase(s);
  311. #endif
  312. }
  313. }
  314. }