[+] i18n
Build AquaMai / build (SDEZ) (push) Has been cancelled Details
Build AquaMai / build (SDGA145) (push) Has been cancelled Details

pull/55/head
Clansty 2024-09-30 01:26:54 +08:00
parent 78a396ce4b
commit 07b8cc04be
No known key found for this signature in database
GPG Key ID: 3A6BE8BAF2EDE134
8 changed files with 381 additions and 14 deletions

View File

@ -299,6 +299,7 @@ DEBUG</DefineConstants>
<Compile Include="Fix\ForceAsServer.cs" />
<Compile Include="Fix\ForceFreePlay.cs" />
<Compile Include="Fix\ForcePaidPlay.cs" />
<Compile Include="Fix\I18nSingleAssemblyHook.cs" />
<Compile Include="Fix\RemoveEncryption.cs" />
<Compile Include="Fix\SkipVersionCheck.cs" />
<Compile Include="Helpers\GuiSizes.cs" />
@ -307,6 +308,11 @@ DEBUG</DefineConstants>
<Compile Include="Helpers\SharedInstances.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Main.cs" />
<Compile Include="Resources\Locale.Designer.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>Locale.resx</DependentUpon>
</Compile>
<Compile Include="TimeSaving\ImproveLoadSpeed.cs" />
<Compile Include="TimeSaving\IWontTapOrSlideVigorously.cs" />
<Compile Include="TimeSaving\SkipEventInfo.cs" />
@ -344,6 +350,13 @@ DEBUG</DefineConstants>
<ItemGroup>
<EmbeddedResource Include="AquaMai.zh.toml" WithCulture="false" />
<EmbeddedResource Include="AquaMai.toml" />
<EmbeddedResource Include="Resources\Locale.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Locale.Designer.cs</LastGenOutput>
</EmbeddedResource>
<EmbeddedResource Include="Resources\Locale.zh.resx" WithCulture="false">
<DependentUpon>Locale.resx</DependentUpon>
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
<Content Include="FodyWeavers.xml" />

View File

@ -22,6 +22,7 @@ namespace AquaMai
public class UXConfig
{
public string Locale { get; set; }
public bool SinglePlayer { get; set; }
public bool LoadAssetsPng { get; set; }
public bool LoadJacketPng { get; set; }

View File

@ -0,0 +1,33 @@
using System.Globalization;
using System.Resources;
using HarmonyLib;
using MelonLoader;
namespace AquaMai.Fix;
public class I18nSingleAssemblyHook
{
[HarmonyPatch(typeof(ResourceManager), "InternalGetResourceSet", typeof(CultureInfo), typeof(bool), typeof(bool))]
[HarmonyPrefix]
public static bool GetResourceSet(CultureInfo culture, bool createIfNotExists, bool tryParents, ref ResourceSet __result, ResourceManager __instance)
{
var GetResourceFileName = __instance.GetType().GetMethod("GetResourceFileName", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
var resourceFileName = (string)GetResourceFileName.Invoke(__instance, [culture]);
var MainAssembly = typeof(AquaMai).Assembly;
var manifestResourceStream = MainAssembly.GetManifestResourceStream(resourceFileName);
if (manifestResourceStream == null)
{
return true;
}
var resourceGroveler = __instance.GetType().GetField("resourceGroveler", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance).GetValue(__instance);
var CreateResourceSet = resourceGroveler.GetType().GetMethod("CreateResourceSet", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
var resourceSet = CreateResourceSet.Invoke(resourceGroveler, [manifestResourceStream, MainAssembly]);
var AddResourceSet = __instance.GetType().GetMethod("AddResourceSet", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static);
var localResourceSets = __instance.GetType().GetField("_resourceSets", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance).GetValue(__instance);
object[] args = [localResourceSets, culture.Name, resourceSet];
AddResourceSet.Invoke(null, args);
__result = (ResourceSet)args[2];
return false;
}
}

View File

@ -1,13 +1,17 @@
using System;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Threading;
using AquaMai.Fix;
using AquaMai.Helpers;
using AquaMai.Resources;
using AquaMai.Utils;
using AquaMai.UX;
using MelonLoader;
using Tomlet;
using UnityEngine;
namespace AquaMai
{
@ -91,6 +95,22 @@ namespace AquaMai
s.CopyTo(fs);
}
private static void InitLocale()
{
if (!string.IsNullOrEmpty(AppConfig.UX.Locale))
{
Locale.Culture = CultureInfo.GetCultureInfo(AppConfig.UX.Locale);
return;
}
Locale.Culture = Application.systemLanguage switch
{
SystemLanguage.Chinese or SystemLanguage.ChineseSimplified or SystemLanguage.ChineseTraditional => CultureInfo.GetCultureInfo("zh"),
SystemLanguage.English => CultureInfo.GetCultureInfo("en"),
_ => CultureInfo.InvariantCulture
};
}
public override void OnInitializeMelon()
{
// Prevent Chinese characters from being garbled
@ -119,6 +139,11 @@ namespace AquaMai
AppConfig.UX.LoadAssetsPng = AppConfig.UX.LoadAssetsPng || AppConfig.UX.LoadJacketPng;
AppConfig.UX.LoadJacketPng = false;
// Init locale with patching C# runtime
// https://stackoverflow.com/questions/1952638/single-assembly-multi-language-windows-forms-deployment-ilmerge-and-satellite-a
Patch(typeof(I18nSingleAssemblyHook));
InitLocale();
// Fixes that does not have side effects
// These don't need to be configurable

View File

@ -0,0 +1,181 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
using MelonLoader;
namespace AquaMai.Resources {
using System;
/// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary>
// This class was auto-generated by the StronglyTypedResourceBuilder
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Locale {
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Locale() {
}
/// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("AquaMai.Resources.Locale", typeof(Locale).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// Overrides the current thread's CurrentUICulture property for all
/// resource lookups using this strongly typed resource class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set {
resourceCulture = value;
}
}
/// <summary>
/// Looks up a localized string similar to End.
/// </summary>
internal static string MarkRepeatEnd {
get {
return ResourceManager.GetString("MarkRepeatEnd", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Start.
/// </summary>
internal static string MarkRepeatStart {
get {
return ResourceManager.GetString("MarkRepeatStart", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Pause.
/// </summary>
internal static string Pause {
get {
return ResourceManager.GetString("Pause", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Loop Not Set.
/// </summary>
internal static string RepeatNotSet {
get {
return ResourceManager.GetString("RepeatNotSet", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Reset.
/// </summary>
internal static string RepeatReset {
get {
return ResourceManager.GetString("RepeatReset", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Loop Set.
/// </summary>
internal static string RepeatStartEndSet {
get {
return ResourceManager.GetString("RepeatStartEndSet", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Loop Start Set.
/// </summary>
internal static string RepeatStartSet {
get {
return ResourceManager.GetString("RepeatStartSet", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Seek &lt;&lt;.
/// </summary>
internal static string SeekBackward {
get {
return ResourceManager.GetString("SeekBackward", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Seek &gt;&gt;.
/// </summary>
internal static string SeekForward {
get {
return ResourceManager.GetString("SeekForward", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Speed.
/// </summary>
internal static string Speed {
get {
return ResourceManager.GetString("Speed", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Speed -.
/// </summary>
internal static string SpeedDown {
get {
return ResourceManager.GetString("SpeedDown", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Speed Reset.
/// </summary>
internal static string SpeedReset {
get {
return ResourceManager.GetString("SpeedReset", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Speed +.
/// </summary>
internal static string SpeedUp {
get {
return ResourceManager.GetString("SpeedUp", resourceCulture);
}
}
}
}

View File

@ -0,0 +1,60 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:element name="root" msdata:IsDataSet="true">
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>1.3</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="SeekBackward" xml:space="preserve">
<value>Seek &lt;&lt;</value>
</data>
<data name="SeekForward" xml:space="preserve">
<value>Seek &gt;&gt;</value>
</data>
<data name="Pause" xml:space="preserve">
<value>Pause</value>
</data>
<data name="MarkRepeatStart" xml:space="preserve">
<value>Start</value>
</data>
<data name="MarkRepeatEnd" xml:space="preserve">
<value>End</value>
</data>
<data name="RepeatReset" xml:space="preserve">
<value>Reset</value>
</data>
<data name="RepeatNotSet" xml:space="preserve">
<value>Loop Not Set</value>
</data>
<data name="RepeatStartSet" xml:space="preserve">
<value>Loop Start Set</value>
</data>
<data name="RepeatStartEndSet" xml:space="preserve">
<value>Loop Set</value>
</data>
<data name="SpeedDown" xml:space="preserve">
<value>Speed -</value>
</data>
<data name="SpeedUp" xml:space="preserve">
<value>Speed +</value>
</data>
<data name="Speed" xml:space="preserve">
<value>Speed</value>
</data>
<data name="SpeedReset" xml:space="preserve">
<value>Speed Reset</value>
</data>
</root>

View File

@ -0,0 +1,53 @@
<root>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>1.3</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="SeekBackward" xml:space="preserve">
<value>倒退 &lt;&lt;</value>
</data>
<data name="SeekForward" xml:space="preserve">
<value>快进 &gt;&gt;</value>
</data>
<data name="Pause" xml:space="preserve">
<value>暂停</value>
</data>
<data name="MarkRepeatEnd" xml:space="preserve">
<value>标记结尾</value>
</data>
<data name="MarkRepeatStart" xml:space="preserve">
<value>标记开头</value>
</data>
<data name="RepeatNotSet" xml:space="preserve">
<value>循环未设定</value>
</data>
<data name="RepeatReset" xml:space="preserve">
<value>循环解除</value>
</data>
<data name="RepeatStartEndSet" xml:space="preserve">
<value>循环已设定</value>
</data>
<data name="RepeatStartSet" xml:space="preserve">
<value>循环开头已设定</value>
</data>
<data name="Speed" xml:space="preserve">
<value>速度</value>
</data>
<data name="SpeedDown" xml:space="preserve">
<value>速度 -</value>
</data>
<data name="SpeedReset" xml:space="preserve">
<value>速度重置</value>
</data>
<data name="SpeedUp" xml:space="preserve">
<value>速度 +</value>
</data>
</root>

View File

@ -1,6 +1,7 @@
using System;
using AquaMai.Fix;
using AquaMai.Helpers;
using AquaMai.Resources;
using Manager;
using UnityEngine;
@ -55,31 +56,31 @@ public class PractiseModeUI : MonoBehaviour
controlHeight * 4 + GuiSizes.Margin * 5
), "");
GUI.Button(GetButtonRect(0, 0), "Seek <<");
GUI.Button(GetButtonRect(1, 0), "Pause");
GUI.Button(GetButtonRect(2, 0), "Seek >>");
GUI.Button(GetButtonRect(0, 0), Locale.SeekBackward);
GUI.Button(GetButtonRect(1, 0), Locale.Pause);
GUI.Button(GetButtonRect(2, 0), Locale.SeekForward);
if (PractiseMode.repeatStart == -1)
{
GUI.Button(GetButtonRect(0, 1), "Start");
GUI.Label(GetButtonRect(1, 1), "Loop not set");
GUI.Button(GetButtonRect(0, 1), Locale.MarkRepeatStart);
GUI.Label(GetButtonRect(1, 1), Locale.RepeatNotSet);
}
else if (PractiseMode.repeatEnd == -1)
{
GUI.Button(GetButtonRect(0, 1), "End");
GUI.Label(GetButtonRect(1, 1), "Loop start set");
GUI.Button(GetButtonRect(2, 1), "Reset");
GUI.Button(GetButtonRect(0, 1), Locale.MarkRepeatEnd);
GUI.Label(GetButtonRect(1, 1), Locale.RepeatStartSet);
GUI.Button(GetButtonRect(2, 1), Locale.RepeatReset);
}
else
{
GUI.Label(GetButtonRect(1, 1), "Loop set");
GUI.Button(GetButtonRect(2, 1), "Reset");
GUI.Label(GetButtonRect(1, 1), Locale.RepeatStartEndSet);
GUI.Button(GetButtonRect(2, 1), Locale.RepeatReset);
}
GUI.Button(GetButtonRect(0, 2), "Speed -");
GUI.Label(GetButtonRect(1, 2), $"Speed {PractiseMode.speed * 100:000}%");
GUI.Button(GetButtonRect(2, 2), "Speed +");
GUI.Button(GetButtonRect(1, 3), "Speed Reset");
GUI.Button(GetButtonRect(0, 2), Locale.SpeedDown);
GUI.Label(GetButtonRect(1, 2), $"{Locale.Speed} {PractiseMode.speed * 100:000}%");
GUI.Button(GetButtonRect(2, 2), Locale.SpeedUp);
GUI.Button(GetButtonRect(1, 3), Locale.SpeedReset);
}
public void Update()