Decompiled source of RomesteadLocalizationAPI v1.0.0

BepInEx/plugins/RomesteadLocalizationAPI.dll

Decompiled a day 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.InteropServices;
using System.Runtime.Versioning;
using System.Text.Json;
using BepInEx;
using BepInEx.Core.Logging.Interpolation;
using BepInEx.Logging;
using BepInEx.NET.Common;
using Candide;
using Candide.GameModels.Helpers;
using HarmonyLib;
using RomesteadLocalizationAPI.Api;
using Shared.Text;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AssemblyTitle("Romestead Localization API")]
[assembly: AssemblyDescription("Romestead Localization API by Ice Box Studio")]
[assembly: AssemblyCompany("Ice Box Studio")]
[assembly: AssemblyProduct("Romestead Localization API")]
[assembly: AssemblyCopyright("Copyright (C) 2026 Ice Box Studio All rights reserved.")]
[assembly: ComVisible(false)]
[assembly: Guid("6f52443b-3b87-402a-9965-44b01b12c078")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETCoreApp,Version=v8.0", FrameworkDisplayName = ".NET 8.0")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace RomesteadLocalizationAPI
{
	public static class PluginInfo
	{
		public const string PLUGIN_GUID = "IceBoxStudio.Romestead.LocalizationAPI";

		public const string PLUGIN_NAME = "Romestead Localization API";

		public const string PLUGIN_VERSION = "1.0.0";

		public const string PLUGIN_AUTHOR = "Ice Box Studio";

		public const string PLUGIN_AUTHOR_URL = "https://steamcommunity.com/id/ibox666/";
	}
	[BepInPlugin("IceBoxStudio.Romestead.LocalizationAPI", "Romestead Localization API", "1.0.0")]
	public sealed class RomesteadLocalizationAPI : BasePlugin
	{
		private Harmony _harmony;

		public static RomesteadLocalizationAPI Instance { get; private set; }

		internal static ManualLogSource Logger { get; private set; }

		public override void Load()
		{
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Expected O, but got Unknown
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Expected O, but got Unknown
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Expected O, but got Unknown
			Instance = this;
			Logger = ((BasePlugin)this).Log;
			bool flag = default(bool);
			try
			{
				_harmony = new Harmony("IceBoxStudio.Romestead.LocalizationAPI");
				_harmony.PatchAll(Assembly.GetExecutingAssembly());
				RomesteadLocalization.Apply();
				ManualLogSource logger = Logger;
				BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(13, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>("Romestead Localization API");
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" initialized.");
				}
				logger.LogInfo(val);
			}
			catch (Exception ex)
			{
				ManualLogSource logger2 = Logger;
				BepInExErrorLogInterpolatedStringHandler val2 = new BepInExErrorLogInterpolatedStringHandler(24, 3, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>("Romestead Localization API");
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" initialization error: ");
					((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(ex.Message);
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("\n");
					((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(ex.StackTrace);
				}
				logger2.LogError(val2);
			}
		}
	}
}
namespace RomesteadLocalizationAPI.Patches
{
	[HarmonyPatch(typeof(LocalizationManager), "SetLocalization")]
	internal static class LocalizationManagerPatch
	{
		private static void Postfix(string locale)
		{
			RomesteadLocalization.OnGameLocalizationLoaded(locale);
		}
	}
}
namespace RomesteadLocalizationAPI.Api
{
	public static class RomesteadLocales
	{
		public const string English = "en";

		public const string ChineseSimplified = "zh_CN";

		public const string ChineseTraditional = "zh_TW";

		public const string Czech = "cs_CZ";

		public const string German = "de_DE";

		public const string Greek = "el_GR";

		public const string Spanish = "es_ES";

		public const string French = "fr_FR";

		public const string Italian = "it_IT";

		public const string Japanese = "ja_JP";

		public const string Korean = "ko_KR";

		public const string Dutch = "nl_NL";

		public const string Polish = "pl_PL";

		public const string PortugueseBrazil = "pt_BR";

		public const string Russian = "ru_RU";

		public const string Slovak = "sk_SK";

		public const string Swedish = "sv_SE";

		public const string Turkish = "tr_TR";

		internal static readonly string[] Known = new string[18]
		{
			"en", "zh_CN", "zh_TW", "cs_CZ", "de_DE", "el_GR", "es_ES", "fr_FR", "it_IT", "ja_JP",
			"ko_KR", "nl_NL", "pl_PL", "pt_BR", "ru_RU", "sk_SK", "sv_SE", "tr_TR"
		};
	}
	public static class RomesteadLocalization
	{
		private sealed class Entry
		{
			public string SourceId;

			public readonly Dictionary<string, string> Texts = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);

			public Entry(string sourceId)
			{
				SourceId = sourceId;
			}
		}

		private const string TestingLocale = "<testing>";

		private static readonly object Sync = new object();

		private static readonly Dictionary<string, Entry> Entries = new Dictionary<string, Entry>(StringComparer.Ordinal);

		private static string _currentLocale = "en";

		public static string CurrentLocale => DetectCurrentLocale();

		public static event Action<string> LanguageChanged;

		public static event Action<string> LocalizationApplied;

		public static RomesteadLocalizer For(string sourceId)
		{
			ValidateSourceId(sourceId);
			return new RomesteadLocalizer(sourceId);
		}

		public static void RegisterJsonDirectory(string sourceId, string directory)
		{
			ValidateSourceId(sourceId);
			if (string.IsNullOrWhiteSpace(directory))
			{
				throw new ArgumentException("Localization directory cannot be empty.", "directory");
			}
			if (!Directory.Exists(directory))
			{
				throw new DirectoryNotFoundException(directory);
			}
			Dictionary<string, Dictionary<string, string>> dictionary = new Dictionary<string, Dictionary<string, string>>(StringComparer.OrdinalIgnoreCase);
			string[] files = Directory.GetFiles(directory, "*.json", SearchOption.TopDirectoryOnly);
			Array.Sort(files, (IComparer<string>?)StringComparer.OrdinalIgnoreCase);
			string[] array = files;
			foreach (string path in array)
			{
				string localeFromJsonFile = GetLocaleFromJsonFile(path);
				foreach (KeyValuePair<string, string> item in ReadJsonTextMap(path))
				{
					AddBundleText(dictionary, localeFromJsonFile, item.Key, item.Value);
				}
			}
			RegisterBundle(sourceId, dictionary);
		}

		public static void RegisterJson(string sourceId, string path)
		{
			ValidateSourceId(sourceId);
			RegisterBundle(sourceId, ReadJsonBundle(path));
		}

		public static void RegisterText(string sourceId, string locale, string key, string text)
		{
			ValidateSourceId(sourceId);
			ValidateLocale(locale);
			ValidateKey(key);
			if (text == null)
			{
				throw new ArgumentNullException("text");
			}
			Dictionary<string, Dictionary<string, string>> dictionary = new Dictionary<string, Dictionary<string, string>>(StringComparer.OrdinalIgnoreCase);
			AddBundleText(dictionary, locale, key, text);
			RegisterBundle(sourceId, dictionary);
		}

		public static void RegisterTexts(string sourceId, string locale, IReadOnlyDictionary<string, string> texts)
		{
			ValidateSourceId(sourceId);
			ValidateLocale(locale);
			if (texts == null)
			{
				throw new ArgumentNullException("texts");
			}
			Dictionary<string, Dictionary<string, string>> dictionary = new Dictionary<string, Dictionary<string, string>>(StringComparer.OrdinalIgnoreCase);
			foreach (KeyValuePair<string, string> text in texts)
			{
				ValidateKey(text.Key);
				if (text.Value == null)
				{
					throw new ArgumentException("Localization text cannot be null: " + text.Key, "texts");
				}
				AddBundleText(dictionary, locale, text.Key, text.Value);
			}
			RegisterBundle(sourceId, dictionary);
		}

		public static void RegisterTexts(string sourceId, params (string Locale, string Key, string Text)[] texts)
		{
			ValidateSourceId(sourceId);
			if (texts == null)
			{
				throw new ArgumentNullException("texts");
			}
			Dictionary<string, Dictionary<string, string>> dictionary = new Dictionary<string, Dictionary<string, string>>(StringComparer.OrdinalIgnoreCase);
			for (int i = 0; i < texts.Length; i++)
			{
				(string, string, string) tuple = texts[i];
				ValidateLocale(tuple.Item1);
				ValidateKey(tuple.Item2);
				if (tuple.Item3 == null)
				{
					throw new ArgumentException("Localization text cannot be null: " + tuple.Item1 + "." + tuple.Item2, "texts");
				}
				AddBundleText(dictionary, tuple.Item1, tuple.Item2, tuple.Item3);
			}
			RegisterBundle(sourceId, dictionary);
		}

		public static string Text(string key, params object[] args)
		{
			return GetText(key, args);
		}

		public static string TextFor(string sourceId, string key, params object[] args)
		{
			return GetTextFor(sourceId, key, args);
		}

		public static string GetText(string key, params object[] args)
		{
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Expected O, but got Unknown
			if (string.IsNullOrEmpty(key))
			{
				return "<key_not_set>";
			}
			string text = TryGetRegisteredText(key, CurrentLocale) ?? TryGetGameText(key) ?? key;
			if (args == null || args.Length == 0)
			{
				return text;
			}
			try
			{
				return string.Format(text, args);
			}
			catch (Exception ex)
			{
				ManualLogSource logger = RomesteadLocalizationAPI.Logger;
				if (logger != null)
				{
					bool flag = default(bool);
					BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(39, 2, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Faulty localization format string at ");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(key);
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral(": ");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(ex.Message);
					}
					logger.LogWarning(val);
				}
				return text;
			}
		}

		public static string GetTextFor(string sourceId, string key, params object[] args)
		{
			ValidateSourceId(sourceId);
			if (string.IsNullOrEmpty(key))
			{
				return "<key_not_set>";
			}
			return GetText(ScopeKey(sourceId, key), args);
		}

		public static void Apply()
		{
			Apply(DetectCurrentLocale(), notify: false);
		}

		public static IReadOnlyList<string> GetSupportedLocales()
		{
			HashSet<string> hashSet = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
			string[] known = RomesteadLocales.Known;
			foreach (string item in known)
			{
				hashSet.Add(item);
			}
			try
			{
				foreach (string key in Globals.SupportedLanguageCodes.Keys)
				{
					if (!string.Equals(key, "<testing>", StringComparison.OrdinalIgnoreCase))
					{
						hashSet.Add(NormalizeLocale(key));
					}
				}
			}
			catch
			{
			}
			foreach (string contentLocale in GetContentLocales())
			{
				hashSet.Add(contentLocale);
			}
			List<string> list = new List<string>(hashSet);
			list.Sort(StringComparer.OrdinalIgnoreCase);
			return list;
		}

		public static string NormalizeLocale(string locale)
		{
			string text = (locale ?? string.Empty).Trim().Replace('-', '_');
			switch (text)
			{
			case "":
				return "en";
			case "en":
			case "en_US":
			case "en_GB":
				return "en";
			case "zh":
			case "zh_CN":
			case "zh_Hans":
				return "zh_CN";
			case "zh_TW":
			case "zh_HK":
			case "zh_MO":
			case "zh_Hant":
				return "zh_TW";
			case "cs":
				return "cs_CZ";
			case "de":
				return "de_DE";
			case "el":
				return "el_GR";
			case "es":
				return "es_ES";
			case "fr":
				return "fr_FR";
			case "it":
				return "it_IT";
			case "ja":
				return "ja_JP";
			case "ko":
				return "ko_KR";
			case "nl":
				return "nl_NL";
			case "pl":
				return "pl_PL";
			case "pt":
			case "pt_PT":
				return "pt_BR";
			case "ru":
				return "ru_RU";
			case "sk":
				return "sk_SK";
			case "sv":
				return "sv_SE";
			case "tr":
				return "tr_TR";
			default:
				return text;
			}
		}

		internal static void OnGameLocalizationLoaded(string locale)
		{
			Apply(NormalizeLocale(locale), notify: true);
		}

		private static void RegisterBundle(string sourceId, Dictionary<string, Dictionary<string, string>> bundle)
		{
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: Expected O, but got Unknown
			lock (Sync)
			{
				bool flag = default(bool);
				foreach (KeyValuePair<string, Dictionary<string, string>> item in bundle)
				{
					string key = NormalizeLocale(item.Key);
					foreach (KeyValuePair<string, string> item2 in item.Value)
					{
						string text = ScopeKey(sourceId, item2.Key);
						if (!Entries.TryGetValue(text, out var value))
						{
							value = new Entry(sourceId);
							Entries[text] = value;
						}
						else if (!string.Equals(value.SourceId, sourceId, StringComparison.Ordinal))
						{
							ManualLogSource logger = RomesteadLocalizationAPI.Logger;
							if (logger != null)
							{
								BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(35, 3, ref flag);
								if (flag)
								{
									((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Localization key ");
									((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(text);
									((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" from ");
									((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(sourceId);
									((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" overrides ");
									((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(value.SourceId);
									((BepInExLogInterpolatedStringHandler)val).AppendLiteral(".");
								}
								logger.LogWarning(val);
							}
							value.SourceId = sourceId;
						}
						value.Texts[key] = item2.Value;
					}
				}
			}
			Apply();
		}

		private static void Apply(string locale, bool notify)
		{
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			string text = NormalizeLocale(locale);
			bool flag = false;
			lock (Sync)
			{
				flag = !string.Equals(_currentLocale, text, StringComparison.OrdinalIgnoreCase);
				_currentLocale = text;
				if (string.Equals(text, "<testing>", StringComparison.OrdinalIgnoreCase))
				{
					return;
				}
				foreach (KeyValuePair<string, Entry> entry in Entries)
				{
					string text2 = SelectText(entry.Value.Texts, text);
					if (text2 != null)
					{
						StringDefinitions.Strings[entry.Key] = new StringDefinition(text2);
					}
				}
			}
			if (notify)
			{
				RomesteadLocalization.LocalizationApplied?.Invoke(text);
				if (flag)
				{
					RomesteadLocalization.LanguageChanged?.Invoke(text);
				}
			}
		}

		private static string TryGetRegisteredText(string key, string locale)
		{
			lock (Sync)
			{
				Entry value;
				return Entries.TryGetValue(key, out value) ? SelectText(value.Texts, locale) : null;
			}
		}

		private static string TryGetGameText(string key)
		{
			try
			{
				string text = default(string);
				return StringDefinitions.TryGetString(key, ref text) ? text : null;
			}
			catch
			{
				return null;
			}
		}

		private static string SelectText(Dictionary<string, string> texts, string locale)
		{
			string text = NormalizeLocale(locale);
			if (string.Equals(text, "<testing>", StringComparison.OrdinalIgnoreCase))
			{
				return null;
			}
			if (texts.TryGetValue(text, out var value))
			{
				return value;
			}
			if (texts.TryGetValue("en", out var value2))
			{
				return value2;
			}
			if (texts.TryGetValue("zh_CN", out var value3))
			{
				return value3;
			}
			using (Dictionary<string, string>.ValueCollection.Enumerator enumerator = texts.Values.GetEnumerator())
			{
				if (enumerator.MoveNext())
				{
					return enumerator.Current;
				}
			}
			return null;
		}

		private static string DetectCurrentLocale()
		{
			if (!string.IsNullOrWhiteSpace(StringDefinitions.CurrentLanguageCode))
			{
				return NormalizeLocale(StringDefinitions.CurrentLanguageCode);
			}
			try
			{
				if (!string.IsNullOrWhiteSpace(Globals.LanguageCode))
				{
					return NormalizeLocale(Globals.LanguageCode);
				}
			}
			catch
			{
			}
			string text = ReadSavedLocale();
			if (!string.IsNullOrWhiteSpace(text))
			{
				return NormalizeLocale(text);
			}
			string text2 = NormalizeLocale(CultureInfo.CurrentCulture.Name);
			string[] known = RomesteadLocales.Known;
			foreach (string b in known)
			{
				if (string.Equals(text2, b, StringComparison.OrdinalIgnoreCase))
				{
					return text2;
				}
			}
			return _currentLocale;
		}

		private static string ReadSavedLocale()
		{
			try
			{
				string path = Path.Combine(GamePathHelper.GetFolderPath((GameFolder)1, false), "localization.json");
				if (!File.Exists(path))
				{
					return null;
				}
				using FileStream utf8Json = File.OpenRead(path);
				using JsonDocument jsonDocument = JsonDocument.Parse((Stream)utf8Json, new JsonDocumentOptions
				{
					AllowTrailingCommas = true,
					CommentHandling = JsonCommentHandling.Skip
				});
				JsonElement value;
				return (jsonDocument.RootElement.TryGetProperty("LanguageCode", out value) && value.ValueKind == JsonValueKind.String) ? value.GetString() : null;
			}
			catch
			{
				return null;
			}
		}

		private static IEnumerable<string> GetContentLocales()
		{
			string root = null;
			try
			{
				object manager = typeof(Globals).GetField("ContentManager")?.GetValue(null);
				root = manager?.GetType().GetProperty("RootDirectory")?.GetValue(manager) as string;
			}
			catch
			{
			}
			if (string.IsNullOrWhiteSpace(root))
			{
				yield break;
			}
			string path = Path.Combine(root, "localization");
			if (!Directory.Exists(path))
			{
				yield break;
			}
			string[] files = Directory.GetFiles(path, "locale_*");
			foreach (string file in files)
			{
				string name = Path.GetFileName(file);
				if (name != null && name.Length > "locale_".Length)
				{
					yield return NormalizeLocale(name.Substring("locale_".Length));
				}
			}
		}

		private static Dictionary<string, string> ReadJsonTextMap(string path)
		{
			if (string.IsNullOrWhiteSpace(path))
			{
				throw new ArgumentException("Localization file path cannot be empty.", "path");
			}
			if (!File.Exists(path))
			{
				throw new FileNotFoundException("Localization file was not found.", path);
			}
			using FileStream utf8Json = File.OpenRead(path);
			using JsonDocument jsonDocument = JsonDocument.Parse((Stream)utf8Json, new JsonDocumentOptions
			{
				AllowTrailingCommas = true,
				CommentHandling = JsonCommentHandling.Skip
			});
			if (jsonDocument.RootElement.ValueKind != JsonValueKind.Object)
			{
				throw new JsonException("Localization file must contain a JSON object: " + path);
			}
			Dictionary<string, string> dictionary = new Dictionary<string, string>(StringComparer.Ordinal);
			foreach (JsonProperty item in jsonDocument.RootElement.EnumerateObject())
			{
				if (item.Value.ValueKind != JsonValueKind.String)
				{
					throw new JsonException("Localization value must be a string: " + path + " -> " + item.Name);
				}
				dictionary[item.Name] = item.Value.GetString();
			}
			return dictionary;
		}

		private static Dictionary<string, Dictionary<string, string>> ReadJsonBundle(string path)
		{
			if (string.IsNullOrWhiteSpace(path))
			{
				throw new ArgumentException("Localization bundle path cannot be empty.", "path");
			}
			if (!File.Exists(path))
			{
				throw new FileNotFoundException("Localization bundle was not found.", path);
			}
			using FileStream utf8Json = File.OpenRead(path);
			using JsonDocument jsonDocument = JsonDocument.Parse((Stream)utf8Json, new JsonDocumentOptions
			{
				AllowTrailingCommas = true,
				CommentHandling = JsonCommentHandling.Skip
			});
			if (jsonDocument.RootElement.ValueKind != JsonValueKind.Object)
			{
				throw new JsonException("Localization bundle must contain a JSON object: " + path);
			}
			Dictionary<string, Dictionary<string, string>> result = new Dictionary<string, Dictionary<string, string>>(StringComparer.OrdinalIgnoreCase);
			foreach (JsonProperty item in jsonDocument.RootElement.EnumerateObject())
			{
				if (!IsLocaleName(item.Name))
				{
					throw new JsonException("Localization bundle top-level key must be a locale: " + path + " -> " + item.Name);
				}
				if (item.Value.ValueKind != JsonValueKind.Object)
				{
					throw new JsonException("Localization locale value must be an object: " + path + " -> " + item.Name);
				}
				foreach (JsonProperty item2 in item.Value.EnumerateObject())
				{
					AddBundleText(result, item.Name, item2.Name, item2.Value, path);
				}
			}
			return result;
		}

		private static string GetLocaleFromJsonFile(string path)
		{
			string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(path);
			if (fileNameWithoutExtension == null)
			{
				return "en";
			}
			return fileNameWithoutExtension.StartsWith("locale_", StringComparison.OrdinalIgnoreCase) ? NormalizeLocale(fileNameWithoutExtension.Substring("locale_".Length)) : NormalizeLocale(fileNameWithoutExtension);
		}

		private static bool IsLocaleName(string value)
		{
			string a = NormalizeLocale(value);
			string[] known = RomesteadLocales.Known;
			foreach (string b in known)
			{
				if (string.Equals(a, b, StringComparison.OrdinalIgnoreCase))
				{
					return true;
				}
			}
			return value.Length == 2 || (value.Length == 5 && value[2] == '_') || (value.Length == 7 && value[2] == '_');
		}

		private static void AddBundleText(Dictionary<string, Dictionary<string, string>> result, string locale, string key, JsonElement value, string path)
		{
			if (value.ValueKind != JsonValueKind.String)
			{
				throw new JsonException($"Localization value must be a string: {path} -> {locale}.{key}");
			}
			AddBundleText(result, locale, key, value.GetString());
		}

		private static void AddBundleText(Dictionary<string, Dictionary<string, string>> result, string locale, string key, string text)
		{
			if (text == null)
			{
				throw new ArgumentNullException("text");
			}
			string key2 = NormalizeLocale(locale);
			if (!result.TryGetValue(key2, out var value))
			{
				value = (result[key2] = new Dictionary<string, string>(StringComparer.Ordinal));
			}
			value[key] = text;
		}

		private static string ScopeKey(string sourceId, string key)
		{
			return key.StartsWith(sourceId + ".", StringComparison.Ordinal) ? key : (sourceId + "." + key);
		}

		private static void ValidateSourceId(string sourceId)
		{
			if (string.IsNullOrWhiteSpace(sourceId))
			{
				throw new ArgumentException("Source id cannot be empty.", "sourceId");
			}
		}

		private static void ValidateLocale(string locale)
		{
			if (string.IsNullOrWhiteSpace(locale))
			{
				throw new ArgumentException("Locale cannot be empty.", "locale");
			}
		}

		private static void ValidateKey(string key)
		{
			if (string.IsNullOrWhiteSpace(key))
			{
				throw new ArgumentException("Localization key cannot be empty.", "key");
			}
		}
	}
	public sealed class RomesteadLocalizer
	{
		public string SourceId { get; }

		public string CurrentLocale => RomesteadLocalization.CurrentLocale;

		public event Action<string> LanguageChanged
		{
			add
			{
				RomesteadLocalization.LanguageChanged += value;
			}
			remove
			{
				RomesteadLocalization.LanguageChanged -= value;
			}
		}

		internal RomesteadLocalizer(string sourceId)
		{
			SourceId = sourceId;
		}

		public RomesteadLocalizer RegisterJson(string path)
		{
			RomesteadLocalization.RegisterJson(SourceId, path);
			return this;
		}

		public RomesteadLocalizer RegisterJsonDirectory(string directory)
		{
			RomesteadLocalization.RegisterJsonDirectory(SourceId, directory);
			return this;
		}

		public RomesteadLocalizer RegisterText(string locale, string key, string text)
		{
			RomesteadLocalization.RegisterText(SourceId, locale, key, text);
			return this;
		}

		public RomesteadLocalizer RegisterTexts(string locale, IReadOnlyDictionary<string, string> texts)
		{
			RomesteadLocalization.RegisterTexts(SourceId, locale, texts);
			return this;
		}

		public RomesteadLocalizer RegisterTexts(params (string Locale, string Key, string Text)[] texts)
		{
			RomesteadLocalization.RegisterTexts(SourceId, texts);
			return this;
		}

		public string Text(string key, params object[] args)
		{
			return RomesteadLocalization.TextFor(SourceId, key, args);
		}

		public string GetText(string key, params object[] args)
		{
			return RomesteadLocalization.GetTextFor(SourceId, key, args);
		}
	}
}