feat: Add IMsgLocalizer and improve localization support

```
Introduce IMsgLocalizer interface and improve localization functionality

- Extend `StringLocalizer` to support `IMsg` object localization and implement the new `IMsgLocalizer` interface.
- Update `.github/workflows/dotnet.yml` to use newer Actions versions, enable coverage tracking, and generate dynamic coverage badges.
- Add `IMsgLocalizer` interface and implement localization indexer in `IMsgLocalizer.cs`.
- Update dependency injection in `Startup.cs` to register `IMsgLocalizer` and refine localization services.
- Improve tests in `LocaleTest.cs` to validate `IMsgLocalizer` usage, placeholder substitution, and remove redundant assertions.

Minor: Adjust `en.yml` formatting by removing unnecessary quotes.
```
This commit is contained in:
MSWS
2025-07-30 03:59:53 -07:00
parent aa37d6e78a
commit b44c73cf87
6 changed files with 31 additions and 14 deletions

View File

@@ -28,15 +28,15 @@ jobs:
- name: Build
run: dotnet build --no-restore
- name: Copy Lang Folder
run: |
mkdir -p build_output/lang/
cp -r TTT/Test/lang/* build_output/lang/
- name: Publish Test Project
run: dotnet publish TTT/Test/Test.csproj --no-restore --no-build -o build_output -c Debug
- uses: actions/upload-artifact@v4
with:
name: build_output
@@ -61,7 +61,6 @@ jobs:
path: build_output
- name: Run tests
# run: "dotnet run --no-build --no-restore --project TTT/Test/Test.csproj -- --coverage --coverage-output $GITHUB_WORKSPACE/coverage.xml --coverage-output-format cobertura"
run: "dotnet ./build_output/Test.dll --coverage --coverage-output $GITHUB_WORKSPACE/coverage.xml --coverage-output-format cobertura"
- name: Code Coverage Summary Report
@@ -95,6 +94,6 @@ jobs:
valColorRange: ${{ env.CODE_COVERAGE }}
maxColorRange: 100
minColorRange: 33
- name: Write to Job Summary
run: cat code-coverage-results.md >> $GITHUB_STEP_SUMMARY

7
Locale/IMsgLocalizer.cs Normal file
View File

@@ -0,0 +1,7 @@
using Microsoft.Extensions.Localization;
namespace TTT.Locale;
public interface IMsgLocalizer : IStringLocalizer {
string this[IMsg msg] { get; }
}

View File

@@ -8,7 +8,7 @@ namespace TTT.Locale;
/// A custom implementation of <see cref="IStringLocalizer"/> that adds support
/// for in-string placeholders like %key% and grammatical pluralization with %s%.
/// </summary>
public partial class StringLocalizer : IStringLocalizer {
public partial class StringLocalizer : IStringLocalizer, IMsgLocalizer {
public static readonly StringLocalizer Instance =
new(new JsonLocalizerFactory());
@@ -112,4 +112,6 @@ public partial class StringLocalizer : IStringLocalizer {
return value;
}
public string this[IMsg msg] => localizer[msg.Key, msg.Args];
}

View File

@@ -1,14 +1,21 @@
using Microsoft.Extensions.Localization;
using TTT.Locale;
using Xunit;
namespace TTT.Test.Locale;
public class LocaleTest(IStringLocalizer localizer) {
public class LocaleTest(IMsgLocalizer localizer) {
[Fact]
public void Locale_BasicTest() {
var msg = localizer["BASIC_TEST"];
Assert.NotNull(msg);
Assert.Equal("Foobar", msg.Value);
var result = localizer[TestMsgs.BASIC_TEST];
Assert.Equal("Foobar", result);
}
[Fact]
public void Locale_Placeholder_Works() {
var msg = localizer[TestMsgs.PLACEHOLDER_TEST("Test")];
Assert.Equal("Placeholder: Test", msg);
}
}

View File

@@ -29,7 +29,9 @@ public class Startup {
services.AddScoped<IScheduler>(s => s.GetRequiredService<TestScheduler>());
services.AddScoped<IGameManager, GameManager>();
services.AddScoped<IStringLocalizerFactory, JsonLocalizerFactory>();
services.AddTransient<IStringLocalizer, StringLocalizer>();
services.AddScoped<StringLocalizer>();
services.AddTransient<IMsgLocalizer>(s
=> s.GetRequiredService<StringLocalizer>());
services.AddModBehavior<GenericInitTester>();
services.AddModBehavior<PluginInitTester>();

View File

@@ -1,2 +1,2 @@
"BASIC_TEST": "Foobar"
"PLACEHOLDER_TEST": "Placeholder: {0}"
BASIC_TEST: "Foobar"
PLACEHOLDER_TEST: "Placeholder: {0}"