Decompiled source of CustomTranslation v0.2.0

plugins/CustomTranslation.dll

Decompiled 4 days ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Resources;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Text.RegularExpressions;
using System.Xml;
using BepInEx;
using BepInEx.Logging;
using CustomFont;
using GlobalEnums;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Serialization;
using Silksong.DataManager;
using Silksong.ModMenu.Elements;
using Silksong.ModMenu.Plugin;
using Silksong.ModMenu.Screens;
using TMProOld;
using TeamCherry.Localization;
using TeamCherry.SharedUtils;
using UnityEngine;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("CustomTranslation")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.2.0.0")]
[assembly: AssemblyInformationalVersion("0.2.0+601cf85de81e98a6b78919bf27e1a25ae87a40f5")]
[assembly: AssemblyProduct("CustomTranslation")]
[assembly: AssemblyTitle("CustomTranslation")]
[assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/CarrieForle/CustomTranslationSilksong")]
[assembly: NeutralResourcesLanguage("EN")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.2.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace BepInEx
{
	[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
	[Conditional("CodeGeneration")]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class BepInAutoPluginAttribute : Attribute
	{
		public BepInAutoPluginAttribute(string? id = null, string? name = null, string? version = null)
		{
		}
	}
}
namespace BepInEx.Preloader.Core.Patching
{
	[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
	[Conditional("CodeGeneration")]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class PatcherAutoPluginAttribute : Attribute
	{
		public PatcherAutoPluginAttribute(string? id = null, string? name = null, string? version = null)
		{
		}
	}
}
namespace Microsoft.CodeAnalysis
{
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace CustomTranslation
{
	public enum TranslationFileKind
	{
		Single,
		Splitted
	}
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInPlugin("io.github.carrieforle.customtranslation", "CustomTranslation", "0.2.0")]
	public class CustomTranslationPlugin : BaseUnityPlugin, IGlobalDataMod<GlobalData>, IRawGlobalDataMod, IModMenuCustomMenu, IModMenuInterface
	{
		public const string ENTRY_FILENAME = "entry.json";

		public const string METADATA_FILENAME = "metadata.json";

		public const string ASSET_DIRNAME = "assets";

		public static LanguageReader languageReader = new LanguageReader();

		public static DirectoryInfo translationDir;

		public static DirectoryInfo dir;

		internal static ManualLogSource logger;

		public static CustomTranslationPlugin Instance;

		private Harmony harmony;

		private GlobalData? globalData;

		public const string Id = "io.github.carrieforle.customtranslation";

		public GlobalData? GlobalData
		{
			get
			{
				if (globalData == null)
				{
					globalData = new GlobalData();
				}
				return globalData;
			}
			set
			{
				globalData = value;
			}
		}

		public static string Name => "CustomTranslation";

		public static string Version => "0.2.0";

		private void Awake()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Expected O, but got Unknown
			harmony = new Harmony("io.github.carrieforle.customtranslation");
			harmony.PatchAll(typeof(Patch));
			logger = ((BaseUnityPlugin)this).Logger;
			dir = new DirectoryInfo(Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location));
			translationDir = DirectoryHelper.TryCreateRecursive(dir, "translation");
			Instance = this;
			RefreshLanguage();
		}

		private void Start()
		{
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			harmony.PatchAll(typeof(LanguagePatch));
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Patched Language class");
			LanguagePatch.LoadAvailableLanguages();
			LanguageCode? val = GlobalData?.Language;
			if (val.HasValue)
			{
				LanguageCode valueOrDefault = val.GetValueOrDefault();
				if (languageReader.ContainsKey(valueOrDefault))
				{
					Language.DoSwitch(valueOrDefault);
				}
			}
		}

		private static IList<TranslationEntry> GetTranslationEntries()
		{
			List<TranslationEntry> list = new List<TranslationEntry>();
			DirectoryInfo[] directories = DirectoryHelper.TryCreate(translationDir).GetDirectories();
			string[] validExtensions = new string[2] { ".txt", ".bytes" };
			DirectoryInfo[] array = directories;
			foreach (DirectoryInfo directoryInfo in array)
			{
				if (File.Exists(Path.Combine(directoryInfo.FullName, "metadata.json")))
				{
					if (File.Exists(Path.Combine(directoryInfo.FullName, "entry.json")))
					{
						list.Add(new TranslationEntry(directoryInfo, TranslationFileKind.Single));
					}
					else if (directoryInfo.GetFiles().Any((FileInfo f) => ((ReadOnlySpan<string>)validExtensions).IndexOf(f.Extension) != -1))
					{
						list.Add(new TranslationEntry(directoryInfo, TranslationFileKind.Splitted));
					}
				}
			}
			return list;
		}

		public static void RefreshLanguage()
		{
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			IList<TranslationEntry> translationEntries = GetTranslationEntries();
			languageReader = new LanguageReader();
			foreach (TranslationEntry item in translationEntries)
			{
				try
				{
					TranslationMetadata translationMetadata = TranslationMetadata.ReadFrom(item);
					Translation value = new Translation(translationMetadata, item);
					if (languageReader.TryGetValue(translationMetadata.Language, out Translation translation))
					{
						logger.LogWarning((object)$"Found duplicate entries for '{translationMetadata.Language}' ('{translation.entry.Name}' and '{item.Name}'). Use '{item.Name}'.");
					}
					languageReader[translationMetadata.Language] = value;
				}
				catch (Exception ex)
				{
					logger.LogWarning((object)("Failed to load entry at '" + item.Name + "': " + ex.Message));
				}
			}
			if (translationEntries.Count == 0)
			{
				logger.LogInfo((object)"No entry found.");
			}
			else
			{
				logger.LogInfo((object)string.Format("Found {0} entries. Loaded {1} entries: {2}", translationEntries.Count, languageReader.Count, string.Join(", ", languageReader.LanguageList)));
			}
		}

		public LocalizedText ModMenuName()
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			return LocalizedText.op_Implicit(Text.Localized("NAME"));
		}

		public AbstractMenuScreen BuildCustomMenu()
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Expected O, but got Unknown
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Expected O, but got Unknown
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: Expected O, but got Unknown
			//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0104: Expected O, but got Unknown
			SimpleMenuScreen val = new SimpleMenuScreen(LocalisedString.op_Implicit(Text.Localized("NAME")));
			TextButton val2 = new TextButton(LocalizedText.op_Implicit(Text.Localized("OPTION_OPEN_TRANSLATION_DIRECTORY")));
			val2.OnSubmit = (Action)Delegate.Combine(val2.OnSubmit, (Action)delegate
			{
				//IL_0007: Unknown result type (might be due to invalid IL or missing references)
				bool flag = false;
				try
				{
					if (languageReader.TryGetValue(Language._currentLanguage, out Translation translation))
					{
						DirectoryInfo location = translation.entry.location;
						Process.Start(location.FullName);
						flag = true;
						logger.LogInfo((object)("Opened translation directory \"" + location.FullName + "\""));
					}
					else
					{
						flag = false;
					}
				}
				catch
				{
					flag = false;
				}
				if (!flag)
				{
					DirectoryInfo directoryInfo5 = DirectoryHelper.TryCreate(translationDir);
					Process.Start(directoryInfo5.FullName);
					logger.LogInfo((object)("Opened translation directory \"" + directoryInfo5.FullName + "\""));
				}
			});
			val.Add((MenuElement)(object)val2);
			TextButton val3 = new TextButton(LocalizedText.op_Implicit(Text.Localized("OPTION_RELOAD_TRANSLATION")), LocalizedText.op_Implicit(Text.Localized("OPTION_DESCRIPTION_RELOAD_TRANSLATION")));
			val3.OnSubmit = (Action)Delegate.Combine(val3.OnSubmit, (Action)delegate
			{
				//IL_0076: Unknown result type (might be due to invalid IL or missing references)
				//IL_0097: Unknown result type (might be due to invalid IL or missing references)
				logger.LogInfo((object)"Reloading translation");
				MenuLanguageSetting val8 = default(MenuLanguageSetting);
				if (((Component)((Component)UIManager.instance).transform.Find("UICanvas/GameOptionsMenuScreen/Content/LanguageSetting/LanguageOption")).TryGetComponent<MenuLanguageSetting>(ref val8))
				{
					RefreshLanguage();
					Language.LoadAvailableLanguages();
					MenuLanguageSetting.UpdateLangsArray();
					int num = ((ReadOnlySpan<string>)MenuLanguageSetting.optionList).IndexOf(((object)(LanguageCode)(ref Language._currentLanguage)).ToString());
					if (num != -1)
					{
						((MenuOptionHorizontal)val8).SetOptionTo(num);
					}
					else
					{
						((BaseUnityPlugin)this).Logger.LogWarning((object)$"Unable to load \"{Language._currentLanguage}\". Fallback to EN.");
						MenuLanguageSetting obj = val8;
						ReadOnlySpan<string> span = MenuLanguageSetting.optionList;
						LanguageCode val9 = (LanguageCode)44;
						((MenuOptionHorizontal)obj).SetOptionTo(span.IndexOf(((object)(LanguageCode)(ref val9)).ToString()));
					}
					val8.UpdateLanguageSetting();
					ChangeFontByLanguage[] array = Object.FindObjectsByType<ChangeFontByLanguage>((FindObjectsSortMode)0);
					for (int j = 0; j < array.Length; j++)
					{
						array[j].SetFont();
					}
					((BaseUnityPlugin)this).Logger.LogInfo((object)"Reloaded translation");
				}
			});
			val.Add((MenuElement)(object)val3);
			TextButton val4 = new TextButton(LocalizedText.op_Implicit(Text.Localized("OPTION_EXPORT_TRANSLATION")));
			val4.OnSubmit = (Action)Delegate.Combine(val4.OnSubmit, (Action)delegate
			{
				//IL_006c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0073: Expected O, but got Unknown
				//IL_0073: Unknown result type (might be due to invalid IL or missing references)
				//IL_0078: Unknown result type (might be due to invalid IL or missing references)
				//IL_0084: Expected O, but got Unknown
				//IL_0220: Unknown result type (might be due to invalid IL or missing references)
				//IL_0227: Expected O, but got Unknown
				string text = ((object)(LanguageCode)(ref Language._currentLanguage)).ToString();
				logger.LogInfo((object)("Exporting: " + text));
				DirectoryInfo directoryInfo = DirectoryHelper.TryCreateRecursive(dir, "export/" + text);
				DirectoryInfo directoryInfo2 = new DirectoryInfo(Path.GetTempPath());
				DirectoryInfo directoryInfo3 = DirectoryHelper.TryCreateRecursive(directoryInfo, "entry");
				using StreamWriter streamWriter = new StreamWriter(Path.Combine(directoryInfo3.FullName, "entry.json"));
				JsonTextWriter val5 = new JsonTextWriter((TextWriter)streamWriter);
				try
				{
					JsonSerializer val6 = JsonSerializer.Create(new JsonSerializerSettings
					{
						Formatting = (Formatting)1
					});
					Dictionary<string, Dictionary<string, string>> dictionary = new Dictionary<string, Dictionary<string, string>>();
					string[] sheetTitles = Language.Settings.sheetTitles;
					foreach (string key in sheetTitles)
					{
						if (Language._currentEntrySheets.TryGetValue(key, out var value) && !Extensions.IsNullOrEmpty<KeyValuePair<string, string>>((ICollection<KeyValuePair<string, string>>)value))
						{
							dictionary[key] = value;
						}
					}
					val6.Serialize((JsonWriter)(object)val5, (object)dictionary);
					DirectoryInfo directoryInfo4 = DirectoryHelper.TryCreateRecursive(directoryInfo, "sheet");
					foreach (KeyValuePair<string, Dictionary<string, string>> item in dictionary)
					{
						item.Deconstruct(out var key2, out var value2);
						string text2 = key2;
						Dictionary<string, string> dictionary2 = value2;
						using StreamWriter streamWriter2 = new StreamWriter(Path.Combine(directoryInfo4.FullName, text + "_" + text2 + ".txt"));
						streamWriter2.WriteLine("<entries>");
						foreach (KeyValuePair<string, string> item2 in dictionary2)
						{
							item2.Deconstruct(out key2, out var value3);
							string text3 = key2;
							string str = value3;
							streamWriter2.WriteLine("<entry name=\"" + text3 + "\">" + Text.EscapeXml(str) + "</entry>");
						}
						streamWriter2.WriteLine("</entries>");
					}
					FileInfo fileInfo = new FileInfo(Path.Combine(directoryInfo2.FullName, "metadata.json"));
					using (StreamWriter streamWriter3 = new StreamWriter(fileInfo.FullName))
					{
						JsonTextWriter val7 = new JsonTextWriter((TextWriter)streamWriter3);
						try
						{
							val6.Serialize((JsonWriter)(object)val7, (object)new Dictionary<string, string> { ["Language"] = text });
						}
						finally
						{
							((IDisposable)val7)?.Dispose();
						}
					}
					fileInfo.CopyTo(Path.Combine(directoryInfo4.FullName, fileInfo.Name), overwrite: true);
					fileInfo.CopyTo(Path.Combine(directoryInfo3.FullName, fileInfo.Name), overwrite: true);
					logger.LogInfo((object)("Exported \"" + text + "\""));
					Process.Start(directoryInfo.FullName);
				}
				finally
				{
					((IDisposable)val5)?.Dispose();
				}
			});
			val.Add((MenuElement)(object)val4);
			return (AbstractMenuScreen)val;
		}
	}
	public class GlobalData
	{
		[JsonConverter(typeof(StringEnumConverter))]
		public LanguageCode Language;
	}
	public class Assets
	{
		public enum FontKind
		{
			Title,
			Text
		}

		public TMP_FontAsset? TitleFont;

		public TMP_FontAsset? TextFont;

		private readonly TranslationEntry entry;

		private bool read;

		public Assets(TranslationEntry entry)
		{
			this.entry = entry;
			base..ctor();
		}

		public TMP_FontAsset? GetFont(FontKind kind)
		{
			if (!read)
			{
				DirectoryInfo directoryInfo = new DirectoryInfo(Path.Combine(entry.location.FullName, "assets"));
				if (!directoryInfo.Exists)
				{
					read = true;
					return null;
				}
				FileInfo fileInfo = null;
				try
				{
					FileInfo[] files = directoryInfo.GetFiles();
					foreach (FileInfo fileInfo2 in files)
					{
						try
						{
							if ((Object)(object)TitleFont == (Object)null && (fileInfo2.Name == "title.ttf" || fileInfo2.Name == "title.otf"))
							{
								TitleFont = Text.CreateFontFrom(fileInfo2);
								fileInfo = fileInfo2;
								CustomTranslationPlugin.logger.LogInfo((object)"Loaded title font");
							}
							else if ((Object)(object)TextFont == (Object)null && (fileInfo2.Name == "text.ttf" || fileInfo2.Name == "text.otf"))
							{
								TextFont = Text.CreateFontFrom(fileInfo2);
								fileInfo = fileInfo2;
								CustomTranslationPlugin.logger.LogInfo((object)"Loaded text font");
							}
						}
						catch (Exception ex)
						{
							CustomTranslationPlugin.logger.LogWarning((object)("Error while loading \"" + fileInfo2.FullName + "\": " + ex.Message + "\nThis asset will be skipped."));
						}
					}
					if ((Object)(object)TitleFont == (Object)null && (Object)(object)TextFont != (Object)null && fileInfo != null)
					{
						TitleFont = Text.CreateFontFrom(fileInfo);
					}
					else if ((Object)(object)TitleFont != (Object)null && (Object)(object)TextFont == (Object)null && fileInfo != null)
					{
						TextFont = Text.CreateFontFrom(fileInfo);
					}
				}
				catch (Exception ex2)
				{
					CustomTranslationPlugin.logger.LogError((object)("Error while discovering assets: " + ex2.Message));
				}
				finally
				{
					read = true;
				}
			}
			return (TMP_FontAsset?)(kind switch
			{
				FontKind.Title => TitleFont, 
				FontKind.Text => TextFont, 
				_ => null, 
			});
		}
	}
	public class TranslationEntry
	{
		public DirectoryInfo location;

		public TranslationFileKind kind;

		public string Name => location.Name;

		public TranslationEntry(DirectoryInfo location, TranslationFileKind kind)
		{
			this.location = location;
			this.kind = kind;
			base..ctor();
		}
	}
	public class TranslationMetadata
	{
		[JsonProperty(/*Could not decode attribute arguments.*/)]
		[JsonConverter(typeof(LanguageCodeConverter))]
		public LanguageCode Language { get; set; }

		[JsonProperty(/*Could not decode attribute arguments.*/)]
		[JsonConverter(typeof(LanguageCodeConverter))]
		public LanguageCode FallbackLanguage { get; set; } = (LanguageCode)44;


		[JsonProperty(/*Could not decode attribute arguments.*/)]
		public float TextFontScale { get; set; } = 1f;


		[JsonProperty(/*Could not decode attribute arguments.*/)]
		public float TitleFontScale { get; set; } = 1f;


		[JsonProperty(/*Could not decode attribute arguments.*/)]
		public bool UseFontAsFallBack { get; set; } = true;


		[JsonConstructor]
		public TranslationMetadata(LanguageCode language)
		{
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			Language = language;
		}

		public static TranslationMetadata ReadFrom(TranslationEntry entry)
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			TranslationMetadata translationMetadata = Text.FromJson<TranslationMetadata>(Path.Combine(entry.location.FullName, "metadata.json"));
			if (translationMetadata == null || (int)translationMetadata.Language == 0)
			{
				throw new CustomTranslationException("Invalid language code");
			}
			return translationMetadata;
		}
	}
	public class Translation
	{
		public readonly TranslationMetadata metadata;

		public readonly TranslationEntry entry;

		public readonly Assets assets;

		public Translation(TranslationMetadata metadata, TranslationEntry entry)
		{
			this.metadata = metadata;
			this.entry = entry;
			assets = new Assets(entry);
			base..ctor();
		}

		public bool UpdateSheet()
		{
			string text = "";
			try
			{
				if (entry.kind == TranslationFileKind.Single)
				{
					Dictionary<string, Dictionary<string, string>> dictionary = Text.FromJson<Dictionary<string, Dictionary<string, string>>>(Path.Combine(entry.location.FullName, "entry.json"));
					if (dictionary == null)
					{
						throw new CustomTranslationException("JSON is null");
					}
					string[] sheetTitles = Language.Settings.sheetTitles;
					for (int i = 0; i < sheetTitles.Length; i++)
					{
						text = sheetTitles[i];
						if (!Language._currentEntrySheets.TryGetValue(text, out var value))
						{
							value = new Dictionary<string, string>();
							Language._currentEntrySheets[text] = value;
						}
						if (!dictionary.TryGetValue(text, out var value2))
						{
							continue;
						}
						foreach (KeyValuePair<string, string> item in value2)
						{
							item.Deconstruct(out var key, out var value3);
							string key2 = key;
							string value4 = value3;
							value[key2] = value4;
						}
					}
				}
				else
				{
					FileInfo[] files = entry.location.GetFiles();
					string[] sheetTitles = Language.Settings.sheetTitles;
					foreach (string obj in sheetTitles)
					{
						text = obj;
						if (!Language._currentEntrySheets.TryGetValue(text, out var value5))
						{
							value5 = new Dictionary<string, string>();
							Language._currentEntrySheets[text] = value5;
						}
						Regex pattern = new Regex("[a-zA-Z_]+?" + text + "\\.(?:txt|bytes)");
						FileInfo fileInfo = files.FirstOrDefault((FileInfo f) => pattern.IsMatch(f.Name));
						if (fileInfo == null)
						{
							continue;
						}
						using StreamReader streamReader = new StreamReader(Path.Combine(entry.location.FullName, fileInfo.Name));
						string text2 = streamReader.ReadToEnd();
						if (!text2.Contains('<'))
						{
							text2 = Encryption.Decrypt(text2);
						}
						using XmlReader xmlReader = XmlReader.Create(new StringReader(text2));
						while (xmlReader.ReadToFollowing("entry"))
						{
							xmlReader.MoveToFirstAttribute();
							string value6 = xmlReader.Value;
							xmlReader.MoveToElement();
							string text3 = xmlReader.ReadElementContentAsString().Trim();
							text3 = StringExtensions.UnescapeXml(text3);
							value5[value6] = text3;
						}
					}
				}
				return true;
			}
			catch (Exception ex)
			{
				CustomTranslationPlugin.logger.LogError((object)("Error while loading \"" + entry.Name + "\" entry on sheet \"" + text + "\": " + ex.Message));
				return false;
			}
		}
	}
	public class LanguageReader
	{
		private readonly SortedList<LanguageCode, Translation> languages = new SortedList<LanguageCode, Translation>(Comparer<LanguageCode>.Default);

		public IList<LanguageCode> LanguageList => languages.Keys;

		public int Count => languages.Count;

		public Translation this[LanguageCode lang]
		{
			get
			{
				//IL_0006: Unknown result type (might be due to invalid IL or missing references)
				return languages[lang];
			}
			set
			{
				//IL_0006: Unknown result type (might be due to invalid IL or missing references)
				languages[lang] = value;
			}
		}

		public bool ContainsKey(LanguageCode key)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			return languages.ContainsKey(key);
		}

		public bool TryGetValue(LanguageCode key, out Translation translation)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			return languages.TryGetValue(key, out translation);
		}
	}
	internal class EnumComparer<T> : Comparer<T> where T : Enum
	{
		public override int Compare(T x, T y)
		{
			return x.CompareTo(y);
		}
	}
	internal class LanguagePatch
	{
		[HarmonyPrefix]
		[HarmonyPatch(typeof(Language), "DoSwitch")]
		private static bool DoSwitch(LanguageCode newLang)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_010b: Unknown result type (might be due to invalid IL or missing references)
			//IL_010c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_014e: Unknown result type (might be due to invalid IL or missing references)
			//IL_016e: Unknown result type (might be due to invalid IL or missing references)
			//IL_016f: Unknown result type (might be due to invalid IL or missing references)
			LocalizationProjectSettings.OnSwitchedLanguage(newLang);
			Language._currentLanguage = newLang;
			Language._currentEntrySheets = new Dictionary<string, Dictionary<string, string>>();
			if (CustomTranslationPlugin.languageReader.TryGetValue(newLang, out Translation translation))
			{
				Language._currentLanguage = translation.metadata.FallbackLanguage;
			}
			string[] sheetTitles = Language.Settings.sheetTitles;
			foreach (string text in sheetTitles)
			{
				Language._currentEntrySheets[text] = new Dictionary<string, string>();
				string languageFileContents = Language.GetLanguageFileContents(text);
				if (string.IsNullOrEmpty(languageFileContents))
				{
					continue;
				}
				using XmlReader xmlReader = XmlReader.Create(new StringReader(languageFileContents));
				while (xmlReader.ReadToFollowing("entry"))
				{
					xmlReader.MoveToFirstAttribute();
					string value = xmlReader.Value;
					xmlReader.MoveToElement();
					string text2 = xmlReader.ReadElementContentAsString().Trim();
					text2 = StringExtensions.UnescapeXml(text2);
					Language._currentEntrySheets[text][value] = text2;
				}
			}
			if (CustomTranslationPlugin.languageReader.ContainsKey(newLang))
			{
				CustomTranslationPlugin.languageReader[newLang].UpdateSheet();
			}
			Language._currentLanguage = newLang;
			LocalizedAsset[] array = (LocalizedAsset[])(object)Object.FindObjectsOfType(typeof(LocalizedAsset));
			for (int j = 0; j < array.Length; j++)
			{
				array[j].LocalizeAsset();
			}
			Language.SendMonoMessage("ChangedLanguage", new object[1] { Language._currentLanguage });
			GlobalData? globalData = CustomTranslationPlugin.Instance.GlobalData;
			if (globalData != null)
			{
				globalData.Language = newLang;
			}
			return false;
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(Language), "GetLanguages")]
		private static void GetLanguages(ref string[] __result)
		{
			List<string> list = new List<string>();
			list.AddRange(__result);
			list.AddRange(CustomTranslationPlugin.languageReader.LanguageList.Select((LanguageCode lang) => ((object)(LanguageCode)(ref lang)).ToString()));
			__result = list.ToArray();
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(Language), "LoadAvailableLanguages")]
		public static void LoadAvailableLanguages()
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			foreach (LanguageCode language in CustomTranslationPlugin.languageReader.LanguageList)
			{
				LanguageCode current = language;
				Extensions.AddIfNotPresent<string>(Language._availableLanguages, ((object)(LanguageCode)(ref current)).ToString());
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(Language), "RestoreLanguageSelection")]
		private static void RestoreLanguageFromGlobalData(ref string __result)
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			LanguageCode? val = CustomTranslationPlugin.Instance.GlobalData?.Language;
			if (val.HasValue)
			{
				LanguageCode valueOrDefault = val.GetValueOrDefault();
				__result = ((object)(LanguageCode)(ref valueOrDefault)).ToString();
			}
			CustomTranslationPlugin.logger.LogInfo((object)("Restored language: " + __result));
		}
	}
	internal class Patch
	{
		private static string[]? originalOptionList;

		private static readonly string[] titleFontNames = new string[2] { "trajan_bold_tmpro", "TrajanPro-Bold SDF" };

		[HarmonyPostfix]
		[HarmonyPatch(typeof(MenuLanguageSetting), "UpdateLangsArray")]
		private static void UpdateLangsArray()
		{
			if (originalOptionList == null)
			{
				originalOptionList = MenuLanguageSetting.optionList.ToArray();
			}
			List<string> list = new List<string>();
			list.AddRange(originalOptionList);
			list.AddRange(from lang in CustomTranslationPlugin.languageReader.LanguageList
				select ((object)(LanguageCode)(ref lang)).ToString() into lang
				where !originalOptionList.Any((string og_lang) => lang == og_lang)
				select lang);
			MenuLanguageSetting.optionList = list.ToArray();
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(MenuLanguageSetting), "UpdateLanguageSetting")]
		private static bool UpdateLanguageSetting(MenuLanguageSetting __instance)
		{
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			LanguageCode val;
			if (((MenuOptionHorizontal)__instance).selectedOptionIndex < MenuLanguageSetting.langs.Length)
			{
				GameManager.instance.gameSettings.gameLanguage = MenuLanguageSetting.langs[((MenuOptionHorizontal)__instance).selectedOptionIndex];
				val = (LanguageCode)MenuLanguageSetting.langs[((MenuOptionHorizontal)__instance).selectedOptionIndex];
			}
			else
			{
				GameManager.instance.gameSettings.gameLanguage = (SupportedLanguages)44;
				val = CustomTranslationPlugin.languageReader.LanguageList[((MenuOptionHorizontal)__instance).selectedOptionIndex - MenuLanguageSetting.langs.Length];
			}
			Language.SwitchLanguage(val);
			GameManager.instance.RefreshLocalization();
			((MenuOptionHorizontal)__instance).UpdateText();
			return false;
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(MenuLanguageSetting), "RefreshCurrentIndex")]
		private static void PatchCurrentIndex(MenuLanguageSetting __instance)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			if (!MenuLanguageSetting.languageCodeToSupportedLanguages.ContainsKey(Language._currentLanguage) && CustomTranslationPlugin.languageReader.ContainsKey(Language._currentLanguage))
			{
				int num = ((ReadOnlySpan<string>)MenuLanguageSetting.optionList).IndexOf(((object)(LanguageCode)(ref Language._currentLanguage)).ToString());
				if (num != -1)
				{
					((MenuOptionHorizontal)__instance).selectedOptionIndex = num;
				}
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(ChangeFontByLanguage), "SetFont", new Type[] { })]
		private static void PatchFont(ChangeFontByLanguage __instance)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			ChangeFontByLanguage __instance2 = __instance;
			if (!CustomTranslationPlugin.languageReader.TryGetValue(Language._currentLanguage, out Translation translation))
			{
				return;
			}
			TMP_FontAsset font = translation.assets.GetFont(Assets.FontKind.Text);
			TMP_FontAsset font2 = translation.assets.GetFont(Assets.FontKind.Title);
			TMP_FontAsset val = null;
			float num = 1f;
			if (((Object)__instance2.defaultFont).name == "perpetua_tmpro")
			{
				val = font;
				num = translation.metadata.TextFontScale;
			}
			else if (titleFontNames.Any((string name) => name == ((Object)__instance2.defaultFont).name))
			{
				val = font2;
				num = translation.metadata.TitleFontScale;
			}
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			TextMeshPro tmpro = __instance2.tmpro;
			((TMP_Text)tmpro).fontSize = ((TMP_Text)tmpro).fontSize * num;
			if (translation.metadata.UseFontAsFallBack)
			{
				if (Extensions.IsNullOrEmpty<TMP_FontAsset>((ICollection<TMP_FontAsset>)((TMP_Text)__instance2.tmpro).font.fallbackFontAssets))
				{
					((TMP_Text)__instance2.tmpro).font.fallbackFontAssets = new List<TMP_FontAsset>(1) { val };
				}
				else if (!((TMP_Text)__instance2.tmpro).font.fallbackFontAssets.Contains(val))
				{
					((TMP_Text)__instance2.tmpro).font.fallbackFontAssets.Add(val);
				}
				return;
			}
			val.fallbackFontAssets = ((TMP_Text)__instance2.tmpro).font.fallbackFontAssets;
			if (Extensions.IsNullOrEmpty<TMP_FontAsset>((ICollection<TMP_FontAsset>)val.fallbackFontAssets))
			{
				val.fallbackFontAssets = new List<TMP_FontAsset>(1) { ((TMP_Text)__instance2.tmpro).font };
			}
			else if (!val.fallbackFontAssets.Contains(((TMP_Text)__instance2.tmpro).font))
			{
				val.fallbackFontAssets.Insert(0, ((TMP_Text)__instance2.tmpro).font);
			}
			__instance2.SetFont(val, true);
		}
	}
	public class CustomTranslationException : Exception
	{
		public CustomTranslationException(string message)
			: base(message)
		{
		}
	}
	public static class Text
	{
		public static LocalisedString Localized(string key)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			return new LocalisedString("Mods.io.github.carrieforle.customtranslation", key);
		}

		public static string Localized(string key, params object[] args)
		{
			return string.Format(Language.Get(key, "Mods.io.github.carrieforle.customtranslation"), args);
		}

		public static T? FromJson<T>(string path)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Expected O, but got Unknown
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			using StreamReader streamReader = new StreamReader(path);
			JsonTextReader val = new JsonTextReader((TextReader)streamReader);
			try
			{
				return new JsonSerializer().Deserialize<T>((JsonReader)(object)val);
			}
			finally
			{
				((IDisposable)val)?.Dispose();
			}
		}

		public static string EscapeXml(string str)
		{
			Dictionary<char, string> dictionary = new Dictionary<char, string>
			{
				['\''] = "&apos;",
				['"'] = "&quot;",
				['>'] = "&gt;",
				['<'] = "&lt;",
				['&'] = "&amp;"
			};
			StringBuilder stringBuilder = new StringBuilder(str);
			for (int i = 0; i < stringBuilder.Length; i++)
			{
				if (dictionary.TryGetValue(stringBuilder[i], out var value))
				{
					stringBuilder.Remove(i, 1);
					stringBuilder.Insert(i, value);
					i += value.Length - 1;
				}
			}
			return stringBuilder.ToString();
		}

		public static TMP_FontAsset CreateFontFrom(FileInfo file)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Expected O, but got Unknown
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			return new FontAssetBuilder(new Font(file.FullName))
			{
				AtlasWidth = 4096,
				AtlasHeight = 4096
			}.Create();
		}
	}
	public static class DirectoryHelper
	{
		public static DirectoryInfo TryCreateRecursive(DirectoryInfo dirRoot, string dir)
		{
			return TryCreate(new DirectoryInfo(Path.Combine(dirRoot.FullName, dir)));
		}

		public static DirectoryInfo TryCreate(DirectoryInfo dir)
		{
			dir.Refresh();
			try
			{
				dir.Create();
			}
			catch
			{
			}
			return dir;
		}
	}
	public class LanguageCodeConverter : JsonConverter
	{
		public override bool CanRead { get; } = true;


		public override bool CanWrite { get; }

		public override bool CanConvert(Type objectType)
		{
			return objectType == typeof(LanguageCode);
		}

		public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer)
		{
			throw new NotImplementedException();
		}

		public override object ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer)
		{
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			string val = (string)reader.Value;
			return Enum.GetValues(typeof(LanguageCode)).Cast<LanguageCode>().First((LanguageCode lang) => ((object)(LanguageCode)(ref lang)).ToString().Equals(val, StringComparison.OrdinalIgnoreCase));
		}
	}
	public class BepinExTraceWriter : ITraceWriter
	{
		[CompilerGenerated]
		private ManualLogSource <logger>P;

		public TraceLevel LevelFilter => TraceLevel.Verbose;

		public BepinExTraceWriter(ManualLogSource logger)
		{
			<logger>P = logger;
			base..ctor();
		}

		public void Trace(TraceLevel level, string message, Exception? ex)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			<logger>P.Log(GetLogLevel(level), (object)message);
			if (ex != null)
			{
				<logger>P.Log(GetLogLevel(level), (object)ex);
			}
		}

		private LogLevel GetLogLevel(TraceLevel level)
		{
			return (LogLevel)(level switch
			{
				TraceLevel.Error => 2, 
				TraceLevel.Warning => 4, 
				TraceLevel.Info => 16, 
				TraceLevel.Off => 0, 
				_ => 8, 
			});
		}
	}
}