From 48aff163f9b2dad0d9ed3427c525970012a3ad33 Mon Sep 17 00:00:00 2001
From: Atony <75191600+AtonyGit@users.noreply.github.com>
Date: Thu, 27 Aug 2026 19:29:12 -0500
Subject: [PATCH] Fix issues with local settings tab localization
---
MiraAPI/LocalSettings/ILocalSetting.cs | 5 +++
MiraAPI/LocalSettings/LocalSettingsTab.cs | 22 ++++++++++--
.../SettingTypes/LocalEnumSetting.cs | 18 +++++++++-
.../SettingTypes/LocalNumberSetting.cs | 16 +++++++++
.../SettingTypes/LocalSettingBase.cs | 3 ++
.../SettingTypes/LocalSliderSetting.cs | 9 +++++
.../SettingTypes/LocalToggleSetting.cs | 10 ++++++
.../LocalSettings/OptionsMenuPatches.cs | 2 ++
MiraAPI/Translation/MiraLocaleManager.cs | 35 +++++++++++++++----
9 files changed, 110 insertions(+), 10 deletions(-)
diff --git a/MiraAPI/LocalSettings/ILocalSetting.cs b/MiraAPI/LocalSettings/ILocalSetting.cs
index b51a13d..9bc4bbd 100644
--- a/MiraAPI/LocalSettings/ILocalSetting.cs
+++ b/MiraAPI/LocalSettings/ILocalSetting.cs
@@ -39,4 +39,9 @@ public interface ILocalSetting
/// Whether it's the last on the row.
/// The created setting's .
GameObject? CreateOption(ToggleButtonBehaviour toggle, SlideBar slider, Transform parent, ref float offset, ref int order, bool last);
+
+ ///
+ /// Used to refresh the setting's information, usually for localization.
+ ///
+ void RefreshOption();
}
diff --git a/MiraAPI/LocalSettings/LocalSettingsTab.cs b/MiraAPI/LocalSettings/LocalSettingsTab.cs
index 7fc7e1d..e22f834 100644
--- a/MiraAPI/LocalSettings/LocalSettingsTab.cs
+++ b/MiraAPI/LocalSettings/LocalSettingsTab.cs
@@ -2,6 +2,7 @@
using System.Collections.Generic;
using BepInEx.Configuration;
using HarmonyLib;
+using MiraAPI.LocalSettings.SettingTypes;
using MiraAPI.Patches.LocalSettings;
using MiraAPI.Translation;
using MiraAPI.Utilities;
@@ -53,6 +54,11 @@ public abstract class LocalSettingsTab(ConfigFile config)
///
public List Settings { get; } = [];
+ ///
+ /// Gets a collection of s alongside the locale keys for them.
+ ///
+ public Dictionary Labels { get; } = [];
+
///
/// Gets the list of s.
///
@@ -74,12 +80,21 @@ public abstract class LocalSettingsTab(ConfigFile config)
}
///
- /// Attempts to open the tab.
+ /// Refreshes setting names upon opening the tab.
/// Override for custom behavior.
///
public virtual void Open()
{
- OptionsMenuPatches.Instance?.OpenTabGroup(TabIndex);
+ foreach (var setting in Settings)
+ {
+ setting.RefreshOption();
+ }
+
+ foreach (var label in Labels)
+ {
+ label.Key.text =
+ $"{label.Value.Translate()}";
+ }
}
///
@@ -273,7 +288,7 @@ public abstract class LocalSettingsTab(ConfigFile config)
return tabButtonObject.gameObject;
}
- private static void CreateLabel(GameObject template, Transform parent, string text, ref float offset)
+ private void CreateLabel(GameObject template, Transform parent, string text, ref float offset)
{
var label = Object.Instantiate(template, parent);
label.transform.localPosition = new Vector3(0, 1.85f - offset);
@@ -281,6 +296,7 @@ public abstract class LocalSettingsTab(ConfigFile config)
label.name = text;
var tmp = label.GetComponent();
+ Labels.Add(tmp, text);
tmp.text = $"{text.Translate()}";
tmp.alignment = TextAlignmentOptions.Center;
diff --git a/MiraAPI/LocalSettings/SettingTypes/LocalEnumSetting.cs b/MiraAPI/LocalSettings/SettingTypes/LocalEnumSetting.cs
index ac0f858..e1e0c7b 100644
--- a/MiraAPI/LocalSettings/SettingTypes/LocalEnumSetting.cs
+++ b/MiraAPI/LocalSettings/SettingTypes/LocalEnumSetting.cs
@@ -26,6 +26,10 @@ public class LocalEnumSetting : LocalSettingBase
///
public string[] Values { get; }
+ private SpriteRenderer _highlight { get; set; }
+
+ private TextMeshPro _btnText { get; set; }
+
///
/// Initializes a new instance of the class.
///
@@ -54,6 +58,7 @@ public class LocalEnumSetting : LocalSettingBase
{
var button = Object.Instantiate(toggle, parent).GetComponent();
var tmp = button.transform.FindChild("Text_TMP").GetComponent();
+ _btnText = tmp;
var rollover = button.GetComponent();
tmp.GetComponent().Destroy();
button.gameObject.SetActive(true);
@@ -63,6 +68,7 @@ public class LocalEnumSetting : LocalSettingBase
var highlight = button.transform.FindChild("ButtonHighlight")?.GetComponent();
if (highlight != null)
{
+ _highlight = highlight;
highlight.color = Tab!.TabAppearance.EnumHoverColor;
highlight.gameObject.SetActive(false);
}
@@ -125,9 +131,19 @@ public class LocalEnumSetting : LocalSettingBase
return button.gameObject;
}
+ ///
+ public override void RefreshOption()
+ {
+ _btnText.text = GetValueText();
+ if (_highlight)
+ {
+ _highlight.gameObject.SetActive(false);
+ }
+ }
+
///
protected override string GetValueText()
{
- return $"{Name.Translate()}: {Values[GetValue()]}";
+ return $"{Name.Translate()}: {Values[GetValue()].Translate()}";
}
}
diff --git a/MiraAPI/LocalSettings/SettingTypes/LocalNumberSetting.cs b/MiraAPI/LocalSettings/SettingTypes/LocalNumberSetting.cs
index 75d1fde..f37ea80 100644
--- a/MiraAPI/LocalSettings/SettingTypes/LocalNumberSetting.cs
+++ b/MiraAPI/LocalSettings/SettingTypes/LocalNumberSetting.cs
@@ -35,6 +35,10 @@ public class LocalNumberSetting : LocalSettingBase
///
public MiraNumberSuffixes SuffixType { get; }
+ private SpriteRenderer _highlight { get; set; }
+
+ private TextMeshPro _btnText { get; set; }
+
///
/// Initializes a new instance of the class.
///
@@ -65,6 +69,7 @@ public class LocalNumberSetting : LocalSettingBase
{
var button = Object.Instantiate(toggle, parent).GetComponent();
var tmp = button.transform.FindChild("Text_TMP").GetComponent();
+ _btnText = tmp;
var rollover = button.GetComponent();
tmp.GetComponent().Destroy();
button.gameObject.SetActive(true);
@@ -74,6 +79,7 @@ public class LocalNumberSetting : LocalSettingBase
var highlight = button.transform.FindChild("ButtonHighlight")?.GetComponent();
if (highlight != null)
{
+ _highlight = highlight;
highlight.color = Tab!.TabAppearance.NumberHoverColor;
highlight.gameObject.SetActive(false);
}
@@ -136,6 +142,16 @@ public class LocalNumberSetting : LocalSettingBase
return button.gameObject;
}
+ ///
+ public override void RefreshOption()
+ {
+ _btnText.text = GetValueText();
+ if (_highlight)
+ {
+ _highlight.gameObject.SetActive(false);
+ }
+ }
+
///
protected override string GetValueText()
{
diff --git a/MiraAPI/LocalSettings/SettingTypes/LocalSettingBase.cs b/MiraAPI/LocalSettings/SettingTypes/LocalSettingBase.cs
index d7c2c64..e26f6ce 100644
--- a/MiraAPI/LocalSettings/SettingTypes/LocalSettingBase.cs
+++ b/MiraAPI/LocalSettings/SettingTypes/LocalSettingBase.cs
@@ -54,6 +54,9 @@ public abstract class LocalSettingBase : ILocalSetting
/// The created setting.
public abstract GameObject CreateOption(ToggleButtonBehaviour toggle, SlideBar slider, Transform parent, ref float offset, ref int order, bool last);
+ ///
+ public abstract void RefreshOption();
+
///
/// Returns the formated string to use in the text of the setting.
///
diff --git a/MiraAPI/LocalSettings/SettingTypes/LocalSliderSetting.cs b/MiraAPI/LocalSettings/SettingTypes/LocalSliderSetting.cs
index eb59cce..2a90bfd 100644
--- a/MiraAPI/LocalSettings/SettingTypes/LocalSliderSetting.cs
+++ b/MiraAPI/LocalSettings/SettingTypes/LocalSliderSetting.cs
@@ -40,6 +40,8 @@ public class LocalSliderSetting : LocalSettingBase
///
public MiraNumberSuffixes SuffixType { get; }
+ private SlideBar _slider { get; set; }
+
///
/// Initializes a new instance of the class.
///
@@ -71,6 +73,7 @@ public class LocalSliderSetting : LocalSettingBase
public override GameObject CreateOption(ToggleButtonBehaviour toggle, SlideBar slider, Transform parent, ref float offset, ref int order, bool last)
{
var newSlider = Object.Instantiate(slider, parent).GetComponent();
+ _slider = newSlider;
var rollover = newSlider.GetComponent();
newSlider.Title = newSlider.transform.FindChild("Text_TMP").GetComponent(); // Why the hell slider has a title property that is not even assigned???
newSlider.Title.GetComponent().Destroy();
@@ -105,6 +108,12 @@ public class LocalSliderSetting : LocalSettingBase
return newSlider.gameObject;
}
+ ///
+ public override void RefreshOption()
+ {
+ _slider.Title.text = GetValueText();
+ }
+
///
protected override string GetValueText()
{
diff --git a/MiraAPI/LocalSettings/SettingTypes/LocalToggleSetting.cs b/MiraAPI/LocalSettings/SettingTypes/LocalToggleSetting.cs
index 3cb02e3..f28b6db 100644
--- a/MiraAPI/LocalSettings/SettingTypes/LocalToggleSetting.cs
+++ b/MiraAPI/LocalSettings/SettingTypes/LocalToggleSetting.cs
@@ -15,6 +15,8 @@ namespace MiraAPI.LocalSettings.SettingTypes;
///
public class LocalToggleSetting : LocalSettingBase
{
+ private ToggleButtonBehaviour _toggle { get; set; }
+
///
/// Initializes a new instance of the class.
///
@@ -32,6 +34,7 @@ public class LocalToggleSetting : LocalSettingBase
public override GameObject CreateOption(ToggleButtonBehaviour toggle, SlideBar slider, Transform parent, ref float offset, ref int order, bool last)
{
var toggleObject = Object.Instantiate(toggle, parent).GetComponent();
+ _toggle = toggleObject;
var tmp = toggleObject.transform.FindChild("Text_TMP").GetComponent();
var passiveButton = toggleObject.GetComponent();
var rollover = toggleObject.GetComponent();
@@ -86,4 +89,11 @@ public class LocalToggleSetting : LocalSettingBase
return toggleObject.gameObject;
}
+
+ ///
+ public override void RefreshOption()
+ {
+ _toggle.UpdateText(GetValue());
+ _toggle.Background.color = GetValue() ? Tab!.TabAppearance.ToggleActiveColor : Tab!.TabAppearance.ToggleInactiveColor;
+ }
}
diff --git a/MiraAPI/Patches/LocalSettings/OptionsMenuPatches.cs b/MiraAPI/Patches/LocalSettings/OptionsMenuPatches.cs
index a8cab15..75edd5e 100644
--- a/MiraAPI/Patches/LocalSettings/OptionsMenuPatches.cs
+++ b/MiraAPI/Patches/LocalSettings/OptionsMenuPatches.cs
@@ -213,6 +213,8 @@ public static class OptionsMenuPatches
if (background != null)
background.color = tab.TabAppearance.TabColor;
+
+ tab.Open();
}
private static void CustomClose(LocalSettingsTab tab)
{
diff --git a/MiraAPI/Translation/MiraLocaleManager.cs b/MiraAPI/Translation/MiraLocaleManager.cs
index 9f9bfd7..a34f22f 100644
--- a/MiraAPI/Translation/MiraLocaleManager.cs
+++ b/MiraAPI/Translation/MiraLocaleManager.cs
@@ -4,6 +4,7 @@ using System.IO;
using System.Linq;
using System.Reflection;
using System.Xml;
+using MiraAPI.Utilities;
using Reactor.Localization.Utilities;
using UnityEngine;
@@ -97,7 +98,22 @@ public static class MiraLocaleManager
var callingAssembly = Assembly.GetCallingAssembly();
var dir = GetModLangDir(modGuid);
- LoadInternalStrings(callingAssembly, modGuid, dir);
+ LoadInternalStrings(callingAssembly, callingAssembly.GetName().Name!, modGuid, dir);
+ }
+
+ ///
+ /// Registers translations for a mod. Copies embedded XML to mira_languages/{modGuid}/ on first run,
+ /// then loads all XML files from that directory into memory.
+ /// Call once per mod during plugin Load().
+ ///
+ /// The mod GUID (e.g., "mira.example").
+ /// The mod's root namespace (e.g., "mira.api").
+ public static void Register(string modGuid, string internalName)
+ {
+ var callingAssembly = Assembly.GetCallingAssembly();
+ var dir = GetModLangDir(modGuid);
+
+ LoadInternalStrings(callingAssembly, internalName, modGuid, dir);
}
///
@@ -194,7 +210,7 @@ public static class MiraLocaleManager
return newString;
}
- private static void LoadInternalStrings(Assembly assembly, string modGuid, string dir)
+ private static void LoadInternalStrings(Assembly assembly, string internalName, string modGuid, string dir)
{
Directory.CreateDirectory(dir);
@@ -203,8 +219,9 @@ public static class MiraLocaleManager
Locale[modGuid] = [];
}
- var resourcePrefix = $"{assembly.GetName().Name}.Resources.Locale.";
+ var resourcePrefix = $"{internalName}.Resources.Locale.";
+ var atLeastOneLoaded = false;
foreach (var locale in LangList)
{
using var resourceStream =
@@ -221,7 +238,8 @@ public static class MiraLocaleManager
{
var dict = ParseXmlFile(xmlContent);
Locale[modGuid][locale.Key] = dict;
- Info($"Loaded {locale.Key} translation for mod {modGuid} ({dict.Count} keys)");
+ Info($"Loaded {locale.Key.ToDisplayString()} translation for mod {modGuid} ({dict.Count} keys)");
+ atLeastOneLoaded = true;
}
catch (Exception e)
{
@@ -229,6 +247,11 @@ public static class MiraLocaleManager
}
}
+ if (!atLeastOneLoaded)
+ {
+ Error($"No internal strings were found for {internalName}!");
+ }
+
if (!Locale.TryGetValue(modGuid, out _))
{
Locale[modGuid] = [];
@@ -247,11 +270,11 @@ public static class MiraLocaleManager
{
var dict = ParseXmlFile(filePath);
Locale[modGuid][lang] = dict;
- Info($"Loaded {lang} translation for mod {modGuid} ({dict.Count} keys)");
+ Info($"Loaded external {lang.ToDisplayString()} translation for mod {modGuid} ({dict.Count} keys)");
}
catch (Exception e)
{
- Error($"Failed to load translation {filePath}: {e.Message}");
+ Error($"Failed to load external translation {filePath}: {e.Message}");
}
}
}