mirror of
https://github.com/NuclearPowered/Reactor.git
synced 2026-10-19 15:51:54 +00:00
Add localization API (#64)
Co-authored-by: js6pak <kubastaron@hotmail.com>
This commit is contained in:
1 parent
f2da251ae5
commit
0c8156aaf6
14 files changed
+523
-86
No files matched your search
@@ -31,7 +31,7 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.435" PrivateAssets="all" />
|
<PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.435" PrivateAssets="all" />
|
||||||
<AdditionalFiles Include="$(MSBuildThisFileDirectory)\stylecop.json" Link="stylecop.json" />
|
<AdditionalFiles Include="$(MSBuildThisFileDirectory)\stylecop.json" Link="stylecop.json" Visible="false" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<CodeAnalysisRuleSet>$(MSBuildThisFileDirectory)\stylecop.ruleset</CodeAnalysisRuleSet>
|
<CodeAnalysisRuleSet>$(MSBuildThisFileDirectory)\stylecop.ruleset</CodeAnalysisRuleSet>
|
||||||
|
|||||||
@@ -0,0 +1,26 @@
|
|||||||
|
using Reactor.Localization;
|
||||||
|
|
||||||
|
namespace Reactor.Example;
|
||||||
|
|
||||||
|
public class ExampleLocalizationProvider : LocalizationProvider
|
||||||
|
{
|
||||||
|
public override bool TryGetText(StringNames stringName, out string? result)
|
||||||
|
{
|
||||||
|
if (stringName == (StringNames) 1337)
|
||||||
|
{
|
||||||
|
switch (CurrentLanguage)
|
||||||
|
{
|
||||||
|
case SupportedLangs.English:
|
||||||
|
result = "Cringe English";
|
||||||
|
return true;
|
||||||
|
|
||||||
|
default:
|
||||||
|
result = "Based " + CurrentLanguage;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result = null;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,6 +2,8 @@ using System;
|
|||||||
using BepInEx;
|
using BepInEx;
|
||||||
using BepInEx.Unity.IL2CPP;
|
using BepInEx.Unity.IL2CPP;
|
||||||
using Il2CppInterop.Runtime.Attributes;
|
using Il2CppInterop.Runtime.Attributes;
|
||||||
|
using Reactor.Localization;
|
||||||
|
using Reactor.Localization.Utilities;
|
||||||
using Reactor.Networking;
|
using Reactor.Networking;
|
||||||
using Reactor.Networking.Attributes;
|
using Reactor.Networking.Attributes;
|
||||||
using Reactor.Networking.Rpc;
|
using Reactor.Networking.Rpc;
|
||||||
@@ -19,9 +21,14 @@ namespace Reactor.Example;
|
|||||||
[ReactorModFlags(ModFlags.RequireOnAllClients)]
|
[ReactorModFlags(ModFlags.RequireOnAllClients)]
|
||||||
public partial class ExamplePlugin : BasePlugin
|
public partial class ExamplePlugin : BasePlugin
|
||||||
{
|
{
|
||||||
|
private static StringNames _helloStringName;
|
||||||
|
|
||||||
public override void Load()
|
public override void Load()
|
||||||
{
|
{
|
||||||
this.AddComponent<ExampleComponent>();
|
this.AddComponent<ExampleComponent>();
|
||||||
|
|
||||||
|
_helloStringName = CustomStringName.CreateAndRegister("Hello!");
|
||||||
|
LocalizationManager.Register(new ExampleLocalizationProvider());
|
||||||
}
|
}
|
||||||
|
|
||||||
[RegisterInIl2Cpp]
|
[RegisterInIl2Cpp]
|
||||||
@@ -34,19 +41,29 @@ public partial class ExamplePlugin : BasePlugin
|
|||||||
{
|
{
|
||||||
TestWindow = new DragWindow(new Rect(60, 20, 0, 0), "Example", () =>
|
TestWindow = new DragWindow(new Rect(60, 20, 0, 0), "Example", () =>
|
||||||
{
|
{
|
||||||
|
if (GUILayout.Button("Log CustomStringName"))
|
||||||
|
{
|
||||||
|
Logger<ExamplePlugin>.Info(TranslationController.Instance.GetString(_helloStringName));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GUILayout.Button("Log localized string"))
|
||||||
|
{
|
||||||
|
Logger<ExamplePlugin>.Info(TranslationController.Instance.GetString((StringNames) 1337));
|
||||||
|
}
|
||||||
|
|
||||||
if (AmongUsClient.Instance && PlayerControl.LocalPlayer)
|
if (AmongUsClient.Instance && PlayerControl.LocalPlayer)
|
||||||
{
|
{
|
||||||
if (GUILayout.Button("Send ExampleRpc"))
|
if (GUILayout.Button("Send ExampleRpc"))
|
||||||
{
|
{
|
||||||
var name = PlayerControl.LocalPlayer.Data.PlayerName;
|
var playerName = PlayerControl.LocalPlayer.Data.PlayerName;
|
||||||
Rpc<ExampleRpc>.Instance.Send(new ExampleRpc.Data($"Send: from {name}"), ackCallback: () =>
|
Rpc<ExampleRpc>.Instance.Send(new ExampleRpc.Data($"Send: from {playerName}"), ackCallback: () =>
|
||||||
{
|
{
|
||||||
Logger<ExamplePlugin>.Info("Got an acknowledgement for example rpc");
|
Logger<ExamplePlugin>.Info("Got an acknowledgement for example rpc");
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!AmongUsClient.Instance.AmHost)
|
if (!AmongUsClient.Instance.AmHost)
|
||||||
{
|
{
|
||||||
Rpc<ExampleRpc>.Instance.SendTo(AmongUsClient.Instance.HostId, new ExampleRpc.Data($"SendTo: from {name} to host"));
|
Rpc<ExampleRpc>.Instance.SendTo(AmongUsClient.Instance.HostId, new ExampleRpc.Data($"SendTo: from {playerName} to host"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,6 +12,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Files", "Solution
|
|||||||
AmongUs.props = AmongUs.props
|
AmongUs.props = AmongUs.props
|
||||||
Directory.Build.props = Directory.Build.props
|
Directory.Build.props = Directory.Build.props
|
||||||
nuget.config = nuget.config
|
nuget.config = nuget.config
|
||||||
|
stylecop.json = stylecop.json
|
||||||
|
stylecop.ruleset = stylecop.ruleset
|
||||||
EndProjectSection
|
EndProjectSection
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Reactor.Networking.Shared", "Reactor.Networking.Shared\Reactor.Networking.Shared.csproj", "{1E68CA20-22EB-4E57-B525-81970BE6363D}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Reactor.Networking.Shared", "Reactor.Networking.Shared\Reactor.Networking.Shared.csproj", "{1E68CA20-22EB-4E57-B525-81970BE6363D}"
|
||||||
|
|||||||
@@ -1,82 +0,0 @@
|
|||||||
using System.Collections.Generic;
|
|
||||||
using System.Globalization;
|
|
||||||
using System.Linq;
|
|
||||||
using HarmonyLib;
|
|
||||||
using Il2CppInterop.Runtime.InteropTypes.Arrays;
|
|
||||||
|
|
||||||
namespace Reactor.Localization;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Provides a way to use custom static StringNames.
|
|
||||||
/// </summary>
|
|
||||||
public class CustomStringName
|
|
||||||
{
|
|
||||||
private static int _lastId = -1;
|
|
||||||
|
|
||||||
private static readonly List<CustomStringName> _list = new();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets a list of all <see cref="CustomStringName"/>s.
|
|
||||||
/// </summary>
|
|
||||||
public static IReadOnlyList<CustomStringName> List => _list.AsReadOnly();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Registers a <see cref="CustomStringName"/> with specified <paramref name="value"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="value">The value.</param>
|
|
||||||
/// <returns>A <see cref="CustomStringName"/>.</returns>
|
|
||||||
public static CustomStringName Register(string value)
|
|
||||||
{
|
|
||||||
var customStringName = new CustomStringName(_lastId--, value);
|
|
||||||
_list.Add(customStringName);
|
|
||||||
|
|
||||||
return customStringName;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the id.
|
|
||||||
/// </summary>
|
|
||||||
public int Id { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the value.
|
|
||||||
/// </summary>
|
|
||||||
public string Value { get; }
|
|
||||||
|
|
||||||
private CustomStringName(int id, string value)
|
|
||||||
{
|
|
||||||
Id = id;
|
|
||||||
Value = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Defines an implicit conversion of a <see cref="CustomStringName"/> to a <see cref="StringNames"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="name">The <see cref="CustomStringName"/>.</param>
|
|
||||||
/// <returns>A <see cref="StringNames"/>.</returns>
|
|
||||||
public static implicit operator StringNames(CustomStringName name) => (StringNames) name.Id;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Defines an explicit conversion of a <see cref="StringNames"/> to a <see cref="CustomStringName"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="name">The <see cref="StringNames"/>.</param>
|
|
||||||
/// <returns>A <see cref="CustomStringName"/>.</returns>
|
|
||||||
public static explicit operator CustomStringName?(StringNames name) => List.SingleOrDefault(x => x.Id == (int) name);
|
|
||||||
|
|
||||||
[HarmonyPatch(typeof(TranslationController), nameof(TranslationController.GetString), typeof(StringNames), typeof(Il2CppReferenceArray<Il2CppSystem.Object>))]
|
|
||||||
private static class GetStringPatch
|
|
||||||
{
|
|
||||||
public static bool Prefix(StringNames id, Il2CppReferenceArray<Il2CppSystem.Object> parts, ref string __result)
|
|
||||||
{
|
|
||||||
var customStringName = (CustomStringName?) id;
|
|
||||||
|
|
||||||
if (customStringName != null)
|
|
||||||
{
|
|
||||||
__result = string.Format(CultureInfo.InvariantCulture, customStringName.Value, parts);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
using System;
|
||||||
|
using System.Globalization;
|
||||||
|
|
||||||
|
namespace Reactor.Localization.Extensions;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Provides extension methods for <see cref="SupportedLangs"/>.
|
||||||
|
/// </summary>
|
||||||
|
public static class SupportedLangsExtensions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a <see cref="CultureInfo"/> from the specified <paramref name="language"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="language">The <see cref="SupportedLangs"/>.</param>
|
||||||
|
/// <returns>a <see cref="CultureInfo"/>.</returns>
|
||||||
|
public static CultureInfo ToCultureInfo(this SupportedLangs language)
|
||||||
|
{
|
||||||
|
return language switch
|
||||||
|
{
|
||||||
|
SupportedLangs.English => CultureInfo.GetCultureInfo("en"),
|
||||||
|
SupportedLangs.Latam => CultureInfo.GetCultureInfo("es"),
|
||||||
|
SupportedLangs.Brazilian => CultureInfo.GetCultureInfo("pt-BR"),
|
||||||
|
SupportedLangs.Portuguese => CultureInfo.GetCultureInfo("pt"),
|
||||||
|
SupportedLangs.Korean => CultureInfo.GetCultureInfo("ko"),
|
||||||
|
SupportedLangs.Russian => CultureInfo.GetCultureInfo("ru"),
|
||||||
|
SupportedLangs.Dutch => CultureInfo.GetCultureInfo("nl"),
|
||||||
|
SupportedLangs.Filipino => CultureInfo.GetCultureInfo("fil"),
|
||||||
|
SupportedLangs.French => CultureInfo.GetCultureInfo("fr"),
|
||||||
|
SupportedLangs.German => CultureInfo.GetCultureInfo("de"),
|
||||||
|
SupportedLangs.Italian => CultureInfo.GetCultureInfo("it"),
|
||||||
|
SupportedLangs.Japanese => CultureInfo.GetCultureInfo("ja"),
|
||||||
|
SupportedLangs.Spanish => CultureInfo.GetCultureInfo("es"),
|
||||||
|
SupportedLangs.SChinese => CultureInfo.GetCultureInfo("zh-Hans"),
|
||||||
|
SupportedLangs.TChinese => CultureInfo.GetCultureInfo("zh-Hant"),
|
||||||
|
SupportedLangs.Irish => CultureInfo.GetCultureInfo("ga"),
|
||||||
|
_ => throw new ArgumentOutOfRangeException(nameof(language), language, null),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,111 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using Il2CppInterop.Runtime.InteropTypes.Arrays;
|
||||||
|
|
||||||
|
namespace Reactor.Localization;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Handles custom <see cref="StringNames"/> localization.
|
||||||
|
/// </summary>
|
||||||
|
public static class LocalizationManager
|
||||||
|
{
|
||||||
|
private static readonly List<LocalizationProvider> _providers = new();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets registered <see cref="LocalizationProvider"/>s.
|
||||||
|
/// </summary>
|
||||||
|
public static IReadOnlyList<LocalizationProvider> Providers { get; } = _providers.AsReadOnly();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Registers a new <see cref="LocalizationProvider"/> to be used for obtaining translations.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="provider">A <see cref="LocalizationProvider"/> instance.</param>
|
||||||
|
public static void Register(LocalizationProvider provider)
|
||||||
|
{
|
||||||
|
if (!_providers.Contains(provider))
|
||||||
|
{
|
||||||
|
_providers.Add(provider);
|
||||||
|
|
||||||
|
if (TranslationController.InstanceExists)
|
||||||
|
{
|
||||||
|
provider.SetLanguage(TranslationController.Instance.currentLanguage.languageID);
|
||||||
|
}
|
||||||
|
|
||||||
|
_providers.Sort((a, b) => b.Priority - a.Priority);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Unregisters a <see cref="LocalizationProvider"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="provider">The <see cref="LocalizationProvider"/> to unregister.</param>
|
||||||
|
public static void Unregister(LocalizationProvider provider)
|
||||||
|
{
|
||||||
|
_providers.Remove(provider);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static bool TryGetTextFormatted(StringNames stringName, Il2CppReferenceArray<Il2CppSystem.Object> parts, out string text)
|
||||||
|
{
|
||||||
|
foreach (var provider in _providers)
|
||||||
|
{
|
||||||
|
if (provider.TryGetTextFormatted(stringName, parts, out text!))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
text = string.Empty;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static bool TryGetText(StringNames stringName, out string text)
|
||||||
|
{
|
||||||
|
foreach (var provider in _providers)
|
||||||
|
{
|
||||||
|
if (provider.TryGetText(stringName, out text!))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
text = string.Empty;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static bool TryGetStringName(SystemTypes systemType, out StringNames stringName)
|
||||||
|
{
|
||||||
|
foreach (var provider in _providers)
|
||||||
|
{
|
||||||
|
if (provider.TryGetStringName(systemType, out var stringNameNullable))
|
||||||
|
{
|
||||||
|
stringName = stringNameNullable!.Value;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
stringName = default;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static bool TryGetStringName(TaskTypes taskTypes, out StringNames stringName)
|
||||||
|
{
|
||||||
|
foreach (var provider in _providers)
|
||||||
|
{
|
||||||
|
if (provider.TryGetStringName(taskTypes, out var stringNameNullable))
|
||||||
|
{
|
||||||
|
stringName = stringNameNullable!.Value;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
stringName = default;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static void OnLanguageChanged(SupportedLangs newLanguage)
|
||||||
|
{
|
||||||
|
foreach (var provider in _providers)
|
||||||
|
{
|
||||||
|
provider.SetLanguage(newLanguage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,90 @@
|
|||||||
|
using Il2CppInterop.Runtime.InteropTypes.Arrays;
|
||||||
|
using Reactor.Utilities;
|
||||||
|
|
||||||
|
namespace Reactor.Localization;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The required implementation of a localization provider class.
|
||||||
|
/// </summary>
|
||||||
|
public abstract class LocalizationProvider
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the current language Among Us is set to.
|
||||||
|
/// <br/>
|
||||||
|
/// If used from <see cref="OnLanguageChanged"/>, this property will return the old language, not the new one.
|
||||||
|
/// </summary>
|
||||||
|
public SupportedLangs? CurrentLanguage { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the priority of this <see cref="LocalizationProvider"/>.
|
||||||
|
/// The higher the priority is, the earlier it will be invoked in relation to other providers.
|
||||||
|
/// <br/>
|
||||||
|
/// You can use the <see cref="ReactorPriority"/> class for this value if you want to make this easier.
|
||||||
|
/// </summary>
|
||||||
|
public virtual int Priority => 0;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the localized text for the given <see cref="StringNames"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="stringName">The <see cref="StringNames"/> to localize.</param>
|
||||||
|
/// <param name="result">The <see cref="string"/> representation of the given <see cref="StringNames"/>.</param>
|
||||||
|
/// <returns>Whether or not this <see cref="LocalizationProvider"/> can handle this <see cref="StringNames"/>.</returns>
|
||||||
|
public virtual bool TryGetText(StringNames stringName, out string? result)
|
||||||
|
{
|
||||||
|
result = null;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the localized text for the given <see cref="StringNames"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="stringName">The <see cref="StringNames"/> to localize.</param>
|
||||||
|
/// <param name="parts">The arguments used for formatting.</param>
|
||||||
|
/// <param name="result">The <see cref="string"/> representation of the given <see cref="StringNames"/>.</param>
|
||||||
|
/// <returns>Whether or not this <see cref="LocalizationProvider"/> can handle this <see cref="StringNames"/>.</returns>
|
||||||
|
public virtual bool TryGetTextFormatted(StringNames stringName, Il2CppReferenceArray<Il2CppSystem.Object> parts, out string? result)
|
||||||
|
{
|
||||||
|
if (!TryGetText(stringName, out result)) return false;
|
||||||
|
|
||||||
|
result = Il2CppSystem.String.Format(result, parts);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the <see cref="StringNames"/> equivalent for the given <see cref="SystemTypes"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="systemType">The <see cref="SystemTypes"/> value.</param>
|
||||||
|
/// <param name="result">The <see cref="string"/> representation of the given <see cref="StringNames"/>.</param>
|
||||||
|
/// <returns>Whether or not this <see cref="LocalizationProvider"/> can handle this <see cref="StringNames"/>.</returns>
|
||||||
|
public virtual bool TryGetStringName(SystemTypes systemType, out StringNames? result)
|
||||||
|
{
|
||||||
|
result = null;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the <see cref="StringNames"/> equivalent for the given <see cref="TaskTypes"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="taskType">The <see cref="TaskTypes"/> value.</param>
|
||||||
|
/// <param name="result">The <see cref="string"/> representation of the given <see cref="StringNames"/>.</param>
|
||||||
|
/// <returns>Whether or not this <see cref="LocalizationProvider"/> can handle this <see cref="StringNames"/>.</returns>
|
||||||
|
public virtual bool TryGetStringName(TaskTypes taskType, out StringNames? result)
|
||||||
|
{
|
||||||
|
result = null;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This method is called when the Among Us language is changed by the user.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="newLanguage">The new language that Among Us has been set to.</param>
|
||||||
|
public virtual void OnLanguageChanged(SupportedLangs newLanguage)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void SetLanguage(SupportedLangs newLanguage)
|
||||||
|
{
|
||||||
|
OnLanguageChanged(newLanguage);
|
||||||
|
CurrentLanguage = newLanguage;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,85 @@
|
|||||||
|
using HarmonyLib;
|
||||||
|
using Il2CppInterop.Runtime.InteropTypes.Arrays;
|
||||||
|
|
||||||
|
namespace Reactor.Localization.Patches;
|
||||||
|
|
||||||
|
[HarmonyPatch]
|
||||||
|
internal static class GetStringPatch
|
||||||
|
{
|
||||||
|
[HarmonyPatch(typeof(TranslationController), nameof(TranslationController.GetString), typeof(StringNames), typeof(Il2CppReferenceArray<Il2CppSystem.Object>))]
|
||||||
|
[HarmonyPatch(typeof(TranslationController), nameof(TranslationController.GetStringWithDefault), typeof(StringNames), typeof(string), typeof(Il2CppReferenceArray<Il2CppSystem.Object>))]
|
||||||
|
[HarmonyPrefix]
|
||||||
|
public static bool StringNamesPatch(StringNames id, Il2CppReferenceArray<Il2CppSystem.Object> parts, out string __result)
|
||||||
|
{
|
||||||
|
if (LocalizationManager.TryGetTextFormatted(id, parts, out __result))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
[HarmonyPatch(typeof(TranslationController), nameof(TranslationController.GetString), typeof(SystemTypes))]
|
||||||
|
[HarmonyPrefix]
|
||||||
|
public static bool SystemTypesStringPatch(TranslationController __instance, SystemTypes room, ref string __result)
|
||||||
|
{
|
||||||
|
if (LocalizationManager.TryGetStringName(room, out var stringName))
|
||||||
|
{
|
||||||
|
if (LocalizationManager.TryGetText(stringName, out var text))
|
||||||
|
{
|
||||||
|
__result = text;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
__result = __instance.GetString(stringName);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
[HarmonyPatch(typeof(TranslationController), nameof(TranslationController.GetSystemName))]
|
||||||
|
[HarmonyPrefix]
|
||||||
|
public static bool SystemTypesStringNamesPatch(SystemTypes room, ref StringNames __result)
|
||||||
|
{
|
||||||
|
if (LocalizationManager.TryGetStringName(room, out var stringName))
|
||||||
|
{
|
||||||
|
__result = stringName;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
[HarmonyPatch(typeof(TranslationController), nameof(TranslationController.GetString), typeof(TaskTypes))]
|
||||||
|
[HarmonyPrefix]
|
||||||
|
public static bool TaskTypesStringPatch(TranslationController __instance, TaskTypes task, ref string __result)
|
||||||
|
{
|
||||||
|
if (LocalizationManager.TryGetStringName(task, out var stringName))
|
||||||
|
{
|
||||||
|
if (LocalizationManager.TryGetText(stringName, out var text))
|
||||||
|
{
|
||||||
|
__result = text;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
__result = __instance.GetString(stringName);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
[HarmonyPatch(typeof(TranslationController), nameof(TranslationController.GetTaskName))]
|
||||||
|
[HarmonyPrefix]
|
||||||
|
public static bool TaskTypesStringNamesPatch(TaskTypes task, ref StringNames __result)
|
||||||
|
{
|
||||||
|
if (LocalizationManager.TryGetStringName(task, out var stringName))
|
||||||
|
{
|
||||||
|
__result = stringName;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
using HarmonyLib;
|
||||||
|
|
||||||
|
namespace Reactor.Localization.Patches;
|
||||||
|
|
||||||
|
[HarmonyPatch]
|
||||||
|
internal static class LanguageChangedPatch
|
||||||
|
{
|
||||||
|
[HarmonyPatch(typeof(TranslationController), nameof(TranslationController.Initialize))]
|
||||||
|
[HarmonyPostfix]
|
||||||
|
public static void Initialize(TranslationController __instance)
|
||||||
|
{
|
||||||
|
if (TranslationController.Instance.GetInstanceID() == __instance.GetInstanceID())
|
||||||
|
LocalizationManager.OnLanguageChanged(__instance.currentLanguage.languageID);
|
||||||
|
}
|
||||||
|
|
||||||
|
[HarmonyPatch(typeof(TranslationController), nameof(TranslationController.SetLanguage))]
|
||||||
|
[HarmonyPostfix]
|
||||||
|
public static void SetLanguage(TranslationController __instance)
|
||||||
|
{
|
||||||
|
LocalizationManager.OnLanguageChanged(__instance.currentLanguage.languageID);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using Reactor.Utilities;
|
||||||
|
|
||||||
|
namespace Reactor.Localization.Providers;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Utility for adding hard-coded localization.
|
||||||
|
/// </summary>
|
||||||
|
public sealed class HardCodedLocalizationProvider : LocalizationProvider
|
||||||
|
{
|
||||||
|
private static readonly Dictionary<StringNames, string> _strings = new();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds a custom, hard-coded translation for a <see cref="StringNames"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="stringName">The <see cref="StringNames"/>.</param>
|
||||||
|
/// <param name="value">The text.</param>
|
||||||
|
public static void Register(StringNames stringName, string value)
|
||||||
|
{
|
||||||
|
if (_strings.ContainsKey(stringName))
|
||||||
|
{
|
||||||
|
Warning($"Registering StringName {stringName} that already exists");
|
||||||
|
}
|
||||||
|
|
||||||
|
_strings[stringName] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public override int Priority => ReactorPriority.Low;
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public override bool TryGetText(StringNames stringName, out string? result)
|
||||||
|
{
|
||||||
|
return _strings.TryGetValue(stringName, out result);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
using Reactor.Localization.Providers;
|
||||||
|
|
||||||
|
namespace Reactor.Localization.Utilities;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Provides a way to use custom static <see cref="StringNames"/>.
|
||||||
|
/// </summary>
|
||||||
|
public static class CustomStringName
|
||||||
|
{
|
||||||
|
private static int _lastId = int.MinValue + 1;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates an returns a unique <see cref="StringNames"/> value.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>A unique <see cref="StringNames"/>.</returns>
|
||||||
|
public static StringNames Create()
|
||||||
|
{
|
||||||
|
var id = _lastId++;
|
||||||
|
return (StringNames) id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates, registeres and returns a unique <see cref="StringNames"/> value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="text">The text.</param>
|
||||||
|
/// <returns>A unique <see cref="StringNames"/>.</returns>
|
||||||
|
public static StringNames CreateAndRegister(string text)
|
||||||
|
{
|
||||||
|
var stringName = Create();
|
||||||
|
HardCodedLocalizationProvider.Register(stringName, text);
|
||||||
|
return stringName;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,6 +6,8 @@ using BepInEx.Configuration;
|
|||||||
using BepInEx.Unity.IL2CPP;
|
using BepInEx.Unity.IL2CPP;
|
||||||
using HarmonyLib;
|
using HarmonyLib;
|
||||||
using Il2CppInterop.Runtime.Attributes;
|
using Il2CppInterop.Runtime.Attributes;
|
||||||
|
using Reactor.Localization;
|
||||||
|
using Reactor.Localization.Providers;
|
||||||
using Reactor.Networking;
|
using Reactor.Networking;
|
||||||
using Reactor.Networking.Attributes;
|
using Reactor.Networking.Attributes;
|
||||||
using Reactor.Networking.Rpc;
|
using Reactor.Networking.Rpc;
|
||||||
@@ -44,11 +46,15 @@ public partial class ReactorPlugin : BasePlugin
|
|||||||
{
|
{
|
||||||
PluginSingleton<ReactorPlugin>.Instance = this;
|
PluginSingleton<ReactorPlugin>.Instance = this;
|
||||||
PluginSingleton<BasePlugin>.Initialize();
|
PluginSingleton<BasePlugin>.Initialize();
|
||||||
|
|
||||||
RegisterInIl2CppAttribute.Initialize();
|
RegisterInIl2CppAttribute.Initialize();
|
||||||
ModList.Initialize();
|
ModList.Initialize();
|
||||||
|
|
||||||
RegisterCustomRpcAttribute.Initialize();
|
RegisterCustomRpcAttribute.Initialize();
|
||||||
MessageConverterAttribute.Initialize();
|
MessageConverterAttribute.Initialize();
|
||||||
MethodRpcAttribute.Initialize();
|
MethodRpcAttribute.Initialize();
|
||||||
|
|
||||||
|
LocalizationManager.Register(new HardCodedLocalizationProvider());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
|
|||||||
@@ -0,0 +1,52 @@
|
|||||||
|
namespace Reactor.Utilities;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Class containing common priorities to be used in various places across Reactor.
|
||||||
|
/// </summary>
|
||||||
|
public static class ReactorPriority
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Lowest priority, will happen last.
|
||||||
|
/// </summary>
|
||||||
|
public const int Last = -800;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Very low priority.
|
||||||
|
/// </summary>
|
||||||
|
public const int VeryLow = -600;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Low priority.
|
||||||
|
/// </summary>
|
||||||
|
public const int Low = -400;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Lower than normal priority.
|
||||||
|
/// </summary>
|
||||||
|
public const int LowerThanNormal = -200;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Normal priority.
|
||||||
|
/// </summary>
|
||||||
|
public const int Normal = 0;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Higher than normal priority.
|
||||||
|
/// </summary>
|
||||||
|
public const int HigherThanNormal = 200;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// High priority.
|
||||||
|
/// </summary>
|
||||||
|
public const int High = 400;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Very high priority.
|
||||||
|
/// </summary>
|
||||||
|
public const int VeryHigh = 600;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Highest priority, will happen first.
|
||||||
|
/// </summary>
|
||||||
|
public const int First = 800;
|
||||||
|
}
|
||||||
Reference in new issue
Block a user