mirror of
https://github.com/GeWuYou/GFramework.git
synced 2026-05-07 00:39:00 +08:00
feat(godot): 添加Godot本地化设置功能
- 新增LocalizationMap类实现用户语言到Godot locale和框架语言码的映射 - 创建GodotLocalizationSettings类同步应用本地化设置到Godot引擎和GFramework框架 - 添加测试项目配置文件GFramework.Game.Tests.csproj - 实现本地化设置的单元测试验证语言同步功能
This commit is contained in:
parent
a22e522cf9
commit
41dd759379
@ -19,6 +19,7 @@
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\GFramework.Game\GFramework.Game.csproj"/>
|
||||
<ProjectReference Include="..\GFramework.Core\GFramework.Core.csproj"/>
|
||||
<ProjectReference Include="..\GFramework.Godot\GFramework.Godot.csproj"/>
|
||||
<ProjectReference Include="..\GFramework.SourceGenerators.Abstractions\GFramework.SourceGenerators.Abstractions.csproj"
|
||||
OutputItemType="Analyzer"
|
||||
ReferenceOutputAssembly="false"/>
|
||||
|
||||
@ -0,0 +1,71 @@
|
||||
using GFramework.Godot.Setting;
|
||||
using GFramework.Godot.Setting.Data;
|
||||
|
||||
namespace GFramework.Game.Tests.Setting;
|
||||
|
||||
/// <summary>
|
||||
/// 覆盖 Godot 本地化设置应用器的语言同步行为,防止持久化语言仅影响 Godot 而未同步框架管理器。
|
||||
/// </summary>
|
||||
[TestFixture]
|
||||
public sealed class GodotLocalizationSettingsTests
|
||||
{
|
||||
[Test]
|
||||
public async Task Apply_ShouldSyncEnglishToGodotLocaleAndFrameworkLanguage()
|
||||
{
|
||||
var manager = new Mock<ILocalizationManager>(MockBehavior.Strict);
|
||||
manager.Setup(it => it.SetLanguage("eng"));
|
||||
string? appliedLocale = null;
|
||||
|
||||
var applicator = CreateApplicator("English", manager.Object, locale => appliedLocale = locale);
|
||||
|
||||
await applicator.Apply();
|
||||
|
||||
Assert.That(appliedLocale, Is.EqualTo("en"));
|
||||
manager.Verify(it => it.SetLanguage("eng"), Times.Once);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task Apply_ShouldSyncChineseToGodotLocaleAndFrameworkLanguage()
|
||||
{
|
||||
var manager = new Mock<ILocalizationManager>(MockBehavior.Strict);
|
||||
manager.Setup(it => it.SetLanguage("zhs"));
|
||||
string? appliedLocale = null;
|
||||
|
||||
var applicator = CreateApplicator("简体中文", manager.Object, locale => appliedLocale = locale);
|
||||
|
||||
await applicator.Apply();
|
||||
|
||||
Assert.That(appliedLocale, Is.EqualTo("zh_CN"));
|
||||
manager.Verify(it => it.SetLanguage("zhs"), Times.Once);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task Apply_ShouldFallbackUnknownLanguageToEnglish()
|
||||
{
|
||||
var manager = new Mock<ILocalizationManager>(MockBehavior.Strict);
|
||||
manager.Setup(it => it.SetLanguage("eng"));
|
||||
string? appliedLocale = null;
|
||||
|
||||
var applicator = CreateApplicator("Esperanto", manager.Object, locale => appliedLocale = locale);
|
||||
|
||||
await applicator.Apply();
|
||||
|
||||
Assert.That(appliedLocale, Is.EqualTo("en"));
|
||||
manager.Verify(it => it.SetLanguage("eng"), Times.Once);
|
||||
}
|
||||
|
||||
private static GodotLocalizationSettings CreateApplicator(
|
||||
string language,
|
||||
ILocalizationManager manager,
|
||||
Action<string> applyGodotLocale)
|
||||
{
|
||||
var settingsModel = new Mock<ISettingsModel>(MockBehavior.Strict);
|
||||
settingsModel.Setup(it => it.GetData<LocalizationSettings>()).Returns(new LocalizationSettings
|
||||
{
|
||||
Language = language
|
||||
});
|
||||
|
||||
return new GodotLocalizationSettings(settingsModel.Object, new LocalizationMap(), () => manager,
|
||||
applyGodotLocale);
|
||||
}
|
||||
}
|
||||
@ -18,12 +18,54 @@ namespace GFramework.Godot.Setting.Data;
|
||||
/// </summary>
|
||||
public class LocalizationMap
|
||||
{
|
||||
private const string DefaultFrameworkLanguage = "eng";
|
||||
private const string DefaultGodotLocale = "en";
|
||||
|
||||
/// <summary>
|
||||
/// 用户语言 -> Godot locale 映射表
|
||||
/// 用户语言 -> Godot locale 映射表。
|
||||
/// </summary>
|
||||
public Dictionary<string, string> LanguageMap { get; set; } = new()
|
||||
{
|
||||
{ "简体中文", "zh_CN" },
|
||||
{ "English", "en" }
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// 用户语言 -> GFramework 本地化语言码映射表。
|
||||
/// </summary>
|
||||
public Dictionary<string, string> FrameworkLanguageMap { get; set; } = new()
|
||||
{
|
||||
{ "简体中文", "zhs" },
|
||||
{ "English", "eng" }
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// 解析用户保存的语言值对应的 Godot locale。
|
||||
/// </summary>
|
||||
/// <param name="storedLanguage">设置系统中保存的语言值。</param>
|
||||
/// <returns>对应的 Godot locale;未知值时回退为英文。</returns>
|
||||
public string ResolveGodotLocale(string? storedLanguage)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(storedLanguage))
|
||||
{
|
||||
return DefaultGodotLocale;
|
||||
}
|
||||
|
||||
return LanguageMap.GetValueOrDefault(storedLanguage, DefaultGodotLocale);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 解析用户保存的语言值对应的框架语言码。
|
||||
/// </summary>
|
||||
/// <param name="storedLanguage">设置系统中保存的语言值。</param>
|
||||
/// <returns>对应的框架语言码;未知值时回退为英文。</returns>
|
||||
public string ResolveFrameworkLanguage(string? storedLanguage)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(storedLanguage))
|
||||
{
|
||||
return DefaultFrameworkLanguage;
|
||||
}
|
||||
|
||||
return FrameworkLanguageMap.GetValueOrDefault(storedLanguage, DefaultFrameworkLanguage);
|
||||
}
|
||||
}
|
||||
@ -11,32 +11,82 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
using GFramework.Core.Abstractions.Localization;
|
||||
using GFramework.Game.Abstractions.Setting;
|
||||
using GFramework.Game.Abstractions.Setting.Data;
|
||||
using GFramework.Godot.Setting.Data;
|
||||
using Godot;
|
||||
|
||||
namespace GFramework.Godot.Setting;
|
||||
|
||||
/// <summary>
|
||||
/// Godot本地化设置类,负责应用本地化配置到Godot引擎
|
||||
/// Godot 本地化设置类,负责将持久化语言配置同时应用到 Godot 引擎与 GFramework 本地化管理器。
|
||||
/// </summary>
|
||||
/// <param name="model">设置模型</param>
|
||||
/// <param name="localizationMap">本地化映射表</param>
|
||||
public class GodotLocalizationSettings(ISettingsModel model, LocalizationMap localizationMap)
|
||||
: IResetApplyAbleSettings
|
||||
public class GodotLocalizationSettings : IResetApplyAbleSettings
|
||||
{
|
||||
private readonly Action<string> _applyGodotLocale;
|
||||
private readonly Func<ILocalizationManager?> _localizationManagerResolver;
|
||||
private readonly LocalizationMap _localizationMap;
|
||||
private readonly ISettingsModel _model;
|
||||
|
||||
/// <summary>
|
||||
/// 应用本地化设置到Godot引擎
|
||||
/// 初始化 Godot 本地化设置应用器,并默认从当前架构上下文解析框架本地化管理器。
|
||||
/// </summary>
|
||||
/// <param name="model">设置模型。</param>
|
||||
/// <param name="localizationMap">本地化映射表。</param>
|
||||
public GodotLocalizationSettings(ISettingsModel model, LocalizationMap localizationMap)
|
||||
: this(model, localizationMap, TryResolveLocalizationManager, TranslationServer.SetLocale)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 初始化 Godot 本地化设置应用器。
|
||||
/// </summary>
|
||||
/// <param name="model">设置模型。</param>
|
||||
/// <param name="localizationMap">本地化映射表。</param>
|
||||
/// <param name="localizationManagerResolver">框架本地化管理器解析器。</param>
|
||||
public GodotLocalizationSettings(
|
||||
ISettingsModel model,
|
||||
LocalizationMap localizationMap,
|
||||
Func<ILocalizationManager?> localizationManagerResolver)
|
||||
: this(model, localizationMap, localizationManagerResolver, TranslationServer.SetLocale)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 初始化 Godot 本地化设置应用器,并显式指定 Godot locale 应用动作。
|
||||
/// 该重载主要用于测试或自定义引擎桥接。
|
||||
/// </summary>
|
||||
/// <param name="model">设置模型。</param>
|
||||
/// <param name="localizationMap">本地化映射表。</param>
|
||||
/// <param name="localizationManagerResolver">框架本地化管理器解析器。</param>
|
||||
/// <param name="applyGodotLocale">Godot locale 应用动作。</param>
|
||||
public GodotLocalizationSettings(
|
||||
ISettingsModel model,
|
||||
LocalizationMap localizationMap,
|
||||
Func<ILocalizationManager?> localizationManagerResolver,
|
||||
Action<string> applyGodotLocale)
|
||||
{
|
||||
_model = model ?? throw new ArgumentNullException(nameof(model));
|
||||
_localizationMap = localizationMap ?? throw new ArgumentNullException(nameof(localizationMap));
|
||||
_localizationManagerResolver =
|
||||
localizationManagerResolver ?? throw new ArgumentNullException(nameof(localizationManagerResolver));
|
||||
_applyGodotLocale = applyGodotLocale ?? throw new ArgumentNullException(nameof(applyGodotLocale));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 应用本地化设置到 Godot 引擎与 GFramework 本地化管理器。
|
||||
/// </summary>
|
||||
/// <returns>完成的任务</returns>
|
||||
public Task Apply()
|
||||
{
|
||||
var settings = model.GetData<LocalizationSettings>();
|
||||
// 尝试从映射表获取 Godot locale
|
||||
var locale = localizationMap.LanguageMap.GetValueOrDefault(settings.Language, "en");
|
||||
// 默认值
|
||||
TranslationServer.SetLocale(locale);
|
||||
var settings = _model.GetData<LocalizationSettings>();
|
||||
var locale = _localizationMap.ResolveGodotLocale(settings.Language);
|
||||
var frameworkLanguage = _localizationMap.ResolveFrameworkLanguage(settings.Language);
|
||||
|
||||
_applyGodotLocale(locale);
|
||||
|
||||
// 设置系统持久化的是用户可见语言值;这里需要同步框架语言码,避免 Godot 与框架状态分裂。
|
||||
_localizationManagerResolver()?.SetLanguage(frameworkLanguage);
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
@ -45,18 +95,30 @@ public class GodotLocalizationSettings(ISettingsModel model, LocalizationMap loc
|
||||
/// </summary>
|
||||
public void Reset()
|
||||
{
|
||||
model.GetData<LocalizationSettings>().Reset();
|
||||
_model.GetData<LocalizationSettings>().Reset();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取本地化设置的数据对象。
|
||||
/// 该属性提供对本地化设置数据的只读访问。
|
||||
/// </summary>
|
||||
public ISettingsData Data { get; } = model.GetData<LocalizationSettings>();
|
||||
public ISettingsData Data => _model.GetData<LocalizationSettings>();
|
||||
|
||||
/// <summary>
|
||||
/// 获取本地化设置数据的类型。
|
||||
/// 该属性返回本地化设置数据的具体类型信息。
|
||||
/// </summary>
|
||||
public Type DataType { get; } = typeof(LocalizationSettings);
|
||||
|
||||
private static ILocalizationManager? TryResolveLocalizationManager()
|
||||
{
|
||||
try
|
||||
{
|
||||
return GameContext.GetFirstArchitectureContext().GetSystem<ILocalizationManager>();
|
||||
}
|
||||
catch (InvalidOperationException)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user