Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of HexResourceTrackerLocalization v0.1.0
HexResourceTrackerLocalization.dll
Decompiled a day agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security.Cryptography; using System.Text; using System.Text.RegularExpressions; using System.Threading; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using HarmonyLib; using LocalizationShared; using Microsoft.CodeAnalysis; using TMPro; using UnityEngine; [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("lnx")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyCopyright("Copyright © lnx")] [assembly: AssemblyFileVersion("0.1.0.0")] [assembly: AssemblyInformationalVersion("0.1.0")] [assembly: AssemblyProduct("HexResourceTrackerLocalization")] [assembly: AssemblyTitle("HexResourceTrackerLocalization")] [assembly: AssemblyMetadata("Author", "lnx")] [assembly: AssemblyVersion("0.1.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 LocalizationShared { internal sealed class TranslationConfig : IDisposable { private readonly ConfigFile config; private readonly Action<string> warning; private readonly Dictionary<string, ConfigEntry<string>> entries = new Dictionary<string, ConfigEntry<string>>(StringComparer.Ordinal); private readonly Dictionary<string, string> defaults; private readonly Dictionary<string, string> aliases = new Dictionary<string, string>(StringComparer.Ordinal); private readonly Dictionary<string, string> lastValues = new Dictionary<string, string>(StringComparer.Ordinal); private readonly Dictionary<string, string> resolved = new Dictionary<string, string>(StringComparer.Ordinal); private DateTime nextCheck; private DateTime observedWrite; private DateTime loadedWrite; private long observedLength; private long loadedLength; private int changed; internal TranslationConfig(ConfigFile config, TranslationDefinition[] definitions, Action<string> warning, Func<string, string> gameLocalize = null) { this.config = config; defaults = new Dictionary<string, string>(StringComparer.Ordinal); this.warning = warning; bool saveOnConfigSet = config.SaveOnConfigSet; config.SaveOnConfigSet = false; try { HashSet<ConfigDefinition> hashSet = new HashSet<ConfigDefinition>(); Dictionary<string, string> dictionary = MigrateLegacySection(config, hashSet); Dictionary<string, string> dictionary2 = MigrateDuplicates(config, definitions); foreach (TranslationDefinition translationDefinition in definitions) { string text = translationDefinition.Default; if (translationDefinition.GameKey != null && gameLocalize != null) { string text2 = gameLocalize(translationDefinition.GameKey); if (!string.IsNullOrEmpty(text2) && text2 != translationDefinition.GameKey && !text2.StartsWith("[", StringComparison.Ordinal)) { text = text2; } } defaults.Add(translationDefinition.Id, text); string text3 = "Исходный текст: " + translationDefinition.Source; ConfigEntry<string> val = config.Bind<string>(translationDefinition.Section, translationDefinition.Key, text, text3); if (!hashSet.Contains(((ConfigEntryBase)val).Definition) && dictionary.TryGetValue(KeyFor(translationDefinition.Source), out var value)) { string text4 = TomlTypeConverter.ConvertToValue<string>(value); if (text4 != translationDefinition.LegacyDefault) { val.Value = text4; } } entries.Add(translationDefinition.Id, val); if (translationDefinition.AliasSource == null) { continue; } aliases.Add(translationDefinition.AliasSource, translationDefinition.Id); if (!dictionary2.TryGetValue(translationDefinition.Id, out var value2)) { dictionary.TryGetValue(KeyFor(translationDefinition.AliasSource), out value2); } if (value2 != null && val.Value == text) { string text5 = TomlTypeConverter.ConvertToValue<string>(value2); if (text5 != translationDefinition.LegacyDefault) { val.Value = text5; } } } config.Save(); } finally { config.SaveOnConfigSet = saveOnConfigSet; } FileInfo fileInfo = new FileInfo(config.ConfigFilePath); loadedWrite = (observedWrite = fileInfo.LastWriteTimeUtc); loadedLength = (observedLength = fileInfo.Length); config.SettingChanged += OnSettingChanged; config.ConfigReloaded += OnReloaded; } private static Dictionary<string, string> MigrateDuplicates(ConfigFile config, TranslationDefinition[] definitions) { //IL_0114: Unknown result type (might be due to invalid IL or missing references) //IL_0120: Expected O, but got Unknown Dictionary<string, string> dictionary = new Dictionary<string, string>(StringComparer.Ordinal); Dictionary<ConfigDefinition, TranslationDefinition> dictionary2 = definitions.Where((TranslationDefinition d) => d.AliasKey != null).ToDictionary((Func<TranslationDefinition, ConfigDefinition>)((TranslationDefinition d) => new ConfigDefinition(d.Section, d.AliasKey))); if (dictionary2.Count == 0 || !File.Exists(config.ConfigFilePath)) { return dictionary; } List<string> list = new List<string>(); string text = ""; string[] array = File.ReadAllLines(config.ConfigFilePath); foreach (string text2 in array) { string text3 = text2.Trim(); if (text3.StartsWith("[", StringComparison.Ordinal) && text3.EndsWith("]", StringComparison.Ordinal)) { text = text3.Substring(1, text3.Length - 2); } int num2 = text3.IndexOf('='); if (text.Length != 0 && num2 > 0 && !text3.StartsWith("#", StringComparison.Ordinal) && !text3.StartsWith("[", StringComparison.Ordinal) && dictionary2.TryGetValue(new ConfigDefinition(text, text3.Substring(0, num2).Trim()), out var value)) { dictionary[value.Id] = text3.Substring(num2 + 1).Trim(); } else { list.Add(text2); } } if (dictionary.Count != 0) { string text4 = config.ConfigFilePath + ".v1.2.bak"; int num3 = 1; while (File.Exists(text4)) { text4 = config.ConfigFilePath + ".v1.2.bak." + num3; num3++; } File.Copy(config.ConfigFilePath, text4); File.WriteAllLines(config.ConfigFilePath, list, new UTF8Encoding(encoderShouldEmitUTF8Identifier: false)); config.Reload(); } return dictionary; } private static Dictionary<string, string> MigrateLegacySection(ConfigFile config, HashSet<ConfigDefinition> existing) { //IL_0104: Unknown result type (might be due to invalid IL or missing references) //IL_010e: Expected O, but got Unknown Dictionary<string, string> dictionary = new Dictionary<string, string>(StringComparer.Ordinal); if (!File.Exists(config.ConfigFilePath)) { return dictionary; } List<string> list = new List<string>(); string text = ""; bool flag = false; string[] array = File.ReadAllLines(config.ConfigFilePath); foreach (string text2 in array) { string text3 = text2.Trim(); if (text3.StartsWith("[", StringComparison.Ordinal) && text3.EndsWith("]", StringComparison.Ordinal)) { text = text3.Substring(1, text3.Length - 2); } bool flag2 = text == "Translations"; flag = flag || flag2; if (!flag2) { list.Add(text2); } int num = text3.IndexOf('='); if (num > 0 && !text3.StartsWith("#", StringComparison.Ordinal) && !text3.StartsWith("[", StringComparison.Ordinal)) { string text4 = text3.Substring(0, num).Trim(); if (flag2) { dictionary[text4] = text3.Substring(num + 1).Trim(); } else if (text.Length != 0) { existing.Add(new ConfigDefinition(text, text4)); } } } if (flag) { string text5 = config.ConfigFilePath + ".v1.1.bak"; int num2 = 1; while (File.Exists(text5)) { text5 = config.ConfigFilePath + ".v1.1.bak." + num2; num2++; } File.Copy(config.ConfigFilePath, text5); File.WriteAllLines(config.ConfigFilePath, list, new UTF8Encoding(encoderShouldEmitUTF8Identifier: false)); config.Reload(); } return dictionary; } internal static string KeyFor(string source) { string text = Regex.Replace(source, "[^\\p{L}\\p{Nd}]+", "_").Trim('_'); if (text.Length > 48) { text = text.Substring(0, 48); } using SHA256 sHA = SHA256.Create(); string text2 = BitConverter.ToString(sHA.ComputeHash(Encoding.UTF8.GetBytes(source))).Replace("-", "").Substring(0, 12); return ((text.Length == 0) ? "Text" : text) + "_" + text2; } internal string Get(string source) { if (aliases.TryGetValue(source, out var value)) { source = value; } if (!entries.TryGetValue(source, out var value2)) { return source; } string text = value2.Value ?? ""; if (lastValues.TryGetValue(source, out var value3) && value3 == text) { return resolved[source]; } lastValues[source] = text; if (!ValidFormat(source, text)) { warning("Invalid translation template [" + ((ConfigEntryBase)value2).Definition.Key + "]; using the built-in text. Preserve its placeholders."); text = defaults[source]; } resolved[source] = text; return text; } private static bool ValidFormat(string source, string value) { if (!source.Contains("{0}")) { return true; } object[] array = ((!source.Contains("{1}")) ? new object[1] { "__LOC_ARG_0__" } : new object[2] { "__LOC_ARG_0__", "__LOC_ARG_1__" }); try { string formatted = string.Format(CultureInfo.InvariantCulture, value, array); return array.All((object argument) => formatted.Contains((string)argument)); } catch (FormatException) { return false; } } internal bool Poll() { if (DateTime.UtcNow >= nextCheck) { nextCheck = DateTime.UtcNow.AddSeconds(1.0); try { FileInfo fileInfo = new FileInfo(config.ConfigFilePath); if (fileInfo.Exists) { if (fileInfo.LastWriteTimeUtc != observedWrite || fileInfo.Length != observedLength) { observedWrite = fileInfo.LastWriteTimeUtc; observedLength = fileInfo.Length; } else if (observedWrite != loadedWrite || observedLength != loadedLength) { bool saveOnConfigSet = config.SaveOnConfigSet; config.SaveOnConfigSet = false; try { config.Reload(); } finally { config.SaveOnConfigSet = saveOnConfigSet; } loadedWrite = observedWrite; loadedLength = observedLength; } } } catch (Exception ex) when (ex is IOException || ex is UnauthorizedAccessException) { warning("Cannot reload translation config: " + ex.Message); } } return Interlocked.Exchange(ref changed, 0) != 0; } private void OnSettingChanged(object sender, SettingChangedEventArgs args) { Interlocked.Exchange(ref changed, 1); } private void OnReloaded(object sender, EventArgs args) { Interlocked.Exchange(ref changed, 1); } public void Dispose() { config.SettingChanged -= OnSettingChanged; config.ConfigReloaded -= OnReloaded; } } internal sealed class TranslationDefinition { internal readonly string Id; internal readonly string Source; internal readonly string Section; internal readonly string Key; internal readonly string Default; internal readonly string LegacyDefault; internal readonly string GameKey; internal readonly string AliasSource; internal readonly string AliasKey; internal TranslationDefinition(string id, string source, string section, string key, string defaultValue, string legacyDefault, string gameKey = null, string aliasSource = null, string aliasKey = null) { Id = id; Source = source; Section = section; Key = key; Default = defaultValue; LegacyDefault = legacyDefault; GameKey = gameKey; AliasSource = aliasSource; AliasKey = aliasKey; } } } namespace HexResourceTrackerLocalization { [BepInPlugin("lordn.hexresourcetracker.localization", "HexResourceTracker Localization", "0.1.0")] [BepInDependency("com.hex.resourcetracker", "1.4.0")] public sealed class Plugin : BaseUnityPlugin { public const string Guid = "lordn.hexresourcetracker.localization"; public const string OriginalGuid = "com.hex.resourcetracker"; private Harmony harmony; private bool initialized; private static FieldInfo panelField; private static FieldInfo dungeonPinsField; private static PropertyInfo modelPinProperty; private static GameObject panel; private static readonly Dictionary<TMP_Text, string> Labels = new Dictionary<TMP_Text, string>(); 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("lordn.hexresourcetracker.localization"); try { Translations.Initialize(((BaseUnityPlugin)this).Config, delegate(string message) { ((BaseUnityPlugin)this).Logger.LogWarning((object)message); }); PluginInfo val = Chainloader.PluginInfos["com.hex.resourcetracker"]; Assembly assembly = ((object)val.Instance).GetType().Assembly; Type type = assembly.GetType("HexResourceTracker.Core.ResourceTrackerMapOverlay", throwOnError: true); Type type2 = assembly.GetType("HexResourceTracker.DungeonPinManager", throwOnError: true); Type? type3 = assembly.GetType("HexResourceTracker.DungeonPinModel", throwOnError: true); panelField = AccessTools.Field(type, "_panel"); dungeonPinsField = AccessTools.Field(type2, "DungeonPins"); modelPinProperty = AccessTools.Property(type3, "Pin"); if (panelField == null || dungeonPinsField == null || modelPinProperty == null) { throw new MissingMemberException("HexResourceTracker layout is incompatible."); } Patch(AccessTools.Method(type, "Create", Type.EmptyTypes, (Type[])null), "OverlayCreated"); Patch(AccessTools.Method(typeof(PinNameData), "SetTextAndGameObject", new Type[1] { typeof(GameObject) }, (Type[])null), "PinLabelCreated"); Patch(AccessTools.Method(typeof(Localization), "SetLanguage", new Type[1] { typeof(string) }, (Type[])null), "LanguageChanged"); Patch(AccessTools.Method(type2, "TryAddDungeonPin", (Type[])null, (Type[])null), "DungeonPinAdded"); OverlayCreated(); initialized = true; ((BaseUnityPlugin)this).Logger.LogInfo((object)("Russian localization loaded for HexResourceTracker " + val.Metadata.Version)); } catch (Exception ex) { Translations.Config?.Dispose(); Translations.Config = null; harmony.UnpatchSelf(); RestoreLabels(); ((BaseUnityPlugin)this).Logger.LogError((object)("Localization disabled: " + ex)); } } private void Update() { if (initialized && Translations.Config != null && Translations.Config.Poll()) { LanguageChanged(); } } private void Patch(MethodBase target, string postfix) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Expected O, but got Unknown if (target == null) { throw new MissingMethodException(postfix); } harmony.Patch(target, (HarmonyMethod)null, new HarmonyMethod(typeof(Plugin), postfix, (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } private static void OverlayCreated() { object? value = panelField.GetValue(null); GameObject val = (GameObject)((value is GameObject) ? value : null); if ((Object)(object)val == (Object)null) { panel = null; Labels.Clear(); return; } if ((Object)(object)panel != (Object)(object)val) { panel = val; Labels.Clear(); TMP_Text[] componentsInChildren = val.GetComponentsInChildren<TMP_Text>(true); foreach (TMP_Text val2 in componentsInChildren) { if (Translations.Text.ContainsKey(val2.text)) { Labels[val2] = val2.text; } } } foreach (KeyValuePair<TMP_Text, string> label in Labels) { if ((Object)(object)label.Key != (Object)null) { label.Key.text = Translations.Translate(label.Value); label.Key.enableAutoSizing = Translations.Russian; label.Key.fontSizeMin = 9f; label.Key.fontSizeMax = ((((Object)((Component)label.Key).gameObject).name == "Label") ? 14f : 12f); if (!Translations.Russian) { label.Key.fontSize = label.Key.fontSizeMax; } } } } private static IEnumerable<PinData> TrackedPins() { if (!(dungeonPinsField.GetValue(null) is IEnumerable enumerable)) { yield break; } foreach (object item in enumerable) { object? value = modelPinProperty.GetValue(item, null); PinData val = (PinData)((value is PinData) ? value : null); if (val != null) { yield return val; } } } private static void PinLabelCreated(PinNameData __instance) { foreach (PinData item in TrackedPins()) { if (item == __instance.ParentPin) { TranslatePin(item); break; } } } private static void TranslatePin(PinData pin) { PinNameData namePinData = pin.m_NamePinData; TMP_Text val = ((namePinData != null) ? namePinData.PinNameText : null); if ((Object)(object)val != (Object)null) { val.text = Translations.TranslatePin(pin.m_name); } } private static void RefreshPins() { foreach (PinData item in TrackedPins()) { TranslatePin(item); } } private static void DungeonPinAdded(bool __result) { if (__result && dungeonPinsField.GetValue(null) is IList { Count: not 0 } list) { object? value = modelPinProperty.GetValue(list[list.Count - 1], null); PinData val = (PinData)((value is PinData) ? value : null); if (val != null) { TranslatePin(val); } } } private static void LanguageChanged() { OverlayCreated(); RefreshPins(); } private static void RestoreLabels() { foreach (KeyValuePair<TMP_Text, string> label in Labels) { if ((Object)(object)label.Key != (Object)null) { label.Key.text = label.Value; label.Key.enableAutoSizing = false; label.Key.fontSize = ((((Object)((Component)label.Key).gameObject).name == "Label") ? 14f : 12f); } } Labels.Clear(); panel = null; if (dungeonPinsField == null || modelPinProperty == null) { return; } foreach (PinData item in TrackedPins()) { PinNameData namePinData = item.m_NamePinData; if ((Object)(object)((namePinData != null) ? namePinData.PinNameText : null) != (Object)null) { item.m_NamePinData.PinNameText.text = item.m_name; } } } private void OnDestroy() { Translations.Config?.Dispose(); Translations.Config = null; Harmony obj = harmony; if (obj != null) { obj.UnpatchSelf(); } RestoreLabels(); } } internal static class Translations { internal static TranslationConfig Config; internal static readonly TranslationDefinition[] Definitions = new TranslationDefinition[40] { new TranslationDefinition("Map Tracking", "Map Tracking", "1 - Interface", "Map Tracking", "Отслеживание", "Отслеживание"), new TranslationDefinition("Resources", "Resources", "1 - Interface", "Resources", "Ресурсы", "Ресурсы"), new TranslationDefinition("Deposits", "Deposits", "1 - Interface", "Deposits", "Месторождения", "Месторождения"), new TranslationDefinition("Dungeons", "Dungeons", "1 - Interface", "Dungeons", "Подземелья", "Подземелья"), new TranslationDefinition("Mushrooms", "Mushrooms", "2 - Resource labels", "Mushrooms", "Гриб", "Грибы", "$item_mushroomcommon"), new TranslationDefinition("Dandelions", "Dandelions", "2 - Resource labels", "Dandelions", "Одуванчик", "Одуванчики", "$item_dandelion"), new TranslationDefinition("Raspberries", "Raspberries", "2 - Resource labels", "Raspberries", "Малина", "Малина", "$item_raspberries"), new TranslationDefinition("Blueberries", "Blueberries", "2 - Resource labels", "Blueberries", "Черника", "Черника", "$item_blueberries"), new TranslationDefinition("Thistle", "Thistle", "2 - Resource labels", "Thistle", "Чертополох", "Чертополох", "$item_thistle"), new TranslationDefinition("Carrot Seeds", "Carrot Seeds", "2 - Resource labels", "Carrot Seeds", "Семена моркови", "Семена моркови", "$item_carrotseeds"), new TranslationDefinition("Turnip Seeds", "Turnip Seeds", "2 - Resource labels", "Turnip Seeds", "Семена репы", "Семена репы", "$item_turnipseeds"), new TranslationDefinition("Dragon Eggs", "Dragon Eggs", "2 - Resource labels", "Dragon Eggs", "Яйцо дракона", "Драконьи яйца", "$item_dragonegg"), new TranslationDefinition("Onion Seeds", "Onion Seeds", "2 - Resource labels", "Onion Seeds", "Семена лука", "Семена лука", "$item_onionseeds"), new TranslationDefinition("Flax", "Flax", "2 - Resource labels", "Flax", "Лен", "Лён", "$item_flax"), new TranslationDefinition("Barley", "Barley", "2 - Resource labels", "Barley", "Ячмень", "Ячмень", "$item_barley"), new TranslationDefinition("Cloudberries", "Cloudberries", "2 - Resource labels", "Cloudberries", "Морошка", "Морошка", "$item_cloudberries"), new TranslationDefinition("Jotun Puffs", "Jotun Puffs", "2 - Resource labels", "Jotun Puffs", "Гриб Йотунов", "Дымовики йотунов", "$item_jotunpuffs"), new TranslationDefinition("Magecap", "Magecap", "2 - Resource labels", "Magecap", "Волшебный гриб", "Колпак мага", "$item_magecap"), new TranslationDefinition("Vineberries", "Vineberries", "2 - Resource labels", "Vineberries", "Гроздь лозовых ягод", "Виноград", "$item_vineberry"), new TranslationDefinition("Smoke Puffs", "Smoke Puffs", "2 - Resource labels", "Smoke Puffs", "Дымчатый гриб", "Дымовики", "$item_smokepuff"), new TranslationDefinition("Fiddleheads", "Fiddleheads", "2 - Resource labels", "Fiddleheads", "Рахис", "Побеги папоротника", "$item_fiddleheadfern"), new TranslationDefinition("Lingonberries", "Lingonberries", "2 - Resource labels", "Lingonberries", "Брусника", "Брусника", "$item_lingonberries"), new TranslationDefinition("Kale Seeds", "Kale Seeds", "2 - Resource labels", "Kale Seeds", "Семена кале", "Семена капусты", "$item_kaleseeds"), new TranslationDefinition("Copper", "Copper", "2 - Resource labels", "Copper", "Залежи меди", "Медь", "$piece_deposit_copper"), new TranslationDefinition("Silver", "Silver", "2 - Resource labels", "Silver", "Серебряная жила", "Серебро", "$piece_deposit_silvervein"), new TranslationDefinition("Giant Skull", "Giant Skull", "2 - Resource labels", "Giant Skull", "Окаменевшая кость", "Череп великана", "$piece_giant_bone"), new TranslationDefinition("Flametal", "Flametal", "2 - Resource labels", "Flametal", "Огнеметаллическая руда", "Огнеметалл", "$item_flametalore"), new TranslationDefinition("Burial Chambers", "Burial Chambers", "3 - Dungeon labels", "Burial Chambers", "Погребальные комнаты", "Погребальные камеры", "$location_forestcrypt"), new TranslationDefinition("Sunken Crypts", "Sunken Crypts", "3 - Dungeon labels", "Sunken Crypts", "Затонувшие склепы", "Затонувшие склепы", "$location_sunkencrypt"), new TranslationDefinition("Frost Caves", "Frost Caves", "3 - Dungeon labels", "Frost Caves", "Ледяные пещеры", "Морозные пещеры", "$location_mountaincave"), new TranslationDefinition("Infested Mines", "Infested Mines", "3 - Dungeon labels", "Infested Mines", "Зараженный рудник", "Заражённые шахты", "$location_dvergrtown"), new TranslationDefinition("Morkhalla", "Morkhalla", "3 - Dungeon labels", "Morkhalla", "Мёркхалла", "Моркхалла", "$location_morkhalla"), new TranslationDefinition("Winding Tunnels", "Winding Tunnels", "3 - Dungeon labels", "Winding Tunnels", "Извилистые тоннели", "Извилистые туннели", "$location_thehole"), new TranslationDefinition("Pin: Burial Chamber", "Burial Chamber", "4 - Map pins", "Burial Chambers", "Погребальные комнаты", "Погребальная камера", "$location_forestcrypt"), new TranslationDefinition("Pin: Sunken Crypt", "Sunken Crypt", "4 - Map pins", "Sunken Crypts", "Затонувшие склепы", "Затонувший склеп", "$location_sunkencrypt"), new TranslationDefinition("Pin: Frost Cave", "Frost Cave", "4 - Map pins", "Frost Caves", "Ледяные пещеры", "Морозная пещера", "$location_mountaincave"), new TranslationDefinition("Pin: Infested Mine", "Infested Mine", "4 - Map pins", "Infested Mines", "Зараженный рудник", "Заражённая шахта", "$location_dvergrtown"), new TranslationDefinition("Pin: Morkhalla", "Morkhalla", "4 - Map pins", "Morkhalla", "Мёркхалла", "Моркхалла", "$location_morkhalla"), new TranslationDefinition("Pin: Winding Tunnel", "Winding Tunnel", "4 - Map pins", "Winding Tunnels", "Извилистые тоннели", "Извилистый туннель", "$location_thehole"), new TranslationDefinition("Pin: Dungeon", "Dungeon", "4 - Map pins", "Unknown dungeon", "Подземелье", "Подземелье") }; internal static readonly Dictionary<string, string> Text = Definitions.ToDictionary<TranslationDefinition, string, string>((TranslationDefinition entry) => entry.Id, (TranslationDefinition entry) => entry.Default, StringComparer.Ordinal); internal static bool Russian { get { if (Localization.instance != null) { return string.Equals(Localization.instance.GetSelectedLanguage(), "Russian", StringComparison.OrdinalIgnoreCase); } return false; } } internal static void Initialize(ConfigFile config, Action<string> warning) { Config = new TranslationConfig(config, Definitions, warning, GameDefault); } private static string GameDefault(string token) { object? obj = typeof(Localization).GetField("m_instance", BindingFlags.Static | BindingFlags.NonPublic)?.GetValue(null); Localization val = (Localization)((obj is Localization) ? obj : null); if (val == null || !(val.GetSelectedLanguage() == "Russian")) { return null; } return val.Localize(token); } internal static string Translate(string value) { return Resolve(value, value); } internal static string TranslatePin(string value) { return Resolve("Pin: " + value, value); } private static string Resolve(string id, string original) { if (original == null || !Russian || !Text.TryGetValue(id, out var value)) { return original; } if (Config != null) { return Config.Get(id); } return value; } } }