Skip to content
Merged

I18n v2 #2709

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions BetterGenshinImpact/App.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
<bgivc:EnumToKVPConverter x:Key="EnumToKVPConverter" />
<bgivc:CultureInfoNameToKVPConverter x:Key="CultureInfoNameToKVPConverter" />
<bgivc:StringToColorConverter x:Key="StringToColorConverter" />
<bgivc:TrConverter x:Key="TrConverter" />
<Style BasedOn="{StaticResource DefaultTextBoxStyle}" TargetType="{x:Type TextBox}">
<Setter Property="behavior:ClipboardInterceptor.EnableSafeClipboard" Value="True" />
</Style>
Expand Down
8 changes: 7 additions & 1 deletion BetterGenshinImpact/App.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,13 @@ public partial class App : Application
}

Log.Logger = loggerConfiguration.CreateLogger();
services.AddLogging(c => c.AddSerilog());
services.AddSingleton<IMissingTranslationReporter, SupabaseMissingTranslationReporter>();
services.AddSingleton<ITranslationService, JsonTranslationService>();
services.AddLogging(logging =>
{
logging.ClearProviders();
logging.Services.AddSingleton<ILoggerProvider, TranslatingSerilogLoggerProvider>();
});

services.AddLocalization();

Expand Down
4 changes: 4 additions & 0 deletions BetterGenshinImpact/BetterGenshinImpact.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@
<PackageReference Include="Serilog.Sinks.Console" Version="6.0.0" />
<PackageReference Include="Serilog.Sinks.File" Version="6.0.0" />
<PackageReference Include="Serilog.Sinks.RichTextBoxEx.Wpf" Version="1.1.0.1" />
<!-- <PackageReference Include="supabase-csharp" Version="0.16.2" />-->
<PackageReference Include="System.Drawing.Common" Version="10.0.0" />
<PackageReference Include="System.IO.Hashing" Version="9.0.4" />
<PackageReference Include="TorchSharp" Version="0.105.0" />
Expand Down Expand Up @@ -200,6 +201,9 @@
<None Update="GameTask\AutoDomain\Assets\1920x1080\**">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="User\I18n\en.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>

<ItemGroup>
Expand Down
4 changes: 2 additions & 2 deletions BetterGenshinImpact/Core/Config/OtherConfig.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System;
using System;
using BetterGenshinImpact.Core.Recognition;
using BetterGenshinImpact.Model;
using CommunityToolkit.Mvvm.ComponentModel;
Expand Down Expand Up @@ -121,4 +121,4 @@ public partial class Ocr : ObservableObject
/// </summary>
[ObservableProperty]
private string _uiCultureInfoName = "zh-Hans";
}
}
1 change: 0 additions & 1 deletion BetterGenshinImpact/Core/Script/ScriptRepoUpdater.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
using System.Net.Http;
using System.Threading.Tasks;
using System.Windows;
using Windows.UI.Xaml.Automation;
using BetterGenshinImpact.View.Windows;
using LibGit2Sharp;
using LibGit2Sharp.Handlers;
Expand Down
130 changes: 130 additions & 0 deletions BetterGenshinImpact/Helpers/TranslatingSerilogLoggerProvider.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
using System;
using System.Collections.Generic;
using System.Linq;
using BetterGenshinImpact.Service.Interface;
using Microsoft.Extensions.Logging;
using Serilog;
using Serilog.Events;

namespace BetterGenshinImpact.Helpers;

public sealed class TranslatingSerilogLoggerProvider : ILoggerProvider
{
private readonly ITranslationService _translationService;

public TranslatingSerilogLoggerProvider(ITranslationService translationService)
{
_translationService = translationService;
}

public Microsoft.Extensions.Logging.ILogger CreateLogger(string categoryName)
{
return new TranslatingSerilogLogger(categoryName, _translationService);
}

public void Dispose()
{
}

private sealed class TranslatingSerilogLogger : Microsoft.Extensions.Logging.ILogger
{
private readonly ITranslationService _translationService;
private readonly Serilog.ILogger _logger;

public TranslatingSerilogLogger(string categoryName, ITranslationService translationService)
{
_translationService = translationService;
_logger = Serilog.Log.Logger.ForContext("SourceContext", categoryName);
}

public IDisposable BeginScope<TState>(TState state) where TState : notnull
{
return NullScope.Instance;
}

public bool IsEnabled(LogLevel logLevel)
{
return logLevel != LogLevel.None;
}

public void Log<TState>(
LogLevel logLevel,
EventId eventId,
TState state,
Exception? exception,
Func<TState, Exception?, string> formatter)
{
if (!IsEnabled(logLevel))
{
return;
}

var serilogLevel = ConvertLevel(logLevel);
if (serilogLevel == null)
{
return;
}

var (template, values) = ExtractTemplateAndValues(state, formatter, exception);
var translatedTemplate = _translationService.Translate(template, TranslationSourceInfo.From(MissingTextSource.Log));

if (values.Length == 0)
{
_logger.Write(serilogLevel.Value, exception, translatedTemplate);
return;
}

_logger.Write(serilogLevel.Value, exception, translatedTemplate, values);
}

private (string Template, object?[] Values) ExtractTemplateAndValues<TState>(
TState state,
Func<TState, Exception?, string> formatter,
Exception? exception)
{
if (state is IReadOnlyList<KeyValuePair<string, object?>> kvps)
{
var original = kvps.FirstOrDefault(kv => string.Equals(kv.Key, "{OriginalFormat}", StringComparison.Ordinal));
var template = original.Value as string;
if (string.IsNullOrEmpty(template))
{
template = formatter(state, exception);
}

var values = kvps
.Where(kv =>
!string.Equals(kv.Key, "{OriginalFormat}", StringComparison.Ordinal) &&
!string.Equals(kv.Key, "EventId", StringComparison.Ordinal))
.Select(kv => kv.Value)
.ToArray();

return (template ?? string.Empty, values);
}

return (formatter(state, exception), Array.Empty<object?>());
}

private static LogEventLevel? ConvertLevel(LogLevel level)
{
return level switch
{
LogLevel.Trace => LogEventLevel.Verbose,
LogLevel.Debug => LogEventLevel.Debug,
LogLevel.Information => LogEventLevel.Information,
LogLevel.Warning => LogEventLevel.Warning,
LogLevel.Error => LogEventLevel.Error,
LogLevel.Critical => LogEventLevel.Fatal,
_ => null
};
}

private sealed class NullScope : IDisposable
{
public static NullScope Instance { get; } = new();

public void Dispose()
{
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
namespace BetterGenshinImpact.Service.Interface;

public interface IMissingTranslationReporter
{
bool TryEnqueue(string language, string key, TranslationSourceInfo sourceInfo);
}
40 changes: 40 additions & 0 deletions BetterGenshinImpact/Service/Interface/ITranslationService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
using System.Globalization;

namespace BetterGenshinImpact.Service.Interface;

public enum MissingTextSource
{
Log,
UiStaticLiteral,
UiDynamicBinding,
Unknown
}

public sealed class TranslationSourceInfo
{
public MissingTextSource Source { get; set; } = MissingTextSource.Unknown;
public string? ViewXamlPath { get; set; }
public string? ViewType { get; set; }
public string? ElementType { get; set; }
public string? ElementName { get; set; }
public string? PropertyName { get; set; }
public string? BindingPath { get; set; }
public string? Notes { get; set; }

public static TranslationSourceInfo From(MissingTextSource source)
{
return new TranslationSourceInfo
{
Source = source
};
}
}

public interface ITranslationService
{
string Translate(string text);
string Translate(string text, TranslationSourceInfo sourceInfo);
CultureInfo GetCurrentCulture();
void Reload();
}

Loading