using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Text; using UnityEngine; using UnityEngine.SceneManagement; namespace I2.Loc { [AddComponentMenu("I2/Localization/Source")] [ExecuteInEditMode] public class LanguageSource : MonoBehaviour { private void Awake() { this.NeverDestroy = false; if (this.NeverDestroy) { if (this.ManagerHasASimilarSource()) { UnityEngine.Object.Destroy(this); return; } if (Application.isPlaying) { UnityEngine.Object.DontDestroyOnLoad(base.gameObject); } } LocalizationManager.AddSource(this); this.UpdateDictionary(false); this.UpdateAssetDictionary(); LocalizationManager.LocalizeAll(true); } private void OnDestroy() { this.NeverDestroy = false; if (!this.NeverDestroy) { LocalizationManager.RemoveSource(this); } } public string GetSourceName() { string text = base.gameObject.name; Transform parent = base.transform.parent; while (parent) { text = parent.name + "_" + text; parent = parent.parent; } return text; } public bool IsEqualTo(LanguageSource Source) { if (Source.mLanguages.Count != this.mLanguages.Count) { return false; } int i = 0; int count = this.mLanguages.Count; while (i < count) { if (Source.GetLanguageIndex(this.mLanguages[i].Name, true, true) < 0) { return false; } i++; } if (Source.mTerms.Count != this.mTerms.Count) { return false; } for (int j = 0; j < this.mTerms.Count; j++) { if (Source.GetTermData(this.mTerms[j].Term, false) == null) { return false; } } return true; } internal bool ManagerHasASimilarSource() { int i = 0; int count = LocalizationManager.Sources.Count; while (i < count) { LanguageSource languageSource = LocalizationManager.Sources[i]; if (languageSource != null && languageSource.IsEqualTo(this) && languageSource != this) { return true; } i++; } return false; } public void ClearAllData() { this.mTerms.Clear(); this.mLanguages.Clear(); this.mDictionary.Clear(); this.mAssetDictionary.Clear(); } public bool IsGlobalSource() { return this.mIsGlobalSource; } public void UpdateAssetDictionary() { this.Assets.RemoveAll((UnityEngine.Object x) => x == null); this.mAssetDictionary = this.Assets.Distinct().ToDictionary((UnityEngine.Object o) => o.name); } public UnityEngine.Object FindAsset(string Name) { if (this.Assets != null) { if (this.mAssetDictionary == null || this.mAssetDictionary.Count != this.Assets.Count) { this.UpdateAssetDictionary(); } UnityEngine.Object result; if (this.mAssetDictionary.TryGetValue(Name, out result)) { return result; } } return null; } public bool HasAsset(UnityEngine.Object Obj) { return this.Assets.Contains(Obj); } public void AddAsset(UnityEngine.Object Obj) { if (this.Assets.Contains(Obj)) { return; } this.Assets.Add(Obj); this.UpdateAssetDictionary(); } public string Export_I2CSV(string Category, char Separator = ',', bool specializationsAsRows = true) { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append("Key[*]Type[*]Desc"); foreach (LanguageData languageData in this.mLanguages) { stringBuilder.Append("[*]"); if (!languageData.IsEnabled()) { stringBuilder.Append('$'); } stringBuilder.Append(GoogleLanguages.GetCodedLanguage(languageData.Name, languageData.Code)); } stringBuilder.Append("[ln]"); int count = this.mLanguages.Count; bool flag = true; foreach (TermData termData in this.mTerms) { string term; if (string.IsNullOrEmpty(Category) || (Category == LanguageSource.EmptyCategory && termData.Term.IndexOfAny(LanguageSource.CategorySeparators) < 0)) { term = termData.Term; } else { if (!termData.Term.StartsWith(Category + "/") || !(Category != termData.Term)) { continue; } term = termData.Term.Substring(Category.Length + 1); } if (!flag) { stringBuilder.Append("[ln]"); } flag = false; if (!specializationsAsRows) { LanguageSource.AppendI2Term(stringBuilder, count, term, termData, Separator, null); } else { List allSpecializations = termData.GetAllSpecializations(); for (int i = 0; i < allSpecializations.Count; i++) { if (i != 0) { stringBuilder.Append("[ln]"); } string forceSpecialization = allSpecializations[i]; LanguageSource.AppendI2Term(stringBuilder, count, term, termData, Separator, forceSpecialization); } } } return stringBuilder.ToString(); } private static void AppendI2Term(StringBuilder Builder, int nLanguages, string Term, TermData termData, char Separator, string forceSpecialization) { LanguageSource.AppendI2Text(Builder, Term); if (!string.IsNullOrEmpty(forceSpecialization) && forceSpecialization != "Any") { Builder.Append("["); Builder.Append(forceSpecialization); Builder.Append("]"); } Builder.Append("[*]"); Builder.Append(termData.TermType.ToString()); Builder.Append("[*]"); Builder.Append(termData.Description); for (int i = 0; i < Mathf.Min(nLanguages, termData.Languages.Length); i++) { Builder.Append("[*]"); string text = termData.Languages[i]; if (!string.IsNullOrEmpty(forceSpecialization)) { text = termData.GetTranslation(i, forceSpecialization); } LanguageSource.AppendI2Text(Builder, text); } } private static void AppendI2Text(StringBuilder Builder, string text) { if (string.IsNullOrEmpty(text)) { return; } if (text.StartsWith("'") || text.StartsWith("=")) { Builder.Append('\''); } Builder.Append(text); } private string Export_Language_to_Cache(int langIndex, bool fillTermWithFallback) { if (!this.mLanguages[langIndex].IsLoaded()) { return null; } StringBuilder stringBuilder = new StringBuilder(); for (int i = 0; i < this.mTerms.Count; i++) { if (i > 0) { stringBuilder.Append("[i2t]"); } TermData termData = this.mTerms[i]; string text = termData.Languages[langIndex]; if (this.OnMissingTranslation == LanguageSource.MissingTranslationAction.Fallback && string.IsNullOrEmpty(text) && this.TryGetFallbackTranslation(termData, out text, langIndex, null, true)) { stringBuilder.Append("[i2fb]"); if (fillTermWithFallback) { termData.Languages[langIndex] = text; } } if (!string.IsNullOrEmpty(text)) { stringBuilder.Append(text); } } return stringBuilder.ToString(); } public string Export_CSV(string Category, char Separator = ',', bool specializationsAsRows = true) { StringBuilder stringBuilder = new StringBuilder(); int count = this.mLanguages.Count; stringBuilder.AppendFormat("Key{0}Type{0}Desc", Separator); foreach (LanguageData languageData in this.mLanguages) { stringBuilder.Append(Separator); if (!languageData.IsEnabled()) { stringBuilder.Append('$'); } LanguageSource.AppendString(stringBuilder, GoogleLanguages.GetCodedLanguage(languageData.Name, languageData.Code), Separator); } stringBuilder.Append("\n"); this.mTerms.Sort((TermData a, TermData b) => string.CompareOrdinal(a.Term, b.Term)); foreach (TermData termData in this.mTerms) { string term; if (string.IsNullOrEmpty(Category) || (Category == LanguageSource.EmptyCategory && termData.Term.IndexOfAny(LanguageSource.CategorySeparators) < 0)) { term = termData.Term; } else { if (!termData.Term.StartsWith(Category + "/") || !(Category != termData.Term)) { continue; } term = termData.Term.Substring(Category.Length + 1); } if (specializationsAsRows) { foreach (string specialization in termData.GetAllSpecializations()) { LanguageSource.AppendTerm(stringBuilder, count, term, termData, specialization, Separator); } } else { LanguageSource.AppendTerm(stringBuilder, count, term, termData, null, Separator); } } return stringBuilder.ToString(); } private static void AppendTerm(StringBuilder Builder, int nLanguages, string Term, TermData termData, string specialization, char Separator) { LanguageSource.AppendString(Builder, Term, Separator); if (!string.IsNullOrEmpty(specialization) && specialization != "Any") { Builder.AppendFormat("[{0}]", specialization); } Builder.Append(Separator); Builder.Append(termData.TermType.ToString()); Builder.Append(Separator); LanguageSource.AppendString(Builder, termData.Description, Separator); for (int i = 0; i < Mathf.Min(nLanguages, termData.Languages.Length); i++) { Builder.Append(Separator); string text = termData.Languages[i]; if (!string.IsNullOrEmpty(specialization)) { text = termData.GetTranslation(i, specialization); } LanguageSource.AppendTranslation(Builder, text, Separator, null); } Builder.Append("\n"); } private static void AppendString(StringBuilder Builder, string Text, char Separator) { if (string.IsNullOrEmpty(Text)) { return; } Text = Text.Replace("\\n", "\n"); if (Text.IndexOfAny((Separator + "\n\"").ToCharArray()) >= 0) { Text = Text.Replace("\"", "\"\""); Builder.AppendFormat("\"{0}\"", Text); } else { Builder.Append(Text); } } private static void AppendTranslation(StringBuilder Builder, string Text, char Separator, string tags) { if (string.IsNullOrEmpty(Text)) { return; } Text = Text.Replace("\\n", "\n"); if (Text.IndexOfAny((Separator + "\n\"").ToCharArray()) >= 0) { Text = Text.Replace("\"", "\"\""); Builder.AppendFormat("\"{0}{1}\"", tags, Text); } else { Builder.Append(tags); Builder.Append(Text); } } public WWW Export_Google_CreateWWWcall(eSpreadsheetUpdateMode UpdateMode = eSpreadsheetUpdateMode.Replace) { string value = this.Export_Google_CreateData(); WWWForm wwwform = new WWWForm(); wwwform.AddField("key", this.Google_SpreadsheetKey); wwwform.AddField("action", "SetLanguageSource"); wwwform.AddField("data", value); wwwform.AddField("updateMode", UpdateMode.ToString()); return new WWW(LocalizationManager.GetWebServiceURL(this), wwwform); } private string Export_Google_CreateData() { List categories = this.GetCategories(true, null); StringBuilder stringBuilder = new StringBuilder(); bool flag = true; foreach (string text in categories) { if (flag) { flag = false; } else { stringBuilder.Append(""); } bool flag2 = true; string category = text; bool specializationsAsRows = flag2; string value = this.Export_I2CSV(category, ',', specializationsAsRows); stringBuilder.Append(text); stringBuilder.Append(""); stringBuilder.Append(value); } return stringBuilder.ToString(); } public string Import_CSV(string Category, string CSVstring, eSpreadsheetUpdateMode UpdateMode = eSpreadsheetUpdateMode.Replace, char Separator = ',', LanguageSource.CsvSetTranslationPrevDelegate callBackSetTranslationPrev = null) { List csv = LocalizationReader.ReadCSV(CSVstring, Separator); return this.Import_CSV(Category, csv, UpdateMode, callBackSetTranslationPrev); } public string Import_I2CSV(string Category, string I2CSVstring, eSpreadsheetUpdateMode UpdateMode = eSpreadsheetUpdateMode.Replace, LanguageSource.CsvSetTranslationPrevDelegate callBackSetTranslationPrev = null) { List csv = LocalizationReader.ReadI2CSV(I2CSVstring); return this.Import_CSV(Category, csv, UpdateMode, callBackSetTranslationPrev); } public string Import_CSV(string Category, List CSV, eSpreadsheetUpdateMode UpdateMode = eSpreadsheetUpdateMode.Replace, LanguageSource.CsvSetTranslationPrevDelegate callBackSetTranslationPrev = null) { List list = new List(CSV); CSV.Clear(); foreach (string[] array in list) { if (0 < array.Length && !string.IsNullOrEmpty(array[0])) { CSV.Add(array); } } string[] array2 = CSV[0]; int num = 1; int num2 = -1; int num3 = -1; string[] texts = new string[] { "Key" }; string[] texts2 = new string[] { "Type" }; string[] texts3 = new string[] { "Desc", "Description" }; if (array2.Length > 1 && this.ArrayContains(array2[0], texts)) { if (UpdateMode == eSpreadsheetUpdateMode.Replace) { this.ClearAllData(); } if (array2.Length > 2) { if (this.ArrayContains(array2[1], texts2)) { num2 = 1; num = 2; } if (this.ArrayContains(array2[1], texts3)) { num3 = 1; num = 2; } } if (array2.Length > 3) { if (this.ArrayContains(array2[2], texts2)) { num2 = 2; num = 3; } if (this.ArrayContains(array2[2], texts3)) { num3 = 2; num = 3; } } int num4 = Mathf.Max(array2.Length - num, 0); int[] array3 = new int[num4]; for (int i = 0; i < num4; i++) { if (string.IsNullOrEmpty(array2[i + num])) { array3[i] = -1; } else { string text = array2[i + num]; bool flag = true; if (text.StartsWith("$")) { flag = false; text = text.Substring(1); } string text2; string text3; GoogleLanguages.UnPackCodeFromLanguageName(text, out text2, out text3); int num5; if (!string.IsNullOrEmpty(text3)) { num5 = this.GetLanguageIndexFromCode(text3, true); } else { num5 = this.GetLanguageIndex(text2, true, false); } if (num5 < 0) { LanguageData languageData = new LanguageData(); languageData.Name = text2; languageData.Code = text3; languageData.Flags = (byte)(0 | ((!flag) ? 1 : 0)); this.mLanguages.Add(languageData); num5 = this.mLanguages.Count - 1; } array3[i] = num5; } } num4 = this.mLanguages.Count; int j = 0; int count = this.mTerms.Count; while (j < count) { TermData termData = this.mTerms[j]; if (termData.Languages.Length < num4) { Array.Resize(ref termData.Languages, num4); Array.Resize(ref termData.Flags, num4); } j++; } int k = 1; int count2 = CSV.Count; while (k < count2) { array2 = CSV[k]; string text4 = (!string.IsNullOrEmpty(Category)) ? (Category + "/" + array2[0]) : array2[0]; string text5 = null; if (text4.EndsWith("]")) { int num6 = text4.LastIndexOf('['); if (num6 > 0) { text5 = text4.Substring(num6 + 1, text4.Length - num6 - 2); if (text5 == "touch") { text5 = "Touch"; } text4 = text4.Remove(num6); } } LanguageSource.ValidateFullTerm(ref text4); if (!string.IsNullOrEmpty(text4)) { TermData termData2 = this.GetTermData(text4, false); if (termData2 == null) { termData2 = new TermData(); termData2.Term = text4; termData2.Languages = new string[this.mLanguages.Count]; termData2.Flags = new byte[this.mLanguages.Count]; for (int l = 0; l < this.mLanguages.Count; l++) { termData2.Languages[l] = string.Empty; } this.mTerms.Add(termData2); this.mDictionary.Add(text4, termData2); } else if (UpdateMode == eSpreadsheetUpdateMode.AddNewTerms) { goto IL_4F2; } if (num2 > 0) { termData2.TermType = LanguageSource.GetTermType(array2[num2]); } if (num3 > 0) { termData2.Description = array2[num3]; } int num7 = 0; while (num7 < array3.Length && num7 < array2.Length - num) { if (!string.IsNullOrEmpty(array2[num7 + num])) { int num8 = array3[num7]; if (num8 >= 0) { string text6 = array2[num7 + num]; if (text6 == "-") { text6 = string.Empty; } else if (text6 == string.Empty) { text6 = null; } if (callBackSetTranslationPrev != null) { callBackSetTranslationPrev(this.mLanguages[num8], ref text6, ref text5); } termData2.SetTranslation(num8, text6, text5); } } num7++; } } IL_4F2: k++; } return string.Empty; } return "Bad Spreadsheet Format.\nFirst columns should be 'Key', 'Type' and 'Desc'"; } private bool ArrayContains(string MainText, params string[] texts) { int i = 0; int num = texts.Length; while (i < num) { if (MainText.IndexOf(texts[i], StringComparison.OrdinalIgnoreCase) >= 0) { return true; } i++; } return false; } public static eTermType GetTermType(string type) { int i = 0; int num = 10; while (i <= num) { eTermType eTermType = (eTermType)i; if (string.Equals(eTermType.ToString(), type, StringComparison.OrdinalIgnoreCase)) { return (eTermType)i; } i++; } return eTermType.Text; } private void Import_Language_from_Cache(int langIndex, string langData, bool useFallback, bool onlyCurrentSpecialization) { int num = 0; int num2; for (int i = 0; i < langData.Length; i = num2 + 5) { TermData termData = this.mTerms[num]; num++; num2 = langData.IndexOf("[i2t]", i); if (num2 < 0) { num2 = langData.Length; } string text = null; if (i != num2) { text = langData.Substring(i, num2 - i); if (text.StartsWith("[i2fb]")) { text = ((!useFallback) ? null : text.Substring(6)); } if (onlyCurrentSpecialization && text != null) { text = SpecializationManager.GetSpecializedText(text, null); } } termData.Languages[langIndex] = text; } } [DebuggerBrowsable(DebuggerBrowsableState.Never)] public event Action Event_OnSourceUpdateFromGoogle; public static void FreeUnusedLanguages() { LanguageSource languageSource = LocalizationManager.Sources[0]; int languageIndex = languageSource.GetLanguageIndex(LocalizationManager.CurrentLanguage, true, true); for (int i = 0; i < languageSource.mTerms.Count; i++) { TermData termData = languageSource.mTerms[i]; for (int j = 0; j < termData.Languages.Length; j++) { if (j != languageIndex) { termData.Languages[j] = null; } } } } public void Import_Google_FromCache() { if (this.GoogleUpdateFrequency == LanguageSource.eGoogleUpdateFrequency.Never) { return; } if (!I2Utils.IsPlaying()) { return; } string sourcePlayerPrefName = this.GetSourcePlayerPrefName(); string text = PersistentStorage.LoadFile(PersistentStorage.eFileType.Persistent, "I2Source_" + sourcePlayerPrefName + ".loc", false); if (string.IsNullOrEmpty(text)) { return; } if (text.StartsWith("[i2e]", StringComparison.Ordinal)) { text = StringObfucator.Decode(text.Substring(5, text.Length - 5)); } bool flag = false; string text2 = this.Google_LastUpdatedVersion; if (PersistentStorage.HasSetting("I2SourceVersion_" + sourcePlayerPrefName)) { text2 = PersistentStorage.GetSetting_String("I2SourceVersion_" + sourcePlayerPrefName, this.Google_LastUpdatedVersion); flag = this.IsNewerVersion(this.Google_LastUpdatedVersion, text2); } if (!flag) { PersistentStorage.DeleteFile(PersistentStorage.eFileType.Persistent, "I2Source_" + sourcePlayerPrefName + ".loc", false); PersistentStorage.DeleteSetting("I2SourceVersion_" + sourcePlayerPrefName); return; } if (text2.Length > 19) { text2 = string.Empty; } this.Google_LastUpdatedVersion = text2; this.Import_Google_Result(text, eSpreadsheetUpdateMode.Replace, false); } private bool IsNewerVersion(string currentVersion, string newVersion) { long num; long num2; return !string.IsNullOrEmpty(newVersion) && (string.IsNullOrEmpty(currentVersion) || (!long.TryParse(newVersion, out num) || !long.TryParse(currentVersion, out num2)) || num > num2); } public void Import_Google(bool ForceUpdate, bool justCheck) { if (!ForceUpdate && this.GoogleUpdateFrequency == LanguageSource.eGoogleUpdateFrequency.Never) { return; } if (!I2Utils.IsPlaying()) { return; } LanguageSource.eGoogleUpdateFrequency googleUpdateFrequency = this.GoogleUpdateFrequency; string sourcePlayerPrefName = this.GetSourcePlayerPrefName(); if (!ForceUpdate && googleUpdateFrequency != LanguageSource.eGoogleUpdateFrequency.Always) { string setting_String = PersistentStorage.GetSetting_String("LastGoogleUpdate_" + sourcePlayerPrefName, string.Empty); try { DateTime d; if (DateTime.TryParse(setting_String, out d)) { double totalDays = (DateTime.Now - d).TotalDays; switch (googleUpdateFrequency) { case LanguageSource.eGoogleUpdateFrequency.Daily: if (totalDays < 1.0) { return; } break; case LanguageSource.eGoogleUpdateFrequency.Weekly: if (totalDays < 8.0) { return; } break; case LanguageSource.eGoogleUpdateFrequency.Monthly: if (totalDays < 31.0) { return; } break; case LanguageSource.eGoogleUpdateFrequency.OnlyOnce: return; } } } catch (Exception) { } } PersistentStorage.SetSetting_String("LastGoogleUpdate_" + sourcePlayerPrefName, DateTime.Now.ToString()); CoroutineManager.Start(this.Import_Google_Coroutine(justCheck)); } private string GetSourcePlayerPrefName() { string text = base.name; if (!string.IsNullOrEmpty(this.Google_SpreadsheetKey)) { text += this.Google_SpreadsheetKey; } if (Array.IndexOf(LocalizationManager.GlobalSources, base.name) >= 0) { return text; } return SceneManager.GetActiveScene().name + "_" + text; } private IEnumerator Import_Google_Coroutine(bool JustCheck) { WWW www = this.Import_Google_CreateWWWcall(false, JustCheck); if (www == null) { yield break; } while (!www.isDone) { yield return null; } bool notError = string.IsNullOrEmpty(www.error); string wwwText = null; if (notError) { byte[] bytes = www.bytes; wwwText = Encoding.UTF8.GetString(bytes, 0, bytes.Length); bool flag = string.IsNullOrEmpty(wwwText) || wwwText == "\"\""; if (JustCheck) { if (!flag) { UnityEngine.Debug.LogWarning("Spreadsheet is not up-to-date and Google Live Synchronization is enabled\nWhen playing in the device the Spreadsheet will be downloaded and translations may not behave as what you see in the editor.\nTo fix this, Import or Export replace to Google"); } yield break; } if (!flag) { string value = this.Import_Google_Result(wwwText, eSpreadsheetUpdateMode.Replace, true); if (string.IsNullOrEmpty(value)) { if (this.Event_OnSourceUpdateFromGoogle != null) { this.Event_OnSourceUpdateFromGoogle(this, true, www.error); } LocalizationManager.LocalizeAll(true); UnityEngine.Debug.Log("Done Google Sync"); } else { if (this.Event_OnSourceUpdateFromGoogle != null) { this.Event_OnSourceUpdateFromGoogle(this, false, www.error); } UnityEngine.Debug.Log("Done Google Sync: source was up-to-date"); } yield break; } } if (this.Event_OnSourceUpdateFromGoogle != null) { this.Event_OnSourceUpdateFromGoogle(this, false, www.error); } UnityEngine.Debug.Log("Language Source was up-to-date with Google Spreadsheet"); yield break; } public WWW Import_Google_CreateWWWcall(bool ForceUpdate, bool justCheck) { if (!this.HasGoogleSpreadsheet()) { return null; } string text = PersistentStorage.GetSetting_String("I2SourceVersion_" + this.GetSourcePlayerPrefName(), this.Google_LastUpdatedVersion); if (text.Length > 19) { text = string.Empty; } if (this.IsNewerVersion(text, this.Google_LastUpdatedVersion)) { this.Google_LastUpdatedVersion = text; } string url = string.Format("{0}?key={1}&action=GetLanguageSource&version={2}", LocalizationManager.GetWebServiceURL(this), this.Google_SpreadsheetKey, (!ForceUpdate) ? this.Google_LastUpdatedVersion : "0"); return new WWW(url); } public bool HasGoogleSpreadsheet() { return !string.IsNullOrEmpty(this.Google_WebServiceURL) && !string.IsNullOrEmpty(this.Google_SpreadsheetKey) && !string.IsNullOrEmpty(LocalizationManager.GetWebServiceURL(this)); } public string Import_Google_Result(string JsonString, eSpreadsheetUpdateMode UpdateMode, bool saveInPlayerPrefs = false) { string result; try { string empty = string.Empty; if (string.IsNullOrEmpty(JsonString) || JsonString == "\"\"") { result = empty; } else { int num = JsonString.IndexOf("version=", StringComparison.Ordinal); int num2 = JsonString.IndexOf("script_version=", StringComparison.Ordinal); if (num < 0 || num2 < 0) { result = "Invalid Response from Google, Most likely the WebService needs to be updated"; } else { num += "version=".Length; num2 += "script_version=".Length; string text = JsonString.Substring(num, JsonString.IndexOf(",", num, StringComparison.Ordinal) - num); int num3 = int.Parse(JsonString.Substring(num2, JsonString.IndexOf(",", num2, StringComparison.Ordinal) - num2)); if (text.Length > 19) { text = string.Empty; } if (num3 != LocalizationManager.GetRequiredWebServiceVersion()) { result = "The current Google WebService is not supported.\nPlease, delete the WebService from the Google Drive and Install the latest version."; } else if (saveInPlayerPrefs && !this.IsNewerVersion(this.Google_LastUpdatedVersion, text)) { result = "LanguageSource is up-to-date"; } else { if (saveInPlayerPrefs) { string sourcePlayerPrefName = this.GetSourcePlayerPrefName(); PersistentStorage.SaveFile(PersistentStorage.eFileType.Persistent, "I2Source_" + sourcePlayerPrefName, "[i2e]" + StringObfucator.Encode(JsonString) + ".loc", true); PersistentStorage.SetSetting_String("I2SourceVersion_" + sourcePlayerPrefName, text); PersistentStorage.ForceSaveSettings(); } this.Google_LastUpdatedVersion = text; if (UpdateMode == eSpreadsheetUpdateMode.Replace) { this.ClearAllData(); } int i = JsonString.IndexOf("[i2category]", StringComparison.Ordinal); while (i > 0) { i += "[i2category]".Length; int num4 = JsonString.IndexOf("[/i2category]", i, StringComparison.Ordinal); string category = JsonString.Substring(i, num4 - i); num4 += "[/i2category]".Length; int num5 = JsonString.IndexOf("[/i2csv]", num4, StringComparison.Ordinal); string i2CSVstring = JsonString.Substring(num4, num5 - num4); i = JsonString.IndexOf("[i2category]", num5, StringComparison.Ordinal); this.Import_I2CSV(category, i2CSVstring, UpdateMode, null); if (UpdateMode == eSpreadsheetUpdateMode.Replace) { UpdateMode = eSpreadsheetUpdateMode.Merge; } } if (I2Utils.IsPlaying()) { this.SaveLanguages(true, PersistentStorage.eFileType.Temporal); } result = empty; } } } } catch (Exception ex) { UnityEngine.Debug.LogWarning(ex); result = ex.ToString(); } return result; } public int GetLanguageIndex(string language, bool AllowDiscartingRegion = true, bool SkipDisabled = true) { int i = 0; int count = this.mLanguages.Count; while (i < count) { if ((!SkipDisabled || this.mLanguages[i].IsEnabled()) && string.Compare(this.mLanguages[i].Name, language, StringComparison.OrdinalIgnoreCase) == 0) { return i; } i++; } if (AllowDiscartingRegion) { int num = -1; int num2 = 0; int j = 0; int count2 = this.mLanguages.Count; while (j < count2) { if (!SkipDisabled || this.mLanguages[j].IsEnabled()) { int commonWordInLanguageNames = LanguageSource.GetCommonWordInLanguageNames(this.mLanguages[j].Name, language); if (commonWordInLanguageNames > num2) { num2 = commonWordInLanguageNames; num = j; } } j++; } if (num >= 0) { return num; } } return -1; } public LanguageData GetLanguageData(string language, bool AllowDiscartingRegion = true) { int languageIndex = this.GetLanguageIndex(language, AllowDiscartingRegion, false); return (languageIndex >= 0) ? this.mLanguages[languageIndex] : null; } public bool IsCurrentLanguage(int languageIndex) { return LocalizationManager.CurrentLanguage == this.mLanguages[languageIndex].Name; } public int GetLanguageIndexFromCode(string Code, bool exactMatch = true) { int i = 0; int count = this.mLanguages.Count; while (i < count) { if (string.Compare(this.mLanguages[i].Code, Code, StringComparison.OrdinalIgnoreCase) == 0) { return i; } i++; } if (!exactMatch) { int j = 0; int count2 = this.mLanguages.Count; while (j < count2) { if (string.Compare(this.mLanguages[j].Code, 0, Code, 0, 2, StringComparison.OrdinalIgnoreCase) == 0) { return j; } j++; } } return -1; } public static int GetCommonWordInLanguageNames(string Language1, string Language2) { if (string.IsNullOrEmpty(Language1) || string.IsNullOrEmpty(Language2)) { return 0; } char[] separator = "( )-/\\".ToCharArray(); string[] array = Language1.ToLower().Split(separator); string[] array2 = Language2.ToLower().Split(separator); int num = 0; foreach (string value in array) { if (!string.IsNullOrEmpty(value) && array2.Contains(value)) { num++; } } foreach (string value2 in array2) { if (!string.IsNullOrEmpty(value2) && array.Contains(value2)) { num++; } } return num; } public static bool AreTheSameLanguage(string Language1, string Language2) { Language1 = LanguageSource.GetLanguageWithoutRegion(Language1); Language2 = LanguageSource.GetLanguageWithoutRegion(Language2); return string.Compare(Language1, Language2, StringComparison.OrdinalIgnoreCase) == 0; } public static string GetLanguageWithoutRegion(string Language) { int num = Language.IndexOfAny("(/\\[,{".ToCharArray()); if (num < 0) { return Language; } return Language.Substring(0, num).Trim(); } public void AddLanguage(string LanguageName) { this.AddLanguage(LanguageName, GoogleLanguages.GetLanguageCode(LanguageName, false)); } public void AddLanguage(string LanguageName, string LanguageCode) { if (this.GetLanguageIndex(LanguageName, false, true) >= 0) { return; } LanguageData languageData = new LanguageData(); languageData.Name = LanguageName; languageData.Code = LanguageCode; this.mLanguages.Add(languageData); int count = this.mLanguages.Count; int i = 0; int count2 = this.mTerms.Count; while (i < count2) { Array.Resize(ref this.mTerms[i].Languages, count); Array.Resize(ref this.mTerms[i].Flags, count); i++; } } public void RemoveLanguage(string LanguageName) { int languageIndex = this.GetLanguageIndex(LanguageName, false, false); if (languageIndex < 0) { return; } int count = this.mLanguages.Count; int i = 0; int count2 = this.mTerms.Count; while (i < count2) { for (int j = languageIndex + 1; j < count; j++) { this.mTerms[i].Languages[j - 1] = this.mTerms[i].Languages[j]; this.mTerms[i].Flags[j - 1] = this.mTerms[i].Flags[j]; } Array.Resize(ref this.mTerms[i].Languages, count - 1); Array.Resize(ref this.mTerms[i].Flags, count - 1); i++; } this.mLanguages.RemoveAt(languageIndex); } public List GetLanguages(bool skipDisabled = true) { List list = new List(); int i = 0; int count = this.mLanguages.Count; while (i < count) { if (!skipDisabled || this.mLanguages[i].IsEnabled()) { list.Add(this.mLanguages[i].Name); } i++; } return list; } public List GetLanguagesCode(bool allowRegions = true, bool skipDisabled = true) { List list = new List(); int i = 0; int count = this.mLanguages.Count; while (i < count) { if (!skipDisabled || this.mLanguages[i].IsEnabled()) { string text = this.mLanguages[i].Code; if (!allowRegions && text != null && text.Length > 2) { text = text.Substring(0, 2); } if (!string.IsNullOrEmpty(text) && !list.Contains(text)) { list.Add(text); } } i++; } return list; } public bool IsLanguageEnabled(string Language) { int languageIndex = this.GetLanguageIndex(Language, false, true); return languageIndex >= 0 && this.mLanguages[languageIndex].IsEnabled(); } public void EnableLanguage(string Language, bool bEnabled) { int languageIndex = this.GetLanguageIndex(Language, false, true); if (languageIndex >= 0) { this.mLanguages[languageIndex].SetEnabled(bEnabled); } } private string GetSavedLanguageFileName(int languageIndex) { if (languageIndex < 0) { return null; } return string.Concat(new string[] { "LangSource_", this.GetSourcePlayerPrefName(), "_", this.mLanguages[languageIndex].Name, ".loc" }); } public void LoadLanguage(int languageIndex, bool UnloadOtherLanguages, bool useFallback, bool onlyCurrentSpecialization, bool forceLoad) { if (!PersistentStorage.CanAccessFiles()) { return; } if (languageIndex >= 0 && (forceLoad || !this.mLanguages[languageIndex].IsLoaded())) { string savedLanguageFileName = this.GetSavedLanguageFileName(languageIndex); string text = PersistentStorage.LoadFile(PersistentStorage.eFileType.Temporal, savedLanguageFileName, false); if (!string.IsNullOrEmpty(text)) { this.Import_Language_from_Cache(languageIndex, text, useFallback, onlyCurrentSpecialization); this.mLanguages[languageIndex].SetLoaded(true); } } if (UnloadOtherLanguages && I2Utils.IsPlaying()) { for (int i = 0; i < this.mLanguages.Count; i++) { if (i != languageIndex) { this.UnloadLanguage(i); } } } } public void LoadAllLanguages(bool forceLoad = false) { for (int i = 0; i < this.mLanguages.Count; i++) { this.LoadLanguage(i, false, false, false, forceLoad); } } public void UnloadLanguage(int languageIndex) { if (!PersistentStorage.CanAccessFiles()) { return; } if (!I2Utils.IsPlaying() || !this.mLanguages[languageIndex].IsLoaded() || !this.mLanguages[languageIndex].CanBeUnloaded() || this.IsCurrentLanguage(languageIndex) || !PersistentStorage.HasFile(PersistentStorage.eFileType.Temporal, this.GetSavedLanguageFileName(languageIndex), true)) { return; } foreach (TermData termData in this.mTerms) { termData.Languages[languageIndex] = null; } this.mLanguages[languageIndex].SetLoaded(false); } public void SaveLanguages(bool unloadAll, PersistentStorage.eFileType fileLocation = PersistentStorage.eFileType.Temporal) { if (!PersistentStorage.CanAccessFiles()) { return; } for (int i = 0; i < this.mLanguages.Count; i++) { string text = this.Export_Language_to_Cache(i, true); if (!string.IsNullOrEmpty(text)) { PersistentStorage.SaveFile(PersistentStorage.eFileType.Temporal, this.GetSavedLanguageFileName(i), text, true); } } if (unloadAll) { for (int j = 0; j < this.mLanguages.Count; j++) { if (unloadAll && !this.IsCurrentLanguage(j)) { this.UnloadLanguage(j); } } } } public List GetCategories(bool OnlyMainCategory = false, List Categories = null) { if (Categories == null) { Categories = new List(); } foreach (TermData termData in this.mTerms) { string categoryFromFullTerm = LanguageSource.GetCategoryFromFullTerm(termData.Term, OnlyMainCategory); if (!Categories.Contains(categoryFromFullTerm)) { Categories.Add(categoryFromFullTerm); } } Categories.Sort(); return Categories; } public static string GetKeyFromFullTerm(string FullTerm, bool OnlyMainCategory = false) { int num = (!OnlyMainCategory) ? FullTerm.LastIndexOfAny(LanguageSource.CategorySeparators) : FullTerm.IndexOfAny(LanguageSource.CategorySeparators); return (num >= 0) ? FullTerm.Substring(num + 1) : FullTerm; } public static string GetCategoryFromFullTerm(string FullTerm, bool OnlyMainCategory = false) { int num = (!OnlyMainCategory) ? FullTerm.LastIndexOfAny(LanguageSource.CategorySeparators) : FullTerm.IndexOfAny(LanguageSource.CategorySeparators); return (num >= 0) ? FullTerm.Substring(0, num) : LanguageSource.EmptyCategory; } public static void DeserializeFullTerm(string FullTerm, out string Key, out string Category, bool OnlyMainCategory = false) { int num = (!OnlyMainCategory) ? FullTerm.LastIndexOfAny(LanguageSource.CategorySeparators) : FullTerm.IndexOfAny(LanguageSource.CategorySeparators); if (num < 0) { Category = LanguageSource.EmptyCategory; Key = FullTerm; } else { Category = FullTerm.Substring(0, num); Key = FullTerm.Substring(num + 1); } } public void UpdateDictionary(bool force = false) { if (!force && this.mDictionary != null && this.mDictionary.Count == this.mTerms.Count) { return; } StringComparer stringComparer = (!this.CaseInsensitiveTerms) ? StringComparer.Ordinal : StringComparer.OrdinalIgnoreCase; if (this.mDictionary.Comparer != stringComparer) { this.mDictionary = new Dictionary(stringComparer); } else { this.mDictionary.Clear(); } int i = 0; int count = this.mTerms.Count; while (i < count) { TermData termData = this.mTerms[i]; LanguageSource.ValidateFullTerm(ref termData.Term); this.mDictionary[termData.Term] = this.mTerms[i]; this.mTerms[i].Validate(); i++; } if (I2Utils.IsPlaying()) { this.SaveLanguages(true, PersistentStorage.eFileType.Temporal); } } public string GetTranslation(string term, string overrideLanguage = null, string overrideSpecialization = null, bool skipDisabled = false, bool allowCategoryMistmatch = false) { string result; if (this.TryGetTranslation(term, out result, overrideLanguage, overrideSpecialization, skipDisabled, allowCategoryMistmatch)) { return result; } return string.Empty; } public bool TryGetTranslation(string term, out string Translation, string overrideLanguage = null, string overrideSpecialization = null, bool skipDisabled = false, bool allowCategoryMistmatch = false) { int languageIndex = this.GetLanguageIndex((overrideLanguage != null) ? overrideLanguage : LocalizationManager.CurrentLanguage, true, false); if (languageIndex >= 0 && (!skipDisabled || this.mLanguages[languageIndex].IsEnabled())) { TermData termData = this.GetTermData(term, allowCategoryMistmatch); if (termData != null) { Translation = termData.GetTranslation(languageIndex, overrideSpecialization); if (Translation == "---") { Translation = string.Empty; return true; } if (!string.IsNullOrEmpty(Translation)) { return true; } Translation = null; } if (this.OnMissingTranslation == LanguageSource.MissingTranslationAction.ShowWarning) { Translation = string.Format("", term); return true; } if (this.OnMissingTranslation == LanguageSource.MissingTranslationAction.Fallback && termData != null) { return this.TryGetFallbackTranslation(termData, out Translation, languageIndex, overrideSpecialization, skipDisabled); } if (this.OnMissingTranslation == LanguageSource.MissingTranslationAction.Empty) { Translation = string.Empty; return true; } } Translation = null; return false; } private bool TryGetFallbackTranslation(TermData termData, out string Translation, int langIndex, string overrideSpecialization = null, bool skipDisabled = false) { string text = this.mLanguages[langIndex].Code; if (!string.IsNullOrEmpty(text)) { if (text.Contains('-')) { text = text.Substring(0, text.IndexOf('-')); } for (int i = 0; i < this.mLanguages.Count; i++) { if (i != langIndex && this.mLanguages[i].Code.StartsWith(text) && (!skipDisabled || this.mLanguages[i].IsEnabled())) { Translation = termData.GetTranslation(i, overrideSpecialization); if (!string.IsNullOrEmpty(Translation)) { return true; } } } } for (int j = 0; j < this.mLanguages.Count; j++) { if (j != langIndex && (!skipDisabled || this.mLanguages[j].IsEnabled()) && (text == null || !this.mLanguages[j].Code.StartsWith(text))) { Translation = termData.GetTranslation(j, overrideSpecialization); if (!string.IsNullOrEmpty(Translation)) { return true; } } } Translation = null; return false; } public TermData AddTerm(string term) { return this.AddTerm(term, eTermType.Text, true); } public TermData GetTermData(string term, bool allowCategoryMistmatch = false) { if (string.IsNullOrEmpty(term)) { return null; } if (this.mDictionary.Count == 0) { this.UpdateDictionary(false); } TermData result; if (this.mDictionary.TryGetValue(term, out result)) { return result; } TermData termData = null; if (allowCategoryMistmatch) { string keyFromFullTerm = LanguageSource.GetKeyFromFullTerm(term, false); foreach (KeyValuePair keyValuePair in this.mDictionary) { if (keyValuePair.Value.IsTerm(keyFromFullTerm, true)) { if (termData != null) { return null; } termData = keyValuePair.Value; } } return termData; } return termData; } public bool ContainsTerm(string term) { return this.GetTermData(term, false) != null; } public List GetTermsList(string Category = null) { if (this.mDictionary.Count != this.mTerms.Count) { this.UpdateDictionary(false); } if (string.IsNullOrEmpty(Category)) { return new List(this.mDictionary.Keys); } List list = new List(); for (int i = 0; i < this.mTerms.Count; i++) { TermData termData = this.mTerms[i]; if (LanguageSource.GetCategoryFromFullTerm(termData.Term, false) == Category) { list.Add(termData.Term); } } return list; } public TermData AddTerm(string NewTerm, eTermType termType, bool SaveSource = true) { LanguageSource.ValidateFullTerm(ref NewTerm); NewTerm = NewTerm.Trim(); if (this.mLanguages.Count == 0) { this.AddLanguage("English", "en"); } TermData termData = this.GetTermData(NewTerm, false); if (termData == null) { termData = new TermData(); termData.Term = NewTerm; termData.TermType = termType; termData.Languages = new string[this.mLanguages.Count]; termData.Flags = new byte[this.mLanguages.Count]; this.mTerms.Add(termData); this.mDictionary.Add(NewTerm, termData); } return termData; } public void RemoveTerm(string term) { int i = 0; int count = this.mTerms.Count; while (i < count) { if (this.mTerms[i].Term == term) { this.mTerms.RemoveAt(i); this.mDictionary.Remove(term); return; } i++; } } public static void ValidateFullTerm(ref string Term) { Term = Term.Replace('\\', '/'); Term = Term.Trim(); if (Term.StartsWith(LanguageSource.EmptyCategory, StringComparison.Ordinal) && Term.Length > LanguageSource.EmptyCategory.Length && Term[LanguageSource.EmptyCategory.Length] == '/') { Term = Term.Substring(LanguageSource.EmptyCategory.Length + 1); } Term = I2Utils.RemoveNonASCII(Term, true); } public bool NeverDestroy; public bool UserAgreesToHaveItOnTheScene; public bool UserAgreesToHaveItInsideThePluginsFolder; [NonSerialized] public bool mIsGlobalSource; public List Assets = new List(); [NonSerialized] public Dictionary mAssetDictionary = new Dictionary(StringComparer.Ordinal); public string Google_WebServiceURL; public string Google_SpreadsheetKey; public string Google_SpreadsheetName; public string Google_LastUpdatedVersion; public LanguageSource.eGoogleUpdateFrequency GoogleUpdateFrequency = LanguageSource.eGoogleUpdateFrequency.Weekly; public LanguageSource.eGoogleUpdateFrequency GoogleInEditorCheckFrequency = LanguageSource.eGoogleUpdateFrequency.Daily; public float GoogleUpdateDelay = 5f; public List mLanguages = new List(); public bool IgnoreDeviceLanguage; public static string EmptyCategory = "Default"; public static char[] CategorySeparators = "/\\".ToCharArray(); public List mTerms = new List(); public bool CaseInsensitiveTerms; [NonSerialized] public Dictionary mDictionary = new Dictionary(StringComparer.Ordinal); public LanguageSource.MissingTranslationAction OnMissingTranslation = LanguageSource.MissingTranslationAction.Fallback; public string mTerm_AppName; public delegate void CsvSetTranslationPrevDelegate(LanguageData setTargetLanguage, ref string setTranslation, ref string setSpecialization); public enum eGoogleUpdateFrequency { Always, Never, Daily, Weekly, Monthly, OnlyOnce } public enum MissingTranslationAction { Empty, Fallback, ShowWarning } } }