Files
better-genshin-impact/BetterGenshinImpact/View/MainWindow.xaml
辉鸭蛋 9f67726781 I18n v2 (#2709)
* feat(i18n): 添加界面与日志的国际化支持

- 新增 ITranslationService 接口及 JsonTranslationService 实现,提供基于 JSON 的翻译服务
- 添加 TrConverter 转换器,支持通过绑定动态翻译界面文本
- 引入 AutoTranslateInterceptor 行为,自动扫描并翻译界面中的静态文本
- 集成 TranslatingSerilogLoggerProvider,实现日志输出的实时翻译
- 在 App.xaml 中注册全局样式,为 Window、UserControl 和 Page 启用自动翻译

* refactor(AutoTranslateInterceptor): 优化自动翻译拦截器的加载与应用机制

- 移除 HomePage 中冗余的 EnableAutoTranslate 属性设置,改为继承属性
- 通过类构造函数注册全局 Loaded 事件处理器,替代在每个元素上单独添加
- 引入请求队列机制,批量处理待应用翻译的元素,避免重复调度
- 扩展属性类型检查,支持 object 类型以处理更多动态内容场景

* fix: 移除全局自动翻译拦截器以避免冲突

移除在 App.xaml 中为 Window、UserControl 和 Page 全局设置的 AutoTranslateInterceptor,
改为仅在 PickerWindow 中显式启用。这解决了全局样式可能导致的意外行为或冲突。

* feat(ui): 为多个窗口启用自动翻译拦截器

为 MapLabelSearchWindow、ArtifactOcrDialog、PromptDialog 等 14 个窗口添加了 AutoTranslateInterceptor.EnableAutoTranslate 属性,以启用自动翻译拦截功能。

* feat(i18n): 添加国际化目录支持并优化异常处理

* feat(ui): 添加软件UI语言设置并改进翻译服务

- 在通用设置页面新增UI语言选择控件,支持动态切换界面语言
- 修改游戏语言标签为“原神游戏语言”以明确区分
- 改进JsonTranslationService,支持UI语言切换时的实时翻译更新
- 优化AutoTranslateInterceptor,缓存原始文本值并在语言切换时恢复
- 添加属性变更监听机制,确保UI元素在语言切换后正确刷新

* feat(自动翻译): 添加排除自动翻译的依赖属性

在 AutoTranslateInterceptor 中新增 ExcludeAutoTranslate 附加属性,允许对特定依赖对象禁用自动翻译功能。当遍历元素进行翻译时,会检查此属性并跳过已标记排除的元素。

* feat(translation): 为缺失文本翻译添加详细上下文信息

扩展翻译服务以收集缺失文本的详细上下文,包括视图路径、元素类型、属性名等。
重构 `ITranslationService` 接口,引入 `TranslationSourceInfo` 类封装上下文信息。
修改 `AutoTranslateInterceptor` 自动收集 UI 元素信息,`JsonTranslationService` 合并多来源上下文。

* Revert "feat(自动翻译): 添加排除自动翻译的依赖属性"

This reverts commit a1c2334951.

* fix: 跳过 GridViewRowPresenter 中的文本翻译

添加 IsInGridViewRowPresenter 检查,避免在 GridViewRowPresenter 控件内进行自动翻译,防止潜在的界面显示问题。

* fix: 修复自动翻译拦截器在组合框上下文中的误触发

在自动翻译拦截器中添加了 IsInComboBoxContext 方法,用于检测依赖对象是否处于 ComboBox 或其相关弹出菜单的上下文中。当检测到对象位于组合框上下文时,跳过自动翻译逻辑,避免对下拉选项等界面元素进行不必要的翻译操作,从而解决潜在的界面干扰问题。

* feat(translation): 添加缺失翻译上报至 Supabase 的功能

- 新增 IMissingTranslationReporter 接口及 SupabaseMissingTranslationReporter 实现
- 在 JsonTranslationService 中集成缺失翻译上报逻辑
- 添加缺失翻译收集的配置设置(MissingTranslationCollectionSettings)
- 优化缺失翻译文件的序列化格式,将 Source 字段改为紧凑的数字表示
- 移除 ScriptRepoUpdater 中未使用的 using 语句
- 在 App.xaml.cs 中注册 SupabaseMissingTranslationReporter 服务

* fix: 修复自动翻译功能中原始值恢复和重复报告问题

- 移除未使用的法语翻译支持以简化语言选项
- 修复 Supabase 报告序列化时移除冗余字段
- 添加已缺失翻译键的缓存以避免重复报告
- 重构自动翻译拦截器,将原始值存储移至依赖属性
- 修复原始值恢复逻辑,确保正确遍历所有子元素

* feat(ui): 添加更新UI语言文件功能

- 在 ITranslationService 接口中添加 Reload 方法
- 在 JsonTranslationService 中实现 Reload 方法,支持重新加载语言文件并发送变更通知
- 在通用设置页面添加“更新”按钮,点击后从远程仓库下载最新语言文件
- 实现 OnUpdateUiLanguageAsync 命令,支持从 GitHub 和镜像源下载语言文件
- 下载后自动替换本地文件并重新加载翻译服务
2026-02-15 19:03:33 +08:00

243 lines
13 KiB
XML

<ui:FluentWindow x:Class="BetterGenshinImpact.View.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:b="http://schemas.microsoft.com/xaml/behaviors"
xmlns:behavior="clr-namespace:BetterGenshinImpact.View.Behavior"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:markup="clr-namespace:BetterGenshinImpact.Markup"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:pages="clr-namespace:BetterGenshinImpact.View.Pages"
xmlns:tray="http://schemas.lepo.co/wpfui/2022/xaml/tray"
xmlns:ui="http://schemas.lepo.co/wpfui/2022/xaml"
xmlns:viewModel="clr-namespace:BetterGenshinImpact.ViewModel"
Title="更好的原神"
Width="900"
Height="600"
d:Background="#D2D2D2"
d:DataContext="{d:DesignInstance Type=viewModel:MainWindowViewModel}"
ui:Design.Background="{DynamicResource ApplicationBackgroundBrush}"
ui:Design.Foreground="{DynamicResource TextFillColorPrimaryBrush}"
ExtendsContentIntoTitleBar="True"
behavior:AutoTranslateInterceptor.EnableAutoTranslate="True"
FontFamily="{StaticResource TextThemeFontFamily}"
Visibility="{Binding IsVisible, Mode=TwoWay, Converter={StaticResource BooleanToVisibilityConverter}}"
WindowBackdropType="Auto"
WindowStartupLocation="CenterScreen"
WindowState="{Binding WindowState, Mode=TwoWay}"
mc:Ignorable="d">
<Window.Resources>
<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" />
</Window.Resources>
<b:Interaction.Triggers>
<b:EventTrigger EventName="Activated">
<b:InvokeCommandAction Command="{Binding ActivatedCommand}" />
</b:EventTrigger>
<b:EventTrigger EventName="Loaded">
<b:InvokeCommandAction Command="{Binding LoadedCommand}" CommandParameter="{Binding}" />
</b:EventTrigger>
<b:EventTrigger EventName="Closing">
<b:InvokeCommandAction Command="{Binding ClosingCommand}" PassEventArgsToCommand="True" />
</b:EventTrigger>
</b:Interaction.Triggers>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<ui:NavigationView x:Name="RootNavigation"
Grid.Column="0"
Grid.Row="1"
Margin="0,0,0,5"
IsBackButtonVisible="Collapsed"
IsPaneToggleVisible="True"
IsTopSeparatorVisible="False"
IsFooterSeparatorVisible="False"
OpenPaneLength="160">
<ui:NavigationView.MenuItems>
<ui:NavigationViewItem Content="启动"
NavigationCacheMode="Enabled"
TargetPageType="{x:Type pages:HomePage}">
<ui:NavigationViewItem.Icon>
<ui:SymbolIcon Symbol="Play24" />
</ui:NavigationViewItem.Icon>
</ui:NavigationViewItem>
<ui:NavigationViewItem Content="实时触发"
NavigationCacheMode="Enabled"
TargetPageType="{x:Type pages:TriggerSettingsPage}">
<ui:NavigationViewItem.Icon>
<ui:SymbolIcon Symbol="Timer24" />
</ui:NavigationViewItem.Icon>
</ui:NavigationViewItem>
<ui:NavigationViewItem Content="独立任务"
NavigationCacheMode="Enabled"
TargetPageType="{x:Type pages:TaskSettingsPage}">
<ui:NavigationViewItem.Icon>
<ui:SymbolIcon Symbol="TaskListSquareLtr24" />
</ui:NavigationViewItem.Icon>
</ui:NavigationViewItem>
<!--<ui:NavigationViewItemSeparator />-->
<ui:NavigationViewItem Content="一条龙"
NavigationCacheMode="Enabled"
TargetPageType="{x:Type pages:OneDragonFlowPage}">
<ui:NavigationViewItem.Icon>
<ui:SymbolIcon Symbol="AnimalTurtle24" />
</ui:NavigationViewItem.Icon>
</ui:NavigationViewItem>
<ui:NavigationViewItem Content="全自动">
<ui:NavigationViewItem.Icon>
<ui:SymbolIcon Symbol="Bot24" />
</ui:NavigationViewItem.Icon>
<ui:NavigationViewItem.MenuItems>
<!--<ui:NavigationViewItemSeparator />-->
<!-- ConvertRange20 -->
<ui:NavigationViewItem Content="调度器"
NavigationCacheMode="Enabled"
TargetPageType="{x:Type pages:ScriptControlPage}">
<ui:NavigationViewItem.Icon>
<ui:SymbolIcon Symbol="DeveloperBoard24" />
</ui:NavigationViewItem.Icon>
</ui:NavigationViewItem>
<!-- WebAsset24 | DocumentJs16 | Script16 -->
<ui:NavigationViewItem Content="JS 脚本"
NavigationCacheMode="Enabled"
TargetPageType="{x:Type pages:JsListPage}">
<ui:NavigationViewItem.Icon>
<ui:SymbolIcon Symbol="DocumentJs16" />
</ui:NavigationViewItem.Icon>
</ui:NavigationViewItem>
<!-- Map24 -->
<ui:NavigationViewItem Content="地图追踪"
NavigationCacheMode="Enabled"
TargetPageType="{x:Type pages:MapPathingPage}">
<ui:NavigationViewItem.Icon>
<ui:SymbolIcon Symbol="Map24" />
</ui:NavigationViewItem.Icon>
</ui:NavigationViewItem>
<!-- Script16 -->
<ui:NavigationViewItem Content="录制回放"
NavigationCacheMode="Enabled"
TargetPageType="{x:Type pages:KeyMouseRecordPage}">
<ui:NavigationViewItem.Icon>
<ui:SymbolIcon Symbol="Record24" />
</ui:NavigationViewItem.Icon>
</ui:NavigationViewItem>
</ui:NavigationViewItem.MenuItems>
</ui:NavigationViewItem>
<ui:NavigationViewItem Content="辅助操控"
NavigationCacheMode="Enabled"
TargetPageType="{x:Type pages:MacroSettingsPage}">
<ui:NavigationViewItem.Icon>
<ui:SymbolIcon Symbol="XboxController24" />
</ui:NavigationViewItem.Icon>
</ui:NavigationViewItem>
<ui:NavigationViewItem Content="快捷键"
NavigationCacheMode="Enabled"
TargetPageType="{x:Type pages:HotKeyPage}">
<ui:NavigationViewItem.Icon>
<ui:SymbolIcon Symbol="Flash24" />
</ui:NavigationViewItem.Icon>
</ui:NavigationViewItem>
<!--<ui:NavigationViewItem Content="按键绑定"
NavigationCacheMode="Enabled"
TargetPageType="{x:Type pages:KeyBindingsSettingsPage}" Cursor="Hand">
<ui:NavigationViewItem.Icon>
<ui:SymbolIcon Symbol="KeyboardMouse16" />
</ui:NavigationViewItem.Icon>
</ui:NavigationViewItem>-->
<ui:NavigationViewItem Content="通知"
NavigationCacheMode="Enabled"
TargetPageType="{x:Type pages:NotificationSettingsPage}">
<ui:NavigationViewItem.Icon>
<ui:SymbolIcon Symbol="Alert24" />
</ui:NavigationViewItem.Icon>
</ui:NavigationViewItem>
</ui:NavigationView.MenuItems>
<ui:NavigationView.FooterMenuItems>
<ui:NavigationViewItem Content="设置"
NavigationCacheMode="Enabled"
TargetPageType="{x:Type pages:CommonSettingsPage}">
<ui:NavigationViewItem.Icon>
<ui:SymbolIcon Symbol="Settings24" />
</ui:NavigationViewItem.Icon>
</ui:NavigationViewItem>
</ui:NavigationView.FooterMenuItems>
<ui:NavigationView.ContentOverlay>
<Grid>
<ui:SnackbarPresenter x:Name="SnackbarPresenter" />
</Grid>
</ui:NavigationView.ContentOverlay>
</ui:NavigationView>
<ui:TitleBar Title="{Binding Title, Mode=OneWay}" Grid.Row="0" Grid.Column="0">
<ui:TitleBar.Icon>
<ui:ImageIcon Source="pack://application:,,,/Resources/Images/logo.png" />
</ui:TitleBar.Icon>
<ui:TitleBar.TrailingContent>
<StackPanel VerticalAlignment="Top" Orientation="Horizontal">
<ui:Button Width="40"
Height="32"
Background="Transparent"
BorderBrush="Transparent"
Command="{Binding OpenFeedCommand}"
CornerRadius="0"
Icon="{ui:SymbolIcon Gift16}"
Foreground="{Binding RedeemCodeButtonForeground}"
ToolTip="获取兑换码信息" />
<ui:Button Width="40"
Height="32"
Background="Transparent"
BorderBrush="Transparent"
Command="{Binding SwitchBackdropCommand}"
CornerRadius="0"
Icon="{ui:SymbolIcon Blur24}"
ToolTip="切换深浅主题或背景样式" />
<ui:Button Width="32"
Height="32"
Background="Transparent"
BorderBrush="Transparent"
Command="{Binding HideCommand}"
CornerRadius="0"
Icon="{ui:SymbolIcon CaretDown24}"
ToolTip="最小化到托盘" />
</StackPanel>
</ui:TitleBar.TrailingContent>
</ui:TitleBar>
<tray:NotifyIcon Grid.Row="0" Grid.Column="0"
FocusOnLeftClick="False"
Icon="pack://application:,,,/Resources/Images/logo.ico"
LeftDoubleClick="OnNotifyIconLeftDoubleClick"
MenuOnRightClick="True"
TooltipText="BetterGI">
<tray:NotifyIcon.Menu>
<ContextMenu>
<ContextMenu.DataContext>
<markup:ServiceLocator Type="{x:Type viewModel:NotifyIconViewModel}" />
</ContextMenu.DataContext>
<ui:MenuItem Command="{Binding CheckUpdateCommand}"
Header="检查更新"
Icon="{ui:SymbolIcon ArrowAutofitUp24}" />
<Separator />
<ui:MenuItem Command="{Binding ExitCommand}"
Header="退出"
Icon="{ui:SymbolIcon Dismiss24}" />
</ContextMenu>
</tray:NotifyIcon.Menu>
</tray:NotifyIcon>
</Grid>
</ui:FluentWindow>