diff --git a/wpf/QuotaFloat.Wpf.csproj b/wpf/QuotaFloat.Wpf.csproj
index 450f72a..c25af3a 100644
--- a/wpf/QuotaFloat.Wpf.csproj
+++ b/wpf/QuotaFloat.Wpf.csproj
@@ -8,10 +8,10 @@
QuotaFloat.Wpf
QuotaFloat.Wpf
Assets\QuoteFloat.ico
- 1.1.1
- 1.1.1.0
- 1.1.1.0
- 1.1.1
+ 1.1.2
+ 1.1.2.0
+ 1.1.2.0
+ 1.1.2
app.manifest
embedded
true
diff --git a/wpf/Resources/UiText.cs b/wpf/Resources/UiText.cs
index 7924c29..a353f19 100644
--- a/wpf/Resources/UiText.cs
+++ b/wpf/Resources/UiText.cs
@@ -15,6 +15,8 @@ public sealed record WidgetText(
string Synced,
string Refresh,
string Settings,
+ string TrayOpenSettings,
+ string TrayExit,
string SyncAutomationName,
string RefreshAutomationName,
string SettingsAutomationName,
@@ -47,6 +49,8 @@ public static WidgetText For(string language) => string.Equals(language, "en-US"
Synced: "已同步",
Refresh: "刷新",
Settings: "设置",
+ TrayOpenSettings: "打开设置",
+ TrayExit: "退出 Quote Float",
SyncAutomationName: "已同步",
RefreshAutomationName: "刷新",
SettingsAutomationName: "设置",
@@ -75,6 +79,8 @@ public static WidgetText For(string language) => string.Equals(language, "en-US"
Synced: "Synced",
Refresh: "Refresh",
Settings: "Settings",
+ TrayOpenSettings: "Open Settings",
+ TrayExit: "Exit Quote Float",
SyncAutomationName: "Synced",
RefreshAutomationName: "Refresh",
SettingsAutomationName: "Settings",
diff --git a/wpf/Services/TrayIconService.cs b/wpf/Services/TrayIconService.cs
index 3d86b56..90c8501 100644
--- a/wpf/Services/TrayIconService.cs
+++ b/wpf/Services/TrayIconService.cs
@@ -2,6 +2,7 @@
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Interop;
+using QuotaFloat.Wpf.Resources;
namespace QuotaFloat.Wpf.Services;
@@ -28,16 +29,18 @@ public sealed class TrayIconService : IDisposable
private readonly Action openSettings;
private readonly Action exitApplication;
+ private readonly Func textProvider;
private readonly HwndSource hwndSource;
private readonly uint iconId = 0x5146;
private IntPtr productIcon;
private bool disposed;
private bool iconAdded;
- public TrayIconService(Window owner, Action openSettings, Action exitApplication)
+ public TrayIconService(Window owner, Action openSettings, Action exitApplication, Func textProvider)
{
this.openSettings = openSettings;
this.exitApplication = exitApplication;
+ this.textProvider = textProvider;
var hwnd = new WindowInteropHelper(owner).Handle;
hwndSource = HwndSource.FromHwnd(hwnd)
@@ -153,8 +156,9 @@ private void ShowContextMenu(IntPtr hwnd)
try
{
- AppendMenu(menu, MfString | MfEnabled, OpenSettingsCommandId, "打开设置");
- AppendMenu(menu, MfString | MfEnabled, ExitCommandId, "退出 Quote Float");
+ var text = textProvider();
+ AppendMenu(menu, MfString | MfEnabled, OpenSettingsCommandId, text.TrayOpenSettings);
+ AppendMenu(menu, MfString | MfEnabled, ExitCommandId, text.TrayExit);
SetForegroundWindow(hwnd);
if (!GetCursorPos(out var point))
{
diff --git a/wpf/Windows/MainWindow.xaml.cs b/wpf/Windows/MainWindow.xaml.cs
index 15da08d..685481d 100644
--- a/wpf/Windows/MainWindow.xaml.cs
+++ b/wpf/Windows/MainWindow.xaml.cs
@@ -84,7 +84,8 @@ private void MainWindow_OnSourceInitialized(object? sender, EventArgs e)
var hwnd = new WindowInteropHelper(this).Handle;
hwndSource = HwndSource.FromHwnd(hwnd);
hwndSource?.AddHook(MainWindowWndProc);
- trayIconService = new TrayIconService(this, ShowSettings, ExitApplication);
+ trayIconService = new TrayIconService(this, ShowSettings, ExitApplication,
+ () => WidgetText.For(preferenceStore.Current.Language));
widgetController.ApplyState(widgetController.State);
}
diff --git a/wpf/app.manifest b/wpf/app.manifest
index 11a20cd..cb514aa 100644
--- a/wpf/app.manifest
+++ b/wpf/app.manifest
@@ -1,6 +1,6 @@
-
+
diff --git a/wpf/tests/Program.cs b/wpf/tests/Program.cs
index 36a1711..6cbc580 100644
--- a/wpf/tests/Program.cs
+++ b/wpf/tests/Program.cs
@@ -45,6 +45,16 @@ void Check(bool condition, string label)
Check(QuotaDisplayState.LoadingState.Status == QuotaUiStatus.Loading && QuotaDisplayState.LoadingState.ActiveRequests == 1, "loading state is explicit");
Check(WidgetText.For("en-US").Status(QuotaUiStatus.Stale, true) == "Refreshing" && WidgetText.For("zh-Hans").Status(QuotaUiStatus.Stale, true) == "刷新中", "refreshing copy is localized");
+var trayLanguage = "zh-Hans";
+Func trayText = () => WidgetText.For(trayLanguage);
+Check(trayText().TrayOpenSettings == "打开设置" && trayText().TrayExit == "退出 Quote Float",
+ "Chinese tray labels are exact");
+trayLanguage = "en-US";
+Check(trayText().TrayOpenSettings == "Open Settings" && trayText().TrayExit == "Exit Quote Float",
+ "English tray labels are exact");
+trayLanguage = "zh-Hans";
+Check(trayText().TrayOpenSettings == "打开设置" && trayText().TrayExit == "退出 Quote Float",
+ "tray labels refresh dynamically from current language");
var refreshingSnapshot = new QuotaSnapshot("Plus", new QuotaWindow(72, DateTimeOffset.UtcNow.AddHours(1), 18000, "5h"), new QuotaWindow(38, DateTimeOffset.UtcNow.AddDays(2), 604800, "Weekly"), 2, Array.Empty(), DateTimeOffset.UtcNow);
using var refreshingSource = new GateAfterFirstSource(refreshingSnapshot);
@@ -292,7 +302,7 @@ void Check(bool condition, string label)
}
Console.WriteLine("PASS: QF-WPF-009 focused fixtures and orchestration checks");
-Console.WriteLine($"RESULTS: fixtures=35; checks={checkCount}; activeRequests={source.MaxActive}; refreshCalls={source.CallCount}; backoffCalls={backoffSource.CallCount}; privacy=normalized-values-only");
+Console.WriteLine($"RESULTS: fixtures=36; checks={checkCount}; activeRequests={source.MaxActive}; refreshCalls={source.CallCount}; backoffCalls={backoffSource.CallCount}; privacy=normalized-values-only");
return 0;
sealed class ManualTimeProvider : TimeProvider