From d1d5b2e557ac89bb6c5a85f7685031cb133e49d1 Mon Sep 17 00:00:00 2001 From: "Nick J. Connors" Date: Fri, 25 Feb 2022 12:42:58 -0500 Subject: [PATCH] Add support for UI translations --- .../AssetBundle/translations/french.json | 15 +++ NewHorizons/Builder/General/MarkerBuilder.cs | 3 +- NewHorizons/Builder/Props/SignalBuilder.cs | 9 +- NewHorizons/Builder/ShipLog/MapModeBuilder.cs | 3 +- .../External/Configs/TranslationConfig.cs | 7 +- NewHorizons/Handlers/TranslationHandler.cs | 98 +++++++++++++++++-- NewHorizons/Main.cs | 59 ++++++----- NewHorizons/Tools/Patches.cs | 14 +-- NewHorizons/Tools/TranslationPatches.cs | 46 +++++++++ NewHorizons/Tools/WarpDrivePatches.cs | 2 +- NewHorizons/Utility/AddToUITable.cs | 25 ----- NewHorizons/translation_schema.json | 2 +- 12 files changed, 200 insertions(+), 83 deletions(-) create mode 100644 NewHorizons/AssetBundle/translations/french.json create mode 100644 NewHorizons/Tools/TranslationPatches.cs delete mode 100644 NewHorizons/Utility/AddToUITable.cs diff --git a/NewHorizons/AssetBundle/translations/french.json b/NewHorizons/AssetBundle/translations/french.json new file mode 100644 index 00000000..1feffced --- /dev/null +++ b/NewHorizons/AssetBundle/translations/french.json @@ -0,0 +1,15 @@ +{ + "$schema": "https://raw.githubusercontent.com/xen-42/outer-wilds-new-horizons/master/NewHorizons/translation_schema.json", + "DialogueDictionary": + { + "Your ship is now equiped with a warp drive!" : "Votre fusée est maintenant équipé d'un moteur de distorsion!", + "You can use the new \"Interstellar Mode\" page in the ship log to lock-on your autopilot to another star system." : "Vous pouvez utiliser la nouvelle page \"Mode Interstellaire\" dans le journal de bord pour diriger votre pilote automatique vers un autre système solaire", + "Then just buckle up and engage the autopilot to warp there!" : "Ensuite, bouclez votre ceinture et engagez le pilote automatique pour y aller!" + }, + "UIDictionary": + { + "Interstellar Mode" : "Mode Interstellaire", + "Nomai Statue" : "Statue Nomaï", + "Anti-Graviton Flux" : "Flux Anti-Gravitonique" + } +} \ No newline at end of file diff --git a/NewHorizons/Builder/General/MarkerBuilder.cs b/NewHorizons/Builder/General/MarkerBuilder.cs index e6efb73a..936c1320 100644 --- a/NewHorizons/Builder/General/MarkerBuilder.cs +++ b/NewHorizons/Builder/General/MarkerBuilder.cs @@ -4,6 +4,7 @@ using System.Reflection; using UnityEngine; using NewHorizons.External.Configs; using Logger = NewHorizons.Utility.Logger; +using NewHorizons.Handlers; namespace NewHorizons.Builder.General { @@ -12,7 +13,7 @@ namespace NewHorizons.Builder.General public static void Make(GameObject body, string name, IPlanetConfig config) { MapMarker mapMarker = body.AddComponent(); - mapMarker.SetValue("_labelID", (UITextType)Utility.AddToUITable.Add(name.ToUpper())); + mapMarker.SetValue("_labelID", (UITextType)TranslationHandler.AddUI(config.Name)); var markerType = MapMarker.MarkerType.Planet; diff --git a/NewHorizons/Builder/Props/SignalBuilder.cs b/NewHorizons/Builder/Props/SignalBuilder.cs index 70e3a4ba..5cedf448 100644 --- a/NewHorizons/Builder/Props/SignalBuilder.cs +++ b/NewHorizons/Builder/Props/SignalBuilder.cs @@ -1,5 +1,6 @@ using NewHorizons.Components; using NewHorizons.External; +using NewHorizons.Handlers; using NewHorizons.Utility; using OWML.Common; using System; @@ -64,9 +65,9 @@ namespace NewHorizons.Builder.Props SignalName.WhiteHole_GD_Receiver, }); SignalFrequencyOverrides = new Dictionary() { - { SignalFrequency.Statue, "NOMAI STATUE" }, + { SignalFrequency.Statue, "Nomai Statue" }, { SignalFrequency.Default, "???" }, - { SignalFrequency.WarpCore, "ANTI-GRAVITON FLUX" } + { SignalFrequency.WarpCore, "Anti-Graviton Flux" } }; _nextCustomSignalName = 200; } @@ -79,14 +80,14 @@ namespace NewHorizons.Builder.Props if (_availableSignalNames.Count == 0) newName = (SignalName)_nextCustomSignalName++; else newName = _availableSignalNames.Pop(); - _customSignalNames.Add(newName, str.ToUpper()); + _customSignalNames.Add(newName, str); return newName; } public static string GetCustomSignalName(SignalName signalName) { _customSignalNames.TryGetValue(signalName, out string name); - return name; + return TranslationHandler.GetTranslation(name, TranslationHandler.TextType.UI).ToUpper(); } public static void Make(GameObject body, Sector sector, SignalModule module, IModBehaviour mod) diff --git a/NewHorizons/Builder/ShipLog/MapModeBuilder.cs b/NewHorizons/Builder/ShipLog/MapModeBuilder.cs index e044a485..96c9b284 100644 --- a/NewHorizons/Builder/ShipLog/MapModeBuilder.cs +++ b/NewHorizons/Builder/ShipLog/MapModeBuilder.cs @@ -11,6 +11,7 @@ using UnityEngine.UI; using Logger = NewHorizons.Utility.Logger; using NewHorizons.Builder.Handlers; using System; +using NewHorizons.Handlers; namespace NewHorizons.Builder.ShipLog { @@ -60,7 +61,7 @@ namespace NewHorizons.Builder.ShipLog public static string GetAstroBodyShipLogName(string id) { - return ShipLogHandler.GetNameFromAstroID(id) ?? id; + return TranslationHandler.GetTranslation(ShipLogHandler.GetNameFromAstroID(id) ?? id, TranslationHandler.TextType.UI); } private static GameObject CreateImage(GameObject nodeGO, Texture2D texture, string name, int layer) diff --git a/NewHorizons/External/Configs/TranslationConfig.cs b/NewHorizons/External/Configs/TranslationConfig.cs index 63c866da..db1d17b7 100644 --- a/NewHorizons/External/Configs/TranslationConfig.cs +++ b/NewHorizons/External/Configs/TranslationConfig.cs @@ -13,6 +13,7 @@ namespace NewHorizons.External.Configs { public Dictionary DialogueDictionary; public Dictionary ShipLogDictionary; + public Dictionary UIDictionary; public TranslationConfig(string filename) { @@ -25,7 +26,11 @@ namespace NewHorizons.External.Configs if (dict.ContainsKey(nameof(ShipLogDictionary))) { ShipLogDictionary = (Dictionary)(dict[nameof(ShipLogDictionary)] as Newtonsoft.Json.Linq.JObject).ToObject(typeof(Dictionary)); - } + } + if (dict.ContainsKey(nameof(UIDictionary))) + { + UIDictionary = (Dictionary)(dict[nameof(UIDictionary)] as Newtonsoft.Json.Linq.JObject).ToObject(typeof(Dictionary)); + } } } } diff --git a/NewHorizons/Handlers/TranslationHandler.cs b/NewHorizons/Handlers/TranslationHandler.cs index dd1229a3..7d9f7caa 100644 --- a/NewHorizons/Handlers/TranslationHandler.cs +++ b/NewHorizons/Handlers/TranslationHandler.cs @@ -4,38 +4,93 @@ using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; +using NewHorizons.Utility; using Logger = NewHorizons.Utility.Logger; namespace NewHorizons.Handlers { public static class TranslationHandler { - public static Dictionary> ShipLogTranslationDictionary = new Dictionary>(); - public static Dictionary> DialogueTranslationDictionary = new Dictionary>(); + private static Dictionary> _shipLogTranslationDictionary = new Dictionary>(); + private static Dictionary> _dialogueTranslationDictionary = new Dictionary>(); + private static Dictionary> _uiTranslationDictionary = new Dictionary>(); + + public enum TextType + { + SHIPLOG, + DIALOGUE, + UI + } + + public static string GetTranslation(string text, TextType type) + { + Dictionary> dictionary; + var language = TextTranslation.Get().m_language; + + switch (type) + { + case TextType.SHIPLOG: + dictionary = _shipLogTranslationDictionary; + break; + case TextType.DIALOGUE: + dictionary = _dialogueTranslationDictionary; + break; + case TextType.UI: + dictionary = _uiTranslationDictionary; + break; + default: + return text; + } + + if(dictionary.TryGetValue(language, out var table)) + { + if(table.TryGetValue(text, out var translatedText)) + { + return translatedText; + } + } + return text; + } public static void RegisterTranslation(TextTranslation.Language language, TranslationConfig config) { if (config.ShipLogDictionary != null && config.ShipLogDictionary.Count() > 0) { - if (!ShipLogTranslationDictionary.ContainsKey(language)) ShipLogTranslationDictionary.Add(language, new Dictionary()); + if (!_shipLogTranslationDictionary.ContainsKey(language)) _shipLogTranslationDictionary.Add(language, new Dictionary()); foreach (var originalKey in config.ShipLogDictionary.Keys) { var key = originalKey.Replace("<", "<").Replace(">", ">").Replace("", ""); - if (!ShipLogTranslationDictionary[language].ContainsKey(key)) ShipLogTranslationDictionary[language].Add(key, config.ShipLogDictionary[originalKey]); - else Logger.LogError($"Duplicate ship log translation for {originalKey}"); + if (!_shipLogTranslationDictionary[language].ContainsKey(key)) _shipLogTranslationDictionary[language].Add(key, config.ShipLogDictionary[originalKey]); + else _shipLogTranslationDictionary[language][key] = config.ShipLogDictionary[originalKey]; } } if (config.DialogueDictionary != null && config.DialogueDictionary.Count() > 0) { - if (!DialogueTranslationDictionary.ContainsKey(language)) DialogueTranslationDictionary.Add(language, new Dictionary()); + if (!_dialogueTranslationDictionary.ContainsKey(language)) _dialogueTranslationDictionary.Add(language, new Dictionary()); foreach (var originalKey in config.DialogueDictionary.Keys) { var key = originalKey.Replace("<", "<").Replace(">", ">").Replace("", ""); - if (!DialogueTranslationDictionary[language].ContainsKey(key)) DialogueTranslationDictionary[language].Add(key, config.DialogueDictionary[originalKey]); - else Logger.LogError($"Duplicate dialogue translation for {originalKey}"); + if (!_dialogueTranslationDictionary[language].ContainsKey(key)) _dialogueTranslationDictionary[language].Add(key, config.DialogueDictionary[originalKey]); + else _dialogueTranslationDictionary[language][key] = config.DialogueDictionary[originalKey]; + } + } + + if (config.UIDictionary != null && config.UIDictionary.Count() > 0) + { + if (!_uiTranslationDictionary.ContainsKey(language)) _uiTranslationDictionary.Add(language, new Dictionary()); + foreach (var originalKey in config.UIDictionary.Keys) + { + var key = originalKey.Replace("<", "<").Replace(">", ">").Replace("", ""); + + if (!_uiTranslationDictionary[language].ContainsKey(key)) _uiTranslationDictionary[language].Add(key, config.UIDictionary[originalKey]); + else _uiTranslationDictionary[language][key] = config.UIDictionary[originalKey]; + + //Also add an upper case version + if (!_uiTranslationDictionary[language].ContainsKey(key.ToUpper())) _uiTranslationDictionary[language].Add(key.ToUpper(), config.UIDictionary[originalKey].ToUpper()); + else _uiTranslationDictionary[language][key] = config.UIDictionary[originalKey].ToUpper(); } } } @@ -46,7 +101,7 @@ namespace NewHorizons.Handlers var language = TextTranslation.Get().m_language; string text = rawText; - if (DialogueTranslationDictionary.TryGetValue(language, out var dict) && dict.TryGetValue(rawText, out var translatedText)) text = translatedText; + if (_dialogueTranslationDictionary.TryGetValue(language, out var dict) && dict.TryGetValue(rawText, out var translatedText)) text = translatedText; TextTranslation.Get().m_table.Insert(key, text); } @@ -57,9 +112,32 @@ namespace NewHorizons.Handlers var language = TextTranslation.Get().m_language; string text = rawText; - if (ShipLogTranslationDictionary.TryGetValue(language, out var dict) && dict.TryGetValue(rawText, out var translatedText)) text = translatedText; + if (_shipLogTranslationDictionary.TryGetValue(language, out var dict) && dict.TryGetValue(rawText, out var translatedText)) text = translatedText; TextTranslation.Get().m_table.InsertShipLog(key, text); } + + public static int AddUI(string rawText) + { + var uiTable = TextTranslation.Get().m_table.theUITable; + var language = TextTranslation.Get().m_language; + + string text = rawText; + if (_shipLogTranslationDictionary.TryGetValue(language, out var dict) && dict.TryGetValue(rawText, out var translatedText)) text = translatedText; + text = text.ToUpper(); + + var key = uiTable.Keys.Max() + 1; + try + { + // Ensure it doesn't already contain our UI entry + KeyValuePair pair = uiTable.First(x => x.Value.Equals(text)); + if (pair.Equals(default(KeyValuePair))) key = pair.Key; + } + catch (Exception) { } + + TextTranslation.Get().m_table.Insert_UI(key, text); + + return key; + } } } diff --git a/NewHorizons/Main.cs b/NewHorizons/Main.cs index 04a6abdd..94a54188 100644 --- a/NewHorizons/Main.cs +++ b/NewHorizons/Main.cs @@ -102,6 +102,7 @@ namespace NewHorizons Tools.WarpDrivePatches.Apply(); Tools.OWCameraFix.Apply(); Tools.ShipLogPatches.Apply(); + Tools.TranslationPatches.Apply(); Logger.Log("Begin load of config files...", Logger.LogType.Log); @@ -122,7 +123,7 @@ namespace NewHorizons #region Reloading private void InitializePauseMenu() { - _reloadButton = ModHelper.Menus.PauseMenu.OptionsButton.Duplicate("RELOAD CONFIGS"); + _reloadButton = ModHelper.Menus.PauseMenu.OptionsButton.Duplicate(TranslationHandler.GetTranslation("Reload Configs", TranslationHandler.TextType.UI).ToUpper()); _reloadButton.OnClick += ReloadConfigs; UpdateReloadButton(); } @@ -216,8 +217,9 @@ namespace NewHorizons _shipWarpController.Init(); StarChartHandler.Init(); - LoadBody(LoadConfig(this, "AssetBundle/WarpDriveConfig.json")); + LoadBody(LoadConfig(this, "AssetBundle/WarpDriveConfig.json")); } + LoadTranslations(ModHelper.Manifest.ModFolderPath + "AssetBundle/", this); Instance.ModHelper.Events.Unity.FireOnNextUpdate(() => AstroObjectLocator.GetAstroObject("MapSatellite").gameObject.AddComponent()); @@ -450,33 +452,38 @@ namespace NewHorizons } if(Directory.Exists(folder + @"translations\")) { - var foundFile = false; - foreach(TextTranslation.Language language in Enum.GetValues(typeof(TextTranslation.Language))) - { - if (language == TextTranslation.Language.UNKNOWN || language == TextTranslation.Language.TOTAL) continue; - - var relativeFile = $"translations/{language.ToString().ToLower()}.json"; - - if (File.Exists($"{folder}{relativeFile}")) - { - Logger.Log($"Registering {language} translation from {mod.ModHelper.Manifest.Name} from {relativeFile}"); - - var config = new TranslationConfig($"{folder}{relativeFile}"); - if (config == null) - { - Logger.Log($"Found {folder}{relativeFile} but couldn't load it"); - continue; - } - - foundFile = true; - - TranslationHandler.RegisterTranslation(language, config); - } - } - if (!foundFile) Logger.LogWarning($"{mod.ModHelper.Manifest.Name} has a folder for translations but none were loaded"); + LoadTranslations(folder, mod); } } + private void LoadTranslations(string folder, IModBehaviour mod) + { + var foundFile = false; + foreach (TextTranslation.Language language in Enum.GetValues(typeof(TextTranslation.Language))) + { + if (language == TextTranslation.Language.UNKNOWN || language == TextTranslation.Language.TOTAL) continue; + + var relativeFile = $"translations/{language.ToString().ToLower()}.json"; + + if (File.Exists($"{folder}{relativeFile}")) + { + Logger.Log($"Registering {language} translation from {mod.ModHelper.Manifest.Name} from {relativeFile}"); + + var config = new TranslationConfig($"{folder}{relativeFile}"); + if (config == null) + { + Logger.Log($"Found {folder}{relativeFile} but couldn't load it"); + continue; + } + + foundFile = true; + + TranslationHandler.RegisterTranslation(language, config); + } + } + if (!foundFile) Logger.LogWarning($"{mod.ModHelper.Manifest.Name} has a folder for translations but none were loaded"); + } + public NewHorizonsBody LoadConfig(IModBehaviour mod, string relativeDirectory) { NewHorizonsBody body = null; diff --git a/NewHorizons/Tools/Patches.cs b/NewHorizons/Tools/Patches.cs index ebd666c9..acebf293 100644 --- a/NewHorizons/Tools/Patches.cs +++ b/NewHorizons/Tools/Patches.cs @@ -27,7 +27,6 @@ namespace NewHorizons.Tools public static void Apply() { // Prefixes - Main.Instance.ModHelper.HarmonyHelper.AddPrefix("GetHUDDisplayName", typeof(Patches), nameof(Patches.GetHUDDisplayName)); Main.Instance.ModHelper.HarmonyHelper.AddPrefix("CheckShipOutsideSolarSystem", typeof(Patches), nameof(Patches.CheckShipOutersideSolarSystem)); Main.Instance.ModHelper.HarmonyHelper.AddPrefix("LateUpdate", typeof(Patches), nameof(Patches.OnSunLightParamUpdaterLateUpdate)); Main.Instance.ModHelper.HarmonyHelper.AddPrefix("Update", typeof(Patches), nameof(Patches.OnSunSurfaceAudioControllerUpdate)); @@ -66,17 +65,6 @@ namespace NewHorizons.Tools Main.Instance.ModHelper.HarmonyHelper.AddPostfix("OnTargetReferenceFrame", typeof(Patches), nameof(Patches.OnMapControllerOnTargetReferenceFrame)); } - public static bool GetHUDDisplayName(ReferenceFrame __instance, ref string __result) - { - var ao = __instance.GetAstroObject(); - if (ao != null && ao.GetAstroObjectName() == AstroObject.Name.CustomString) - { - __result = ao.GetCustomName(); - return false; - } - return true; - } - public static bool CheckShipOutersideSolarSystem(PlayerState __instance, ref bool __result) { if (PlayerState._inBrambleDimension) return false; @@ -222,7 +210,7 @@ namespace NewHorizons.Tools SignalBuilder.SignalFrequencyOverrides.TryGetValue(__0, out string customName); if (customName != null) { - if (NewHorizonsData.KnowsFrequency(customName)) __result = customName; + if (NewHorizonsData.KnowsFrequency(customName)) __result = TranslationHandler.GetTranslation(customName, TranslationHandler.TextType.UI).ToUpper(); else __result = UITextLibrary.GetString(UITextType.SignalFreqUnidentified); return false; } diff --git a/NewHorizons/Tools/TranslationPatches.cs b/NewHorizons/Tools/TranslationPatches.cs new file mode 100644 index 00000000..4c6695b5 --- /dev/null +++ b/NewHorizons/Tools/TranslationPatches.cs @@ -0,0 +1,46 @@ +using NewHorizons.Handlers; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using UnityEngine; +using Logger = NewHorizons.Utility.Logger; + +namespace NewHorizons.Tools +{ + public static class TranslationPatches + { + public static void Apply() + { + Main.Instance.ModHelper.HarmonyHelper.AddPrefix(nameof(ReferenceFrame.GetHUDDisplayName), typeof(TranslationPatches), nameof(TranslationPatches.GetHUDDisplayName)); + + var canvasMapMarkerInit = typeof(CanvasMapMarker).GetMethod(nameof(CanvasMapMarker.Init), new Type[] { typeof(Canvas), typeof(Transform), typeof(string) }); + Main.Instance.ModHelper.HarmonyHelper.AddPostfix(canvasMapMarkerInit, typeof(TranslationPatches), nameof(TranslationPatches.OnCanvasMapMarkerInit)); + + Main.Instance.ModHelper.HarmonyHelper.AddPostfix(nameof(CanvasMapMarker.SetLabel), typeof(TranslationPatches), nameof(TranslationPatches.OnCanvasMapMarkerSetLabel)); + + } + + public static bool GetHUDDisplayName(ReferenceFrame __instance, ref string __result) + { + var ao = __instance.GetAstroObject(); + if (ao != null && ao.GetAstroObjectName() == AstroObject.Name.CustomString) + { + __result = TranslationHandler.GetTranslation(ao.GetCustomName(), TranslationHandler.TextType.UI); + return false; + } + return true; + } + + public static void OnCanvasMapMarkerInit(CanvasMapMarker __instance) + { + __instance._label = TranslationHandler.GetTranslation(__instance._label, TranslationHandler.TextType.UI); + } + + public static void OnCanvasMapMarkerSetLabel(CanvasMapMarker __instance) + { + __instance._label = TranslationHandler.GetTranslation(__instance._label, TranslationHandler.TextType.UI); + } + } +} diff --git a/NewHorizons/Tools/WarpDrivePatches.cs b/NewHorizons/Tools/WarpDrivePatches.cs index 4fa7e713..c2ab803d 100644 --- a/NewHorizons/Tools/WarpDrivePatches.cs +++ b/NewHorizons/Tools/WarpDrivePatches.cs @@ -22,7 +22,7 @@ namespace NewHorizons.Tools { if (!Main.HasWarpDrive) return; - var newPrompt = "Interstellar Mode"; + var newPrompt = TranslationHandler.GetTranslation("Interstellar Mode", TranslationHandler.TextType.UI); __instance._detectiveModePrompt.SetText(newPrompt); var text = GameObject.Find("Ship_Body/Module_Cabin/Systems_Cabin/ShipLogPivot/ShipLog/ShipLogPivot/ShipLogCanvas/ScreenPromptListScaleRoot/ScreenPromptList_UpperRight/ScreenPrompt/Text").GetComponent(); text.text = newPrompt; diff --git a/NewHorizons/Utility/AddToUITable.cs b/NewHorizons/Utility/AddToUITable.cs deleted file mode 100644 index 954b3d06..00000000 --- a/NewHorizons/Utility/AddToUITable.cs +++ /dev/null @@ -1,25 +0,0 @@ -using OWML.Utils; -using System; -using System.Collections.Generic; -using System.Linq; -using UnityEngine; - -namespace NewHorizons.Utility -{ - static class AddToUITable - { - public static int Add(string text) - { - TextTranslation.TranslationTable instance = GameObject.FindObjectOfType().GetValue("m_table"); - - try - { - KeyValuePair pair = instance.theUITable.First(x => x.Value.Equals(text)); - if (pair.Equals(default(KeyValuePair))) return pair.Key; - } - catch (Exception) { } - instance.Insert_UI(instance.theUITable.Keys.Max() + 1, text); - return instance.theUITable.Keys.Max(); - } - } -} diff --git a/NewHorizons/translation_schema.json b/NewHorizons/translation_schema.json index 53319acf..720a7a5e 100644 --- a/NewHorizons/translation_schema.json +++ b/NewHorizons/translation_schema.json @@ -13,7 +13,7 @@ "ShipLogDictionary": { "$ref": "#/$defs/table" }, - "UITable": { + "UIDictionary": { "$ref": "#/$defs/table" }, "DialogueDictionary": {