mirror of
https://github.com/babalae/better-genshin-impact.git
synced 2026-03-15 07:43:20 +08:00
feat(ui): 添加更新UI语言文件功能
- 在 ITranslationService 接口中添加 Reload 方法 - 在 JsonTranslationService 中实现 Reload 方法,支持重新加载语言文件并发送变更通知 - 在通用设置页面添加“更新”按钮,点击后从远程仓库下载最新语言文件 - 实现 OnUpdateUiLanguageAsync 命令,支持从 GitHub 和镜像源下载语言文件 - 下载后自动替换本地文件并重新加载翻译服务
This commit is contained in:
@@ -35,5 +35,6 @@ public interface ITranslationService
|
||||
string Translate(string text);
|
||||
string Translate(string text, TranslationSourceInfo sourceInfo);
|
||||
CultureInfo GetCurrentCulture();
|
||||
void Reload();
|
||||
}
|
||||
|
||||
|
||||
@@ -58,6 +58,39 @@ public sealed class JsonTranslationService : ITranslationService, IDisposable
|
||||
}
|
||||
}
|
||||
|
||||
public void Reload()
|
||||
{
|
||||
var cultureName = _otherConfig.UiCultureInfoName ?? string.Empty;
|
||||
string previousLoaded;
|
||||
string currentLoaded;
|
||||
|
||||
lock (_sync)
|
||||
{
|
||||
previousLoaded = _loadedCultureName;
|
||||
FlushMissingIfDirty(previousLoaded);
|
||||
|
||||
if (string.IsNullOrWhiteSpace(cultureName) || IsChineseCultureName(cultureName))
|
||||
{
|
||||
_loadedCultureName = string.Empty;
|
||||
_map = new Dictionary<string, string>(StringComparer.Ordinal);
|
||||
_existingMissingKeys = new HashSet<string>(StringComparer.Ordinal);
|
||||
}
|
||||
else
|
||||
{
|
||||
_loadedCultureName = cultureName;
|
||||
_map = LoadMap(cultureName);
|
||||
_existingMissingKeys = LoadExistingMissingKeys(cultureName);
|
||||
}
|
||||
|
||||
_missingKeys.Clear();
|
||||
Interlocked.Exchange(ref _dirtyMissing, 0);
|
||||
currentLoaded = _loadedCultureName;
|
||||
}
|
||||
|
||||
WeakReferenceMessenger.Default.Send(
|
||||
new PropertyChangedMessage<object>(this, nameof(OtherConfig.UiCultureInfoName), previousLoaded, currentLoaded));
|
||||
}
|
||||
|
||||
public string Translate(string text)
|
||||
{
|
||||
return Translate(text, TranslationSourceInfo.From(MissingTextSource.Unknown));
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -32,6 +32,7 @@
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<ui:TextBlock Grid.Row="0"
|
||||
Grid.Column="0"
|
||||
@@ -43,9 +44,15 @@
|
||||
Foreground="{ui:ThemeResource TextFillColorTertiaryBrush}"
|
||||
Text="UI Language"
|
||||
TextWrapping="Wrap" />
|
||||
<ui:Button Grid.Row="0"
|
||||
Grid.RowSpan="2"
|
||||
Grid.Column="1"
|
||||
Margin="0,0,12,0"
|
||||
Command="{Binding UpdateUiLanguageCommand}"
|
||||
Content="更新" />
|
||||
<ComboBox Grid.Row="0"
|
||||
Grid.RowSpan="2"
|
||||
Grid.Column="1"
|
||||
Grid.Column="2"
|
||||
Width="200"
|
||||
Margin="0,0,36,0"
|
||||
DisplayMemberPath="Value"
|
||||
|
||||
@@ -7,6 +7,9 @@ using System.Globalization;
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using Windows.System;
|
||||
@@ -20,6 +23,7 @@ using BetterGenshinImpact.GameTask.AutoTrackPath;
|
||||
using BetterGenshinImpact.GameTask.Common.Element.Assets;
|
||||
using BetterGenshinImpact.GameTask.LogParse;
|
||||
using BetterGenshinImpact.Helpers;
|
||||
using BetterGenshinImpact.Helpers.Http;
|
||||
using BetterGenshinImpact.Model;
|
||||
using BetterGenshinImpact.Service.Interface;
|
||||
using BetterGenshinImpact.Service.Notification;
|
||||
@@ -34,6 +38,7 @@ using CommunityToolkit.Mvvm.Messaging.Messages;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Localization;
|
||||
using Microsoft.Win32;
|
||||
using Newtonsoft.Json;
|
||||
using Wpf.Ui;
|
||||
|
||||
namespace BetterGenshinImpact.ViewModel.Pages;
|
||||
@@ -89,6 +94,94 @@ public partial class CommonSettingsPageViewModel : ViewModel
|
||||
}
|
||||
);
|
||||
|
||||
[RelayCommand]
|
||||
private async Task OnUpdateUiLanguageAsync()
|
||||
{
|
||||
var cultureName = Config.OtherConfig.UiCultureInfoName ?? string.Empty;
|
||||
if (string.IsNullOrWhiteSpace(cultureName))
|
||||
{
|
||||
throw new InvalidOperationException("当前UI语言为空,无法更新语言文件。");
|
||||
}
|
||||
|
||||
if (cultureName == "zh-Hans")
|
||||
{
|
||||
await ThemedMessageBox.InformationAsync("zh-Hans 无语言文件,无需更新。");
|
||||
return;
|
||||
}
|
||||
|
||||
var urls = new[]
|
||||
{
|
||||
$"https://raw.githubusercontent.com/babalae/bettergi-i18n/refs/heads/main/i18n/{cultureName}.json",
|
||||
$"https://cnb.cool/bettergi/bettergi-i18n/-/git/raw/main/i18n/{cultureName}.json"
|
||||
};
|
||||
|
||||
using var httpClient = new HttpClient
|
||||
{
|
||||
Timeout = TimeSpan.FromSeconds(30)
|
||||
};
|
||||
|
||||
byte[]? bytes = null;
|
||||
Exception? lastError = null;
|
||||
var allNotFound = true;
|
||||
foreach (var url in urls)
|
||||
{
|
||||
try
|
||||
{
|
||||
using var request = new HttpRequestMessage(HttpMethod.Get, url);
|
||||
request.Headers.UserAgent.ParseAdd("BetterGenshinImpact");
|
||||
using var response = await httpClient.SendAsync(request);
|
||||
if (response.StatusCode == HttpStatusCode.NotFound)
|
||||
{
|
||||
lastError = new HttpRequestException("Language file not found.", null, response.StatusCode);
|
||||
continue;
|
||||
}
|
||||
|
||||
allNotFound = false;
|
||||
response.EnsureSuccessStatusCode();
|
||||
bytes = await response.Content.ReadAsByteArrayAsync();
|
||||
|
||||
var json = Encoding.UTF8.GetString(bytes);
|
||||
_ = JsonConvert.DeserializeObject<Dictionary<string, string>>(json)
|
||||
?? throw new JsonException("翻译文件不是有效的 JSON 字典。");
|
||||
break;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
lastError = e;
|
||||
allNotFound = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (bytes == null)
|
||||
{
|
||||
if (allNotFound)
|
||||
{
|
||||
await ThemedMessageBox.WarningAsync($"语言文件不存在:{cultureName}.json");
|
||||
return;
|
||||
}
|
||||
|
||||
throw new Exception($"下载语言文件失败:{cultureName}.json", lastError);
|
||||
}
|
||||
|
||||
var dir = Global.Absolute(@"User\I18n");
|
||||
Directory.CreateDirectory(dir);
|
||||
var path = Path.Combine(dir, $"{cultureName}.json");
|
||||
var tmp = $"{path}.{Guid.NewGuid():N}.tmp";
|
||||
await File.WriteAllBytesAsync(tmp, bytes);
|
||||
|
||||
if (File.Exists(path))
|
||||
{
|
||||
File.Replace(tmp, path, null);
|
||||
}
|
||||
else
|
||||
{
|
||||
File.Move(tmp, path);
|
||||
}
|
||||
|
||||
var translator = App.GetService<ITranslationService>() ?? throw new NullReferenceException();
|
||||
translator.Reload();
|
||||
}
|
||||
|
||||
public string SelectedCountry
|
||||
{
|
||||
get => _selectedCountry;
|
||||
|
||||
Reference in New Issue
Block a user