From aff501e231701a252f6b86c9b7d53b33a5ed2c78 Mon Sep 17 00:00:00 2001 From: Scott Hanselman Date: Tue, 17 Mar 2026 20:20:18 -0700 Subject: [PATCH 1/4] feat: complete Chinese localization for all remaining strings Localize ~40 remaining hardcoded English strings across: - Toast notifications (device, session, node, health, camera, activity) - CanvasWindow (error, retry, ready state) - WebChatWindow (error messages, unavailable state) - DownloadProgressDialog (title, progress text) - TrayMenuWindow title Both en-US and zh-CN resource files now have 163 keys (up from 125), fully in sync. Adds PrimaryLanguageOverride for local zh-CN testing. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/OpenClaw.Tray.WinUI/App.xaml.cs | 45 ++--- .../Dialogs/DownloadProgressDialog.cs | 5 +- .../Services/NodeService.cs | 9 +- .../Strings/en-us/Resources.resw | 161 ++++++++++++++++++ .../Strings/zh-cn/Resources.resw | 161 ++++++++++++++++++ .../Windows/CanvasWindow.xaml | 4 +- .../Windows/CanvasWindow.xaml.cs | 17 +- .../Windows/WebChatWindow.xaml | 4 +- .../Windows/WebChatWindow.xaml.cs | 25 +-- 9 files changed, 372 insertions(+), 59 deletions(-) diff --git a/src/OpenClaw.Tray.WinUI/App.xaml.cs b/src/OpenClaw.Tray.WinUI/App.xaml.cs index 4bd6aa8..d179861 100644 --- a/src/OpenClaw.Tray.WinUI/App.xaml.cs +++ b/src/OpenClaw.Tray.WinUI/App.xaml.cs @@ -86,6 +86,9 @@ public partial class App : Application public App() { + // Force Chinese locale for testing — remove or wrap in #if DEBUG before release + global::Windows.Globalization.ApplicationLanguages.PrimaryLanguageOverride = "zh-CN"; + InitializeComponent(); CheckPreviousRun(); @@ -569,8 +572,8 @@ private void CopyDeviceIdToClipboard() // Show toast confirming copy new ToastContentBuilder() - .AddText("📋 Device ID Copied") - .AddText($"Run: openclaw devices approve {_nodeService.ShortDeviceId}...") + .AddText(LocalizationHelper.GetString("Toast_DeviceIdCopied")) + .AddText(string.Format(LocalizationHelper.GetString("Toast_DeviceIdCopiedDetail"), _nodeService.ShortDeviceId)) .Show(); } catch (Exception ex) @@ -598,8 +601,8 @@ private void CopyNodeSummaryToClipboard() global::Windows.ApplicationModel.DataTransfer.Clipboard.SetContent(dataPackage); new ToastContentBuilder() - .AddText("📋 Node summary copied") - .AddText($"{_lastNodes.Length} node(s) copied to clipboard") + .AddText(LocalizationHelper.GetString("Toast_NodeSummaryCopied")) + .AddText(string.Format(LocalizationHelper.GetString("Toast_NodeSummaryCopiedDetail"), _lastNodes.Length)) .Show(); } catch (Exception ex) @@ -655,8 +658,8 @@ private async Task ExecuteSessionActionAsync(string action, string sessionKey, s if (!sent) { new ToastContentBuilder() - .AddText("❌ Session action failed") - .AddText("Could not send request to gateway.") + .AddText(LocalizationHelper.GetString("Toast_SessionActionFailed")) + .AddText(LocalizationHelper.GetString("Toast_SessionActionFailedDetail")) .Show(); return; } @@ -672,7 +675,7 @@ private async Task ExecuteSessionActionAsync(string action, string sessionKey, s try { new ToastContentBuilder() - .AddText("❌ Session action failed") + .AddText(LocalizationHelper.GetString("Toast_SessionActionFailed")) .AddText(ex.Message) .Show(); } @@ -1158,8 +1161,8 @@ private void OnNodeStatusChanged(object? sender, ConnectionStatus status) try { new ToastContentBuilder() - .AddText("🔌 Node Mode Active") - .AddText("This PC can now receive commands from the agent (canvas, screenshots)") + .AddText(LocalizationHelper.GetString("Toast_NodeModeActive")) + .AddText(LocalizationHelper.GetString("Toast_NodeModeActiveDetail")) .Show(); } catch { /* ignore */ } @@ -1177,16 +1180,16 @@ private void OnPairingStatusChanged(object? sender, OpenClaw.Shared.PairingStatu AddRecentActivity("Node pairing pending", category: "node", dashboardPath: "nodes", nodeId: args.DeviceId); // Show toast with approval instructions new ToastContentBuilder() - .AddText("⏳ Awaiting Pairing Approval") - .AddText($"Run on gateway: openclaw devices approve {args.DeviceId.Substring(0, 16)}...") + .AddText(LocalizationHelper.GetString("Toast_PairingPending")) + .AddText(string.Format(LocalizationHelper.GetString("Toast_PairingPendingDetail"), args.DeviceId.Substring(0, 16))) .Show(); } else if (args.Status == OpenClaw.Shared.PairingStatus.Paired) { AddRecentActivity("Node paired", category: "node", dashboardPath: "nodes", nodeId: args.DeviceId); new ToastContentBuilder() - .AddText("✅ Node Paired!") - .AddText("This PC can now receive commands from the agent") + .AddText(LocalizationHelper.GetString("Toast_NodePaired")) + .AddText(LocalizationHelper.GetString("Toast_NodePairedDetail")) .Show(); } } @@ -1499,8 +1502,8 @@ private async Task RunHealthCheckAsync(bool userInitiated = false) if (userInitiated) { new ToastContentBuilder() - .AddText("Health Check") - .AddText("Gateway is not connected yet.") + .AddText(LocalizationHelper.GetString("Toast_HealthCheck")) + .AddText(LocalizationHelper.GetString("Toast_HealthCheckNotConnected")) .Show(); } return; @@ -1513,8 +1516,8 @@ private async Task RunHealthCheckAsync(bool userInitiated = false) if (userInitiated) { new ToastContentBuilder() - .AddText("Health Check") - .AddText("Health check request sent.") + .AddText(LocalizationHelper.GetString("Toast_HealthCheck")) + .AddText(LocalizationHelper.GetString("Toast_HealthCheckSent")) .Show(); } } @@ -1524,7 +1527,7 @@ private async Task RunHealthCheckAsync(bool userInitiated = false) if (userInitiated) { new ToastContentBuilder() - .AddText("Health Check Failed") + .AddText(LocalizationHelper.GetString("Toast_HealthCheckFailed")) .AddText(ex.Message) .Show(); } @@ -1744,10 +1747,10 @@ private void ShowSurfaceImprovementsTipIfNeeded() try { new ToastContentBuilder() - .AddText("⚡ New: Activity Stream") - .AddText("Open the tray menu to view live sessions, usage, and node activity in one flyout.") + .AddText(LocalizationHelper.GetString("Toast_ActivityStreamTip")) + .AddText(LocalizationHelper.GetString("Toast_ActivityStreamTipDetail")) .AddButton(new ToastButton() - .SetContent("Open Activity Stream") + .SetContent(LocalizationHelper.GetString("Toast_ActivityStreamTipButton")) .AddArgument("action", "open_activity")) .Show(); } diff --git a/src/OpenClaw.Tray.WinUI/Dialogs/DownloadProgressDialog.cs b/src/OpenClaw.Tray.WinUI/Dialogs/DownloadProgressDialog.cs index 501d5a3..c66b2e4 100644 --- a/src/OpenClaw.Tray.WinUI/Dialogs/DownloadProgressDialog.cs +++ b/src/OpenClaw.Tray.WinUI/Dialogs/DownloadProgressDialog.cs @@ -1,6 +1,7 @@ using Microsoft.UI.Xaml; using Microsoft.UI.Xaml.Controls; using Microsoft.UI.Xaml.Media; +using OpenClawTray.Helpers; using Updatum; namespace OpenClawTray.Dialogs; @@ -17,11 +18,11 @@ public DownloadProgressDialog(UpdatumManager updater) public void ShowAsync() { - _window = new Window { Title = "Downloading Update..." }; + _window = new Window { Title = LocalizationHelper.GetString("WindowTitle_Downloading") }; _window.SystemBackdrop = new MicaBackdrop(); var panel = new StackPanel { Padding = new Thickness(20) }; - var progressText = new TextBlock { Text = "Downloading update...", Margin = new Thickness(0, 0, 0, 10) }; + var progressText = new TextBlock { Text = LocalizationHelper.GetString("Download_ProgressText"), Margin = new Thickness(0, 0, 0, 10) }; var progressBar = new ProgressBar { IsIndeterminate = true }; panel.Children.Add(progressText); diff --git a/src/OpenClaw.Tray.WinUI/Services/NodeService.cs b/src/OpenClaw.Tray.WinUI/Services/NodeService.cs index 851fe42..b7b5408 100644 --- a/src/OpenClaw.Tray.WinUI/Services/NodeService.cs +++ b/src/OpenClaw.Tray.WinUI/Services/NodeService.cs @@ -4,6 +4,7 @@ using Microsoft.UI.Dispatching; using OpenClaw.Shared; using OpenClaw.Shared.Capabilities; +using OpenClawTray.Helpers; using OpenClawTray.Windows; using Microsoft.UI.Xaml; @@ -417,8 +418,8 @@ private async Task OnScreenCapture(ScreenCaptureArgs args) try { new ToastContentBuilder() - .AddText("📸 Screen Captured") - .AddText("OpenClaw agent captured your screen") + .AddText(LocalizationHelper.GetString("Toast_ScreenCaptured")) + .AddText(LocalizationHelper.GetString("Toast_ScreenCapturedDetail")) .Show(); } catch { /* ignore notification errors */ } @@ -457,8 +458,8 @@ private async Task OnCameraSnap(CameraSnapArgs args) try { new ToastContentBuilder() - .AddText("📷 Camera access blocked") - .AddText("Enable camera access in Windows Privacy settings for OpenClaw Tray") + .AddText(LocalizationHelper.GetString("Toast_CameraBlocked")) + .AddText(LocalizationHelper.GetString("Toast_CameraBlockedDetail")) .Show(); } catch { } diff --git a/src/OpenClaw.Tray.WinUI/Strings/en-us/Resources.resw b/src/OpenClaw.Tray.WinUI/Strings/en-us/Resources.resw index a219e8b..881da12 100644 --- a/src/OpenClaw.Tray.WinUI/Strings/en-us/Resources.resw +++ b/src/OpenClaw.Tray.WinUI/Strings/en-us/Resources.resw @@ -466,4 +466,165 @@ n/a + + + + Canvas + + + ❌ Canvas Error + + + Retry + + + 🎨 Canvas Ready + + + Waiting for content... + + + + + + Web Chat Unavailable + + + Open in Browser Instead + + + Can't reach OpenClaw Gateway + + + The gateway at {0} is not responding. + +To connect: +• Make sure your OpenClaw gateway is running +• If remote, connect via VPN to your home network +• Or use SSH tunnel: ssh -N -L 18789:localhost:18789 your-server + + + The gateway HTTPS certificate is not trusted. + +To connect securely: +• Use an HTTPS gateway URL (for example: https://host.tailnet.ts.net) +• If self-signed, import the cert into Windows Trusted Root Certification Authorities +• Or use SSH tunnel to localhost and keep using localhost URLs + + + Invalid gateway URL: {0} + + + Web chat requires a secure context. + +There is no safe bypass for remote plain HTTP: browsers and WebView enforce this. + +Use one of these options: +• Use a trusted HTTPS/WSS endpoint (Let's Encrypt, Tailscale Serve, Caddy) +• If self-signed, import your gateway CA/cert into Windows Trusted Root (certmgr.msc) +• Or tunnel to localhost: ssh -N -L 18789:localhost:18789 <server> + + + + + + OpenClaw Menu + + + + + + 📋 Device ID Copied + + + Run: openclaw devices approve {0}... + + + 📋 Node summary copied + + + {0} node(s) copied to clipboard + + + + + + ❌ Session action failed + + + Could not send request to gateway. + + + + + + 🔌 Node Mode Active + + + This PC can now receive commands from the agent (canvas, screenshots) + + + ⏳ Awaiting Pairing Approval + + + Run on gateway: openclaw devices approve {0}... + + + ✅ Node Paired! + + + This PC can now receive commands from the agent + + + + + + Health Check + + + Gateway is not connected yet. + + + Health check request sent. + + + Health Check Failed + + + + + + 📸 Screen Captured + + + OpenClaw agent captured your screen + + + 📷 Camera access blocked + + + Enable camera access in Windows Privacy settings for OpenClaw Tray + + + + + + ⚡ New: Activity Stream + + + Open the tray menu to view live sessions, usage, and node activity in one flyout. + + + Open Activity Stream + + + + + + Downloading Update... + + + Downloading update... + + diff --git a/src/OpenClaw.Tray.WinUI/Strings/zh-cn/Resources.resw b/src/OpenClaw.Tray.WinUI/Strings/zh-cn/Resources.resw index 4053744..5da2f3f 100644 --- a/src/OpenClaw.Tray.WinUI/Strings/zh-cn/Resources.resw +++ b/src/OpenClaw.Tray.WinUI/Strings/zh-cn/Resources.resw @@ -466,4 +466,165 @@ + + + + 画布 + + + ❌ 画布错误 + + + 重试 + + + 🎨 画布就绪 + + + 等待内容... + + + + + + 网页聊天不可用 + + + 在浏览器中打开 + + + 无法连接到 OpenClaw 网关 + + + 网关 {0} 没有响应。 + +连接方法: +• 确保 OpenClaw 网关正在运行 +• 如果是远程网关,请通过 VPN 连接到您的家庭网络 +• 或使用 SSH 隧道:ssh -N -L 18789:localhost:18789 your-server + + + 网关 HTTPS 证书不受信任。 + +安全连接方法: +• 使用 HTTPS 网关地址(例如:https://host.tailnet.ts.net) +• 如果是自签名证书,请将其导入 Windows 受信任的根证书颁发机构 +• 或使用 SSH 隧道连接到 localhost 并继续使用 localhost 地址 + + + 无效的网关地址: {0} + + + 网页聊天需要安全上下文。 + +远程纯 HTTP 没有安全的绕过方法:浏览器和 WebView 强制执行此限制。 + +请使用以下选项之一: +• 使用受信任的 HTTPS/WSS 端点(Let's Encrypt、Tailscale Serve、Caddy) +• 如果是自签名证书,请将网关 CA/证书导入 Windows 受信任的根证书(certmgr.msc) +• 或通过隧道连接到 localhost:ssh -N -L 18789:localhost:18789 <服务器> + + + + + + OpenClaw 菜单 + + + + + + 📋 设备 ID 已复制 + + + 运行: openclaw devices approve {0}... + + + 📋 节点摘要已复制 + + + 已复制 {0} 个节点到剪贴板 + + + + + + ❌ 会话操作失败 + + + 无法向网关发送请求。 + + + + + + 🔌 节点模式已激活 + + + 此电脑现在可以接收来自代理的命令(画布、截图) + + + ⏳ 等待配对批准 + + + 在网关上运行: openclaw devices approve {0}... + + + ✅ 节点已配对! + + + 此电脑现在可以接收来自代理的命令 + + + + + + 健康检查 + + + 网关尚未连接。 + + + 健康检查请求已发送。 + + + 健康检查失败 + + + + + + 📸 屏幕已捕获 + + + OpenClaw 代理捕获了您的屏幕 + + + 📷 相机访问被阻止 + + + 请在 Windows 隐私设置中为 OpenClaw Tray 启用相机访问 + + + + + + ⚡ 新功能: 活动流 + + + 打开托盘菜单即可查看实时会话、用量和节点活动。 + + + 打开活动流 + + + + + + 正在下载更新... + + + 正在下载更新... + + diff --git a/src/OpenClaw.Tray.WinUI/Windows/CanvasWindow.xaml b/src/OpenClaw.Tray.WinUI/Windows/CanvasWindow.xaml index c27fc25..4daa2d8 100644 --- a/src/OpenClaw.Tray.WinUI/Windows/CanvasWindow.xaml +++ b/src/OpenClaw.Tray.WinUI/Windows/CanvasWindow.xaml @@ -31,7 +31,7 @@ VerticalAlignment="Center" Spacing="16" Padding="32"> - @@ -40,7 +40,7 @@ MaxWidth="400" HorizontalAlignment="Center" Foreground="{ThemeResource TextFillColorSecondaryBrush}"/> -