Decompiled source of Valheim Ascended PTBR v1.0.0

plugins/ValheimAscended_PTBR.dll

Decompiled 11 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using System.Text.RegularExpressions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using TMPro;
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("ValheimAscended_PTBR")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("ValheimAscended_PTBR")]
[assembly: AssemblyTitle("ValheimAscended_PTBR")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[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 ValheimAscendedPTBR
{
	[BepInPlugin("glitnir.valheimascended.ptbr", "Valheim Ascended PT-BR", "1.0.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class Plugin : BaseUnityPlugin
	{
		public const string Guid = "glitnir.valheimascended.ptbr";

		public const string ModName = "Valheim Ascended PT-BR";

		public const string Version = "1.0.0";

		private const string VaGuid = "com.valheimascended.mod";

		internal static ManualLogSource Log;

		internal static Translator Tr;

		internal static ConfigEntry<bool> Enabled;

		internal static ConfigEntry<bool> TranslateTmp;

		internal static ConfigEntry<bool> ColorizeKeywords;

		internal static ConfigEntry<string> DictionaryFile;

		internal static ConfigEntry<KeyboardShortcut> ReloadKey;

		internal static ConfigEntry<bool> DumpUntranslated;

		private static string _pluginDir;

		private static Type _terminalType;

		private static readonly Dictionary<int, bool> SkipCache = new Dictionary<int, bool>();

		private static HashSet<string> _dumped;

		private static string _dumpPath;

		private Harmony _harmony;

		private static readonly Regex EnglishWord = new Regex("[A-Za-z]{3,}", RegexOptions.CultureInvariant);

		private static bool _loggedError;

		private void Awake()
		{
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_011e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0128: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			_pluginDir = Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location) ?? Paths.PluginPath;
			Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("1 - Geral", "Ativado", true, "Liga/desliga a tradução do Valheim Ascended.");
			TranslateTmp = ((BaseUnityPlugin)this).Config.Bind<bool>("1 - Geral", "TraduzirTextMeshPro", true, "Também traduz textos TextMeshPro (mensagens na tela, dicas de item, texto de hover, menu de personagens). Chat e console nunca são traduzidos.");
			ColorizeKeywords = ((BaseUnityPlugin)this).Config.Bind<bool>("1 - Geral", "ColorirPalavrasChave", true, "Colore palavras-chave em português nas descrições de talentos (fogo, gelo, veneno, sangramento...), igual o mod faz com as palavras em inglês.");
			DictionaryFile = ((BaseUnityPlugin)this).Config.Bind<string>("1 - Geral", "ArquivoDicionario", "translations/pt-BR.json", "Dicionário principal (relativo à pasta do plugin). Se existir 'translations/pt-BR.custom.json', ele é carregado por cima — use esse arquivo para as suas correções, assim elas não se perdem ao atualizar.");
			ReloadKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("1 - Geral", "TeclaRecarregar", new KeyboardShortcut((KeyCode)289, (KeyCode[])(object)new KeyCode[1] { (KeyCode)306 }), "Recarrega o dicionário sem reiniciar o jogo (útil para testar traduções).");
			DumpUntranslated = ((BaseUnityPlugin)this).Config.Bind<bool>("9 - Debug", "SalvarNaoTraduzidos", false, "Salva em BepInEx/ValheimAscended_PTBR_nao_traduzidos.txt os textos de interface que continuaram em inglês. Útil para completar o dicionário quando o Valheim Ascended atualizar.");
			LoadDictionary();
			_terminalType = AccessTools.TypeByName("Terminal");
			_harmony = new Harmony("glitnir.valheimascended.ptbr");
			ApplyPatches();
		}

		private void Update()
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			KeyboardShortcut value = ReloadKey.Value;
			if (((KeyboardShortcut)(ref value)).IsDown())
			{
				LoadDictionary();
				Log.LogMessage((object)"Dicionário recarregado.");
			}
		}

		private void OnDestroy()
		{
			Harmony harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
		}

		internal static void LoadDictionary()
		{
			Translator translator = new Translator();
			Dictionary<string, string> dictionary = new Dictionary<string, string>(StringComparer.Ordinal);
			string path = Path.Combine(_pluginDir, DictionaryFile.Value);
			if (File.Exists(path))
			{
				LoadInto(dictionary, path);
			}
			else
			{
				LoadEmbedded(dictionary);
			}
			string path2 = Path.Combine(Path.GetDirectoryName(path) ?? _pluginDir, Path.GetFileNameWithoutExtension(path) + ".custom.json");
			LoadInto(dictionary, path2);
			LoadInto(dictionary, Path.Combine(Paths.ConfigPath, "ValheimAscended_PTBR.custom.json"));
			string[] array = new string[5] { "STR", "AGI", "INT", "END", "DEX" };
			foreach (string text in array)
			{
				string key = "% per " + text;
				if (!dictionary.ContainsKey(key))
				{
					dictionary[key] = "% por " + text;
				}
			}
			translator.Load(dictionary);
			Tr = translator;
			SkipCache.Clear();
			Log.LogInfo((object)$"Dicionário carregado: {translator.LiteralCount} literais, {translator.TemplateCount} modelos ({translator.SkippedCount} ignorados).");
		}

		private static void LoadEmbedded(Dictionary<string, string> target)
		{
			try
			{
				using Stream stream = typeof(Plugin).Assembly.GetManifestResourceStream("ValheimAscendedPTBR.pt-BR.json");
				if (stream == null)
				{
					Log.LogError((object)"Dicionário embutido não encontrado na DLL.");
					return;
				}
				using StreamReader streamReader = new StreamReader(stream, Encoding.UTF8);
				Dictionary<string, string> dictionary = MiniJson.ParseFlatObject(streamReader.ReadToEnd());
				foreach (KeyValuePair<string, string> item in dictionary)
				{
					target[item.Key] = item.Value;
				}
				Log.LogInfo((object)$"Dicionário embutido: {dictionary.Count} entradas.");
			}
			catch (Exception ex)
			{
				Log.LogError((object)("Erro lendo o dicionário embutido: " + ex.Message));
			}
		}

		private static void LoadInto(Dictionary<string, string> target, string path)
		{
			if (!File.Exists(path))
			{
				return;
			}
			try
			{
				Dictionary<string, string> dictionary = MiniJson.ParseFlatObject(File.ReadAllText(path, Encoding.UTF8));
				foreach (KeyValuePair<string, string> item in dictionary)
				{
					target[item.Key] = item.Value;
				}
				Log.LogInfo((object)$"{Path.GetFileName(path)}: {dictionary.Count} entradas.");
			}
			catch (Exception ex)
			{
				Log.LogError((object)("Erro lendo " + path + ": " + ex.Message));
			}
		}

		private void ApplyPatches()
		{
			TryPatch(AccessTools.PropertySetter(typeof(Text), "text"), "UiTextPrefix");
			TryPatch(AccessTools.PropertySetter(typeof(TMP_Text), "text"), "TmpTextPrefix");
			TryPatch(AccessTools.Method(typeof(TMP_Text), "SetText", new Type[2]
			{
				typeof(string),
				typeof(bool)
			}, (Type[])null), "TmpSetTextPrefix");
			Type type = AccessTools.TypeByName("ValheimAscended.UI.TalentPanel");
			if (type != null)
			{
				TryPatch(AccessTools.Method(type, "ColorizeDescription", new Type[1] { typeof(string) }, (Type[])null), "ColorizePrefix", "ColorizePostfix");
			}
			else
			{
				Log.LogWarning((object)"Valheim Ascended não encontrado — só a tradução genérica de texto está ativa.");
			}
		}

		private void TryPatch(MethodBase target, string prefix = null, string postfix = null)
		{
			//IL_0043: 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)
			if (target == null)
			{
				Log.LogWarning((object)("Método alvo não encontrado para " + (prefix ?? postfix) + "."));
				return;
			}
			try
			{
				_harmony.Patch(target, (prefix == null) ? ((HarmonyMethod)null) : new HarmonyMethod(typeof(Plugin), prefix, (Type[])null), (postfix == null) ? ((HarmonyMethod)null) : new HarmonyMethod(typeof(Plugin), postfix, (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			}
			catch (Exception ex)
			{
				Log.LogError((object)("Falha ao aplicar patch em " + target.DeclaringType?.Name + "." + target.Name + ": " + ex.Message));
			}
		}

		private static void UiTextPrefix(Text __instance, ref string value)
		{
			if (!Enabled.Value || Tr == null || string.IsNullOrEmpty(value) || (Object)(object)__instance == (Object)null)
			{
				return;
			}
			try
			{
				if (!IsInputText(__instance))
				{
					string text = Tr.Translate(value);
					if (DumpUntranslated.Value && text == value)
					{
						Dump(value);
					}
					value = text;
				}
			}
			catch (Exception e)
			{
				LogOnce(e);
			}
		}

		private static void TmpTextPrefix(TMP_Text __instance, ref string value)
		{
			if (!Enabled.Value || !TranslateTmp.Value || Tr == null || string.IsNullOrEmpty(value) || (Object)(object)__instance == (Object)null)
			{
				return;
			}
			try
			{
				if (!IsInputOrChat(__instance))
				{
					value = Tr.Translate(value);
				}
			}
			catch (Exception e)
			{
				LogOnce(e);
			}
		}

		private static void TmpSetTextPrefix(TMP_Text __instance, ref string __0)
		{
			TmpTextPrefix(__instance, ref __0);
		}

		private static void ColorizePrefix(ref string __0)
		{
			if (!Enabled.Value || Tr == null || string.IsNullOrEmpty(__0))
			{
				return;
			}
			try
			{
				__0 = Tr.Translate(__0);
			}
			catch (Exception e)
			{
				LogOnce(e);
			}
		}

		private static void ColorizePostfix(ref string __result)
		{
			if (!Enabled.Value || !ColorizeKeywords.Value || string.IsNullOrEmpty(__result))
			{
				return;
			}
			try
			{
				__result = PtColorizer.Apply(__result);
			}
			catch (Exception e)
			{
				LogOnce(e);
			}
		}

		private static bool IsInputText(Text t)
		{
			int instanceID = ((Object)t).GetInstanceID();
			if (SkipCache.TryGetValue(instanceID, out var value))
			{
				return value;
			}
			InputField componentInParent = ((Component)t).GetComponentInParent<InputField>(true);
			value = (Object)(object)componentInParent != (Object)null && (Object)(object)componentInParent.textComponent == (Object)(object)t;
			Remember(instanceID, value);
			return value;
		}

		private static bool IsInputOrChat(TMP_Text t)
		{
			int instanceID = ((Object)t).GetInstanceID();
			if (SkipCache.TryGetValue(instanceID, out var value))
			{
				return value;
			}
			TMP_InputField componentInParent = ((Component)t).GetComponentInParent<TMP_InputField>(true);
			value = (Object)(object)componentInParent != (Object)null && (Object)(object)componentInParent.textComponent == (Object)(object)t;
			if (!value && _terminalType != null)
			{
				value = (Object)(object)((Component)t).GetComponentInParent(_terminalType, true) != (Object)null;
			}
			Remember(instanceID, value);
			return value;
		}

		private static void Remember(int id, bool skip)
		{
			if (SkipCache.Count > 20000)
			{
				SkipCache.Clear();
			}
			SkipCache[id] = skip;
		}

		private static void Dump(string s)
		{
			if (_dumped == null)
			{
				_dumped = new HashSet<string>(StringComparer.Ordinal);
				_dumpPath = Path.Combine(Paths.BepInExRootPath, "ValheimAscended_PTBR_nao_traduzidos.txt");
			}
			if (_dumped.Count > 5000 || s.Length > 2000 || !EnglishWord.IsMatch(s) || !_dumped.Add(s))
			{
				return;
			}
			try
			{
				File.AppendAllText(_dumpPath, s.Replace("\r", "\\r").Replace("\n", "\\n") + Environment.NewLine, Encoding.UTF8);
			}
			catch
			{
			}
		}

		private static void LogOnce(Exception e)
		{
			if (!_loggedError)
			{
				_loggedError = true;
				Log.LogError((object)("Erro na tradução (mostrado só uma vez): " + e));
			}
		}
	}
	internal static class PtColorizer
	{
		private static readonly Regex TagSplit = new Regex("(<[^>]+>)", RegexOptions.CultureInvariant);

		private static readonly KeyValuePair<Regex, string>[] Rules = new KeyValuePair<Regex, string>[20]
		{
			R("\\b(fogo|chamas)\\b", "#FF8844"),
			R("\\b(queima\\w*)\\b", "#FF8844"),
			R("\\b(gelo|geada|frio)\\b", "#66CCFF"),
			R("\\b(resfriad\\w*|resfriamento)\\b", "#66CCFF"),
			R("\\b(congelad\\w*|congelar|congelamento)\\b", "#44AAFF"),
			R("\\b(enregelamento)\\b", "#44AAFF"),
			R("\\b(raios?)\\b(?! de [\\d<])(?!:)", "#FFFF66"),
			R("\\b(eletrifica\\w*)\\b", "#FFFF66"),
			R("\\b(espírito|espiritua(?:l|is))\\b", "#CCCCFF"),
			R("\\b(veneno|envenenad\\w*|peçonha)\\b", "#66FF66"),
			R("\\b(sangramento|sangra\\w*)\\b", "#DD4444"),
			R("\\b(molhad[oa]s?)\\b", "#66CCFF"),
			R("\\b(fumaça|enfumaçad[oa]s?)\\b", "#888888"),
			R("\\b(atordoa\\w*)\\b", "#FFAA44"),
			R("\\b(desequilibr\\w*|desequilíbrio)\\b", "#FFAA44"),
			R("\\b(lentidão)\\b", "#66CCFF"),
			R("\\b(enraizad\\w*|enraíza\\w*)\\b", "#A088DD"),
			R("\\b(Voltagem)\\b", "#FFFF66"),
			R("\\b(Calor)\\b", "#FF8844"),
			R("\\b(Ressonância)\\b", "#CC99FF")
		};

		private static KeyValuePair<Regex, string> R(string pattern, string color)
		{
			return new KeyValuePair<Regex, string>(new Regex(pattern, RegexOptions.IgnoreCase | RegexOptions.CultureInvariant), color);
		}

		public static string Apply(string text)
		{
			string[] array = TagSplit.Split(text);
			StringBuilder stringBuilder = new StringBuilder(text.Length + 64);
			int num = 0;
			string[] array2 = array;
			foreach (string text2 in array2)
			{
				if (text2.Length == 0)
				{
					continue;
				}
				if (text2[0] == '<' && text2[text2.Length - 1] == '>')
				{
					if (text2.StartsWith("<color", StringComparison.OrdinalIgnoreCase))
					{
						num++;
					}
					else if (text2.StartsWith("</color", StringComparison.OrdinalIgnoreCase) && num > 0)
					{
						num--;
					}
					stringBuilder.Append(text2);
					continue;
				}
				if (num > 0)
				{
					stringBuilder.Append(text2);
					continue;
				}
				string text3 = text2;
				KeyValuePair<Regex, string>[] rules = Rules;
				for (int j = 0; j < rules.Length; j++)
				{
					KeyValuePair<Regex, string> keyValuePair = rules[j];
					string color = keyValuePair.Value;
					text3 = keyValuePair.Key.Replace(text3, (Match m) => "\u0001" + color + "\u0002" + m.Groups[1].Value + "\u0003");
				}
				text3 = text3.Replace("\u0001", "<color=").Replace("\u0002", ">").Replace("\u0003", "</color>");
				stringBuilder.Append(text3);
			}
			return stringBuilder.ToString();
		}
	}
	internal sealed class Translator
	{
		private sealed class Part
		{
			public string Literal;

			public string Token;

			public int Group;
		}

		private sealed class Rule
		{
			public string En;

			public string Pt;

			public bool IsTemplate;

			public string Anchor;

			public bool NeedWordStart;

			public bool NeedWordEnd;

			public string Pattern;

			public List<object> PtParts;

			public string[] Prefilter;

			public bool Broken;

			private Regex _re;

			public Regex Re
			{
				get
				{
					if (_re == null)
					{
						_re = new Regex(Pattern, RegexOptions.CultureInvariant, TimeSpan.FromMilliseconds(40.0));
					}
					return _re;
				}
			}
		}

		private struct Hit
		{
			public int Start;

			public int Length;

			public string Replacement;
		}

		private static readonly Regex TokenRx = new Regex("\\{[^{}]*\\}", RegexOptions.CultureInvariant);

		private static readonly Regex WordRx = new Regex("\\p{L}{2,}", RegexOptions.CultureInvariant);

		private static readonly CultureInfo PtBr = CultureInfo.GetCultureInfo("pt-BR");

		private const string InnerGroup = "([^\\n]*?)";

		private const string LeadGroup = "((?:<[^>]*>|[^\\s<>])*?)";

		private const string TrailGroup = "((?:<[^>]*>|[^\\s<>])*)";

		private readonly Dictionary<string, string> _exact = new Dictionary<string, string>(StringComparer.Ordinal);

		private readonly Dictionary<string, List<Rule>> _byAnchor = new Dictionary<string, List<Rule>>(StringComparer.Ordinal);

		private readonly Dictionary<string, string> _cache = new Dictionary<string, string>(StringComparer.Ordinal);

		private readonly int _cacheLimit;

		public int LiteralCount { get; private set; }

		public int TemplateCount { get; private set; }

		public int SkippedCount { get; private set; }

		public Translator(int cacheLimit = 30000)
		{
			_cacheLimit = cacheLimit;
		}

		public void Load(Dictionary<string, string> dict)
		{
			_exact.Clear();
			_byAnchor.Clear();
			_cache.Clear();
			int num = (SkippedCount = 0);
			int literalCount = (TemplateCount = num);
			LiteralCount = literalCount;
			List<Rule> list = new List<Rule>();
			foreach (KeyValuePair<string, string> item in dict)
			{
				if (!string.IsNullOrEmpty(item.Key) && item.Value != null && !(item.Key == item.Value))
				{
					Rule rule = ((item.Key.IndexOf('{') >= 0 && TokenRx.IsMatch(item.Key)) ? BuildTemplate(item.Key, item.Value) : BuildLiteral(item.Key, item.Value));
					if (rule == null)
					{
						SkippedCount++;
					}
					else
					{
						list.Add(rule);
					}
				}
			}
			HashSet<string> hashSet = new HashSet<string>(StringComparer.Ordinal);
			foreach (Rule item2 in list)
			{
				if (!item2.IsTemplate)
				{
					hashSet.Add(item2.En);
				}
			}
			List<Rule> list2 = new List<Rule>();
			foreach (Rule item3 in list)
			{
				if (item3.IsTemplate || item3.En.Length > 40 || !IsSimpleWords(item3.En))
				{
					continue;
				}
				string text = item3.En.ToUpperInvariant();
				if (!(text == item3.En) && !hashSet.Contains(text))
				{
					hashSet.Add(text);
					Rule rule2 = BuildLiteral(text, item3.Pt.ToUpper(PtBr));
					if (rule2 != null)
					{
						list2.Add(rule2);
					}
				}
			}
			list.AddRange(list2);
			Dictionary<string, int> dictionary = new Dictionary<string, int>(StringComparer.Ordinal);
			List<List<string>> list3 = new List<List<string>>(list.Count);
			foreach (Rule item4 in list)
			{
				List<string> list4 = LiteralWords(item4);
				list3.Add(list4);
				foreach (string item5 in list4)
				{
					dictionary.TryGetValue(item5, out var value);
					dictionary[item5] = value + 1;
				}
			}
			for (int i = 0; i < list.Count; i++)
			{
				Rule rule3 = list[i];
				List<string> list5 = list3[i];
				if (list5.Count == 0)
				{
					SkippedCount++;
					continue;
				}
				string text2 = null;
				int num4 = int.MaxValue;
				foreach (string item6 in list5)
				{
					int num5 = dictionary[item6];
					if (num5 < num4 || (num5 == num4 && item6.Length > text2.Length))
					{
						text2 = item6;
						num4 = num5;
					}
				}
				rule3.Anchor = text2;
				if (!_byAnchor.TryGetValue(text2, out var value2))
				{
					value2 = (_byAnchor[text2] = new List<Rule>());
				}
				value2.Add(rule3);
				if (rule3.IsTemplate)
				{
					TemplateCount++;
					continue;
				}
				LiteralCount++;
				if (!_exact.ContainsKey(rule3.En))
				{
					_exact[rule3.En] = rule3.Pt;
				}
			}
		}

		private static bool IsSimpleWords(string s)
		{
			bool result = false;
			foreach (char c in s)
			{
				if (char.IsLetter(c))
				{
					result = true;
				}
				else if (c != ' ' && c != '-' && c != '\'' && c != '!' && c != '&')
				{
					return false;
				}
			}
			return result;
		}

		private static List<string> LiteralWords(Rule r)
		{
			List<string> list = new List<string>();
			string input = (r.IsTemplate ? TokenRx.Replace(r.En, " ") : r.En);
			input = Regex.Replace(input, "<[^>]*>", " ");
			foreach (Match item2 in WordRx.Matches(input))
			{
				string item = item2.Value.ToLowerInvariant();
				if (!list.Contains(item))
				{
					list.Add(item);
				}
			}
			return list;
		}

		private static bool IsWordChar(char c)
		{
			return char.IsLetterOrDigit(c);
		}

		private static Rule BuildLiteral(string en, string pt)
		{
			if (en.Length == 0)
			{
				return null;
			}
			return new Rule
			{
				En = en,
				Pt = pt,
				IsTemplate = false,
				NeedWordStart = IsWordChar(en[0]),
				NeedWordEnd = IsWordChar(en[en.Length - 1])
			};
		}

		private static Rule BuildTemplate(string en, string pt)
		{
			List<Part> list = new List<Part>();
			int num = 0;
			foreach (Match item in TokenRx.Matches(en))
			{
				if (item.Index > num)
				{
					list.Add(new Part
					{
						Literal = en.Substring(num, item.Index - num)
					});
				}
				list.Add(new Part
				{
					Token = item.Value
				});
				num = item.Index + item.Length;
			}
			if (num < en.Length)
			{
				list.Add(new Part
				{
					Literal = en.Substring(num)
				});
			}
			List<Part> list2 = new List<Part>();
			for (int i = 0; i < list.Count; i++)
			{
				if (list[i].Literal != null)
				{
					list2.Add(list[i]);
					continue;
				}
				int j = i;
				StringBuilder stringBuilder = new StringBuilder();
				for (; j < list.Count && list[j].Literal == null; j++)
				{
					stringBuilder.Append(list[j].Token);
				}
				if (j - i > 1 && pt.Contains(stringBuilder.ToString()))
				{
					list2.Add(new Part
					{
						Token = stringBuilder.ToString()
					});
				}
				else
				{
					for (int k = i; k < j; k++)
					{
						list2.Add(new Part
						{
							Token = list[k].Token
						});
					}
				}
				i = j - 1;
			}
			string text = pt;
			while (list2.Count > 0 && list2[0].Literal == null && text.StartsWith(list2[0].Token, StringComparison.Ordinal) && CountOf(text, list2[0].Token) == 1)
			{
				text = text.Substring(list2[0].Token.Length);
				list2.RemoveAt(0);
			}
			while (list2.Count > 0 && list2[list2.Count - 1].Literal == null && text.EndsWith(list2[list2.Count - 1].Token, StringComparison.Ordinal) && CountOf(text, list2[list2.Count - 1].Token) == 1)
			{
				text = text.Substring(0, text.Length - list2[list2.Count - 1].Token.Length);
				list2.RemoveAt(list2.Count - 1);
			}
			if (list2.Count == 0)
			{
				return null;
			}
			bool flag = false;
			foreach (Part item2 in list2)
			{
				if (item2.Literal == null)
				{
					flag = true;
					break;
				}
			}
			if (!flag)
			{
				StringBuilder stringBuilder2 = new StringBuilder();
				foreach (Part item3 in list2)
				{
					stringBuilder2.Append(item3.Literal);
				}
				string text2 = stringBuilder2.ToString();
				if (text2.Trim().Length < 2)
				{
					return null;
				}
				return BuildLiteral(text2, text);
			}
			int num2 = 0;
			foreach (Part item4 in list2)
			{
				if (item4.Literal == null)
				{
					continue;
				}
				string literal = item4.Literal;
				for (int l = 0; l < literal.Length; l++)
				{
					if (char.IsLetter(literal[l]))
					{
						num2++;
					}
				}
			}
			if (num2 < 2)
			{
				return null;
			}
			StringBuilder stringBuilder3 = new StringBuilder();
			List<string> tokens = new List<string>();
			List<string> list3 = new List<string>();
			for (int m = 0; m < list2.Count; m++)
			{
				Part part = list2[m];
				if (part.Literal != null)
				{
					if (m == 0 && IsWordChar(part.Literal[0]))
					{
						stringBuilder3.Append("(?<![\\p{L}\\p{N}])");
					}
					stringBuilder3.Append(Regex.Escape(part.Literal));
					if (m == list2.Count - 1 && IsWordChar(part.Literal[part.Literal.Length - 1]))
					{
						stringBuilder3.Append("(?![\\p{L}\\p{N}])");
					}
					string text3 = part.Literal.Trim();
					if (text3.Length >= 3)
					{
						list3.Add(text3);
					}
				}
				else
				{
					part.Group = tokens.Count;
					tokens.Add(part.Token);
					if (m == 0)
					{
						stringBuilder3.Append("((?:<[^>]*>|[^\\s<>])*?)");
					}
					else if (m == list2.Count - 1)
					{
						stringBuilder3.Append("((?:<[^>]*>|[^\\s<>])*)");
					}
					else
					{
						stringBuilder3.Append("([^\\n]*?)");
					}
				}
			}
			List<object> list4 = new List<object>();
			List<int> list5 = new List<int>();
			for (int n = 0; n < tokens.Count; n++)
			{
				list5.Add(n);
			}
			list5.Sort((int a, int b) => tokens[b].Length.CompareTo(tokens[a].Length));
			int num3 = 0;
			StringBuilder stringBuilder4 = new StringBuilder();
			while (num3 < text.Length)
			{
				int num4 = -1;
				if (text[num3] == '{')
				{
					foreach (int item5 in list5)
					{
						if (string.CompareOrdinal(text, num3, tokens[item5], 0, tokens[item5].Length) == 0)
						{
							num4 = item5;
							break;
						}
					}
				}
				if (num4 >= 0)
				{
					if (stringBuilder4.Length > 0)
					{
						list4.Add(stringBuilder4.ToString());
						stringBuilder4.Length = 0;
					}
					list4.Add(num4);
					num3 += tokens[num4].Length;
				}
				else
				{
					stringBuilder4.Append(text[num3]);
					num3++;
				}
			}
			if (stringBuilder4.Length > 0)
			{
				list4.Add(stringBuilder4.ToString());
			}
			StringBuilder stringBuilder5 = new StringBuilder();
			foreach (Part item6 in list2)
			{
				stringBuilder5.Append(item6.Literal ?? item6.Token);
			}
			return new Rule
			{
				En = stringBuilder5.ToString(),
				Pt = text,
				IsTemplate = true,
				Pattern = stringBuilder3.ToString(),
				PtParts = list4,
				Prefilter = list3.ToArray()
			};
		}

		private static int CountOf(string s, string sub)
		{
			int num = 0;
			int startIndex = 0;
			while ((startIndex = s.IndexOf(sub, startIndex, StringComparison.Ordinal)) >= 0)
			{
				num++;
				startIndex += sub.Length;
			}
			return num;
		}

		public string Translate(string s)
		{
			return Translate(s, 0);
		}

		private string Translate(string s, int depth)
		{
			if (string.IsNullOrEmpty(s))
			{
				return s;
			}
			if (_cache.TryGetValue(s, out var value))
			{
				return value;
			}
			string text = TranslateCore(s, depth);
			if (_cache.Count >= _cacheLimit)
			{
				_cache.Clear();
			}
			_cache[s] = text;
			if ((object)text != s && !_cache.ContainsKey(text))
			{
				_cache[text] = text;
			}
			return text;
		}

		private string TranslateCore(string s, int depth)
		{
			if (_exact.TryGetValue(s, out var value))
			{
				return value;
			}
			HashSet<string> hashSet = null;
			foreach (Match item in WordRx.Matches(s))
			{
				if (hashSet == null)
				{
					hashSet = new HashSet<string>(StringComparer.Ordinal);
				}
				hashSet.Add(item.Value.ToLowerInvariant());
			}
			if (hashSet == null)
			{
				return s;
			}
			List<Hit> hits = null;
			foreach (string item2 in hashSet)
			{
				if (!_byAnchor.TryGetValue(item2, out var value2))
				{
					continue;
				}
				foreach (Rule item3 in value2)
				{
					if (item3.IsTemplate)
					{
						CollectTemplate(item3, s, depth, ref hits);
					}
					else
					{
						CollectLiteral(item3, s, ref hits);
					}
				}
			}
			if (hits == null)
			{
				return s;
			}
			hits.Sort(delegate(Hit a, Hit b)
			{
				int num2 = b.Length.CompareTo(a.Length);
				return (num2 == 0) ? a.Start.CompareTo(b.Start) : num2;
			});
			List<Hit> list = new List<Hit>();
			foreach (Hit item4 in hits)
			{
				bool flag = false;
				foreach (Hit item5 in list)
				{
					if (item4.Start < item5.Start + item5.Length && item5.Start < item4.Start + item4.Length)
					{
						flag = true;
						break;
					}
				}
				if (!flag)
				{
					list.Add(item4);
				}
			}
			if (list.Count == 0)
			{
				return s;
			}
			list.Sort((Hit a, Hit b) => a.Start.CompareTo(b.Start));
			StringBuilder stringBuilder = new StringBuilder(s.Length + 32);
			int num = 0;
			foreach (Hit item6 in list)
			{
				stringBuilder.Append(s, num, item6.Start - num);
				stringBuilder.Append(item6.Replacement);
				num = item6.Start + item6.Length;
			}
			stringBuilder.Append(s, num, s.Length - num);
			return stringBuilder.ToString();
		}

		private static void CollectLiteral(Rule r, string s, ref List<Hit> hits)
		{
			int startIndex = 0;
			while ((startIndex = s.IndexOf(r.En, startIndex, StringComparison.Ordinal)) >= 0)
			{
				int num = startIndex + r.En.Length;
				bool flag = true;
				if (r.NeedWordStart && startIndex > 0 && IsWordChar(s[startIndex - 1]))
				{
					flag = false;
				}
				if (flag && r.NeedWordEnd && num < s.Length && IsWordChar(s[num]))
				{
					flag = false;
				}
				if (flag)
				{
					if (hits == null)
					{
						hits = new List<Hit>();
					}
					hits.Add(new Hit
					{
						Start = startIndex,
						Length = r.En.Length,
						Replacement = r.Pt
					});
					startIndex = num;
				}
				else
				{
					startIndex++;
				}
			}
		}

		private void CollectTemplate(Rule r, string s, int depth, ref List<Hit> hits)
		{
			if (r.Broken)
			{
				return;
			}
			string[] prefilter = r.Prefilter;
			foreach (string value in prefilter)
			{
				if (s.IndexOf(value, StringComparison.Ordinal) < 0)
				{
					return;
				}
			}
			MatchCollection matchCollection;
			try
			{
				matchCollection = r.Re.Matches(s);
				if (matchCollection.Count == 0)
				{
					return;
				}
			}
			catch (RegexMatchTimeoutException)
			{
				r.Broken = true;
				return;
			}
			catch (ArgumentException)
			{
				r.Broken = true;
				return;
			}
			foreach (Match item in matchCollection)
			{
				if (item.Length == 0)
				{
					continue;
				}
				StringBuilder stringBuilder = new StringBuilder();
				foreach (object ptPart in r.PtParts)
				{
					if (ptPart is string value2)
					{
						stringBuilder.Append(value2);
						continue;
					}
					string text = item.Groups[(int)ptPart + 1].Value;
					if (depth < 2 && text.Length > 1 && HasLetters(text))
					{
						text = Translate(text, depth + 1);
					}
					stringBuilder.Append(text);
				}
				if (hits == null)
				{
					hits = new List<Hit>();
				}
				hits.Add(new Hit
				{
					Start = item.Index,
					Length = item.Length,
					Replacement = stringBuilder.ToString()
				});
			}
		}

		private static bool HasLetters(string s)
		{
			bool flag = false;
			foreach (char c in s)
			{
				switch (c)
				{
				case '<':
					flag = true;
					continue;
				case '>':
					flag = false;
					continue;
				}
				if (!flag && char.IsLetter(c))
				{
					return true;
				}
			}
			return false;
		}
	}
	internal static class MiniJson
	{
		public static Dictionary<string, string> ParseFlatObject(string json)
		{
			Dictionary<string, string> dictionary = new Dictionary<string, string>(StringComparer.Ordinal);
			int i = 0;
			SkipWs(json, ref i);
			Expect(json, ref i, '{');
			SkipWs(json, ref i);
			if (Peek(json, i) == '}')
			{
				return dictionary;
			}
			while (true)
			{
				SkipWs(json, ref i);
				string key = ReadString(json, ref i);
				SkipWs(json, ref i);
				Expect(json, ref i, ':');
				SkipWs(json, ref i);
				string value = ReadString(json, ref i);
				dictionary[key] = value;
				SkipWs(json, ref i);
				switch (Peek(json, i))
				{
				case ',':
					break;
				case '}':
					i++;
					return dictionary;
				default:
					throw new FormatException("JSON inválido perto da posição " + i);
				}
				i++;
			}
		}

		private static char Peek(string s, int i)
		{
			if (i >= s.Length)
			{
				return '\0';
			}
			return s[i];
		}

		private static void SkipWs(string s, ref int i)
		{
			while (i < s.Length && char.IsWhiteSpace(s[i]))
			{
				i++;
			}
		}

		private static void Expect(string s, ref int i, char c)
		{
			if (Peek(s, i) != c)
			{
				throw new FormatException("Esperado '" + c + "' na posição " + i);
			}
			i++;
		}

		private static string ReadString(string s, ref int i)
		{
			Expect(s, ref i, '"');
			StringBuilder stringBuilder = new StringBuilder();
			while (i < s.Length)
			{
				char c = s[i++];
				switch (c)
				{
				case '"':
					return stringBuilder.ToString();
				default:
					stringBuilder.Append(c);
					continue;
				case '\\':
					break;
				}
				if (i >= s.Length)
				{
					break;
				}
				char c2 = s[i++];
				switch (c2)
				{
				case 'n':
					stringBuilder.Append('\n');
					break;
				case 't':
					stringBuilder.Append('\t');
					break;
				case 'r':
					stringBuilder.Append('\r');
					break;
				case 'b':
					stringBuilder.Append('\b');
					break;
				case 'f':
					stringBuilder.Append('\f');
					break;
				case '"':
					stringBuilder.Append('"');
					break;
				case '\\':
					stringBuilder.Append('\\');
					break;
				case '/':
					stringBuilder.Append('/');
					break;
				case 'u':
					if (i + 4 > s.Length)
					{
						throw new FormatException("Escape \\u incompleto");
					}
					stringBuilder.Append((char)int.Parse(s.Substring(i, 4), NumberStyles.HexNumber, CultureInfo.InvariantCulture));
					i += 4;
					break;
				default:
					stringBuilder.Append(c2);
					break;
				}
			}
			throw new FormatException("String JSON sem fechamento");
		}
	}
}