diff --git a/ValheimLib/Language.cs b/ValheimLib/Language.cs index 9aef212..0850e42 100644 --- a/ValheimLib/Language.cs +++ b/ValheimLib/Language.cs @@ -1,49 +1,161 @@ -using MonoMod.RuntimeDetour; +using BepInEx; +using MonoMod.RuntimeDetour; using System; using System.Collections.Generic; +using System.IO; using ValheimLib.Util.Reflection; namespace ValheimLib { + /// + /// Class for adding / replacing localization tokens + /// public static class Language { + /// + /// Your token must start with this character. + /// public const char TokenFirstChar = '$'; - public static List AdditionalTokens = new List(); + internal static Dictionary> AdditionalTokens = + new Dictionary>(); - public struct TokenValue - { - public string Token; - public string Value; - } + internal static Func>> DoQuoteLineSplit; - public static void Init() + internal static void Init() { - var _ = new Hook( + _ = new Hook( typeof(Localization).GetMethod(nameof(Localization.SetupLanguage), ReflectionHelper.AllBindingFlags), typeof(Language).GetMethod(nameof(AddTokens), ReflectionHelper.AllBindingFlags)); + + var doQuoteLineSplitMethodInfo = typeof(Localization).GetMethod(nameof(Localization.DoQuoteLineSplit), ReflectionHelper.AllBindingFlags); + DoQuoteLineSplit = (Func>>) + Delegate.CreateDelegate(typeof(Func>>), null, doQuoteLineSplitMethodInfo); + + AddLanguageFilesFromPluginFolder(); + } + + private static Dictionary GetLanguageDict(string language) + { + if (!AdditionalTokens.TryGetValue(language, out var languageDict)) + { + languageDict = new Dictionary(); + AdditionalTokens.Add(language, languageDict); + } + + return languageDict; + } + + private static void AddLanguageFilesFromPluginFolder() + { + var languagePaths = Directory.GetFiles(Paths.PluginPath, "*.language", SearchOption.AllDirectories); + foreach (var path in languagePaths) + { + AddPath(path); + } } - // Todo : for now the custom tokens are getting to any language - public static void AddToken(string token, string value, bool forceReplace = false) + /// + /// Add a token and its value to the specified language (default to English) + /// + /// token / key + /// value that will be printed in the game + /// + /// replace the token if it already exists + public static void AddToken(string token, string value, string language = "English", bool forceReplace = false) { if (token[0] != TokenFirstChar) { - throw new Exception($"Token first char should be $ ! (token : {token})"); + throw new Exception($"Token first char should be {TokenFirstChar} ! (token : {token})"); } + Dictionary languageDict; + if (!forceReplace) { - foreach (var pair in AdditionalTokens) + if (AdditionalTokens.TryGetValue(language, out languageDict)) { - if (pair.Token == token) + foreach (var pair in languageDict) { - throw new Exception($"Token named {token} already exist !"); + if (pair.Key == token) + { + throw new Exception($"Token named {token} already exist !"); + } } } } - AdditionalTokens.Add(new TokenValue { Token = token.Substring(1), Value = value }); + languageDict = GetLanguageDict(language); + languageDict.Add(token.Substring(1), value); + } + + /// + /// Add a token and its value to the English language + /// + /// token / key + /// value that will be printed in the game + /// replace the token if it already exists + public static void AddToken(string token, string value, bool forceReplace = false) => + AddToken(token, value, "French", forceReplace); + + /// + /// Add a file via path + /// + /// absolute path to file + public static void AddPath(string path) + { + if (path == null) + { + throw new NullReferenceException($"param {nameof(path)} is null"); + } + + var fileContent = File.ReadAllText(path); + Add(fileContent); + Log.LogInfo($"Added language file {Path.GetFileName(path)}"); + } + + /// + /// Add a language file + /// + /// Entire file as string + public static void Add(string fileContent) + { + if (fileContent == null) + { + throw new NullReferenceException($"param {nameof(fileContent)} is null"); + } + + LoadLanguageFile(fileContent); + } + + private static void LoadLanguageFile(string fileContent) + { + var stringReader = new StringReader(fileContent); + var languages = stringReader.ReadLine().Split(new []{ ',' }); + + foreach (List keyAndValues in DoQuoteLineSplit(stringReader)) + { + if (keyAndValues.Count != 0) + { + var token = keyAndValues[0]; + if (!token.StartsWith("//") && token.Length != 0) + { + for (var i = 0; i < languages.Length; i++) + { + var language = languages[i]; + + string tokenValue = keyAndValues[i]; + if (string.IsNullOrEmpty(tokenValue) || tokenValue[0] == '\r') + { + tokenValue = keyAndValues[1]; + } + + var languageDict = GetLanguageDict(language); + languageDict.Add(token, tokenValue); + } + } + } + } } private static bool AddTokens(Func orig, Localization self, string language) @@ -52,9 +164,12 @@ private static bool AddTokens(Func orig, Localizatio if (res) { - foreach (var pair in AdditionalTokens) + if (AdditionalTokens.TryGetValue(language, out var tokens)) { - self.AddWord(pair.Token, pair.Value); + foreach (var pair in tokens) + { + self.AddWord(pair.Key, pair.Value); + } } }