diff --git a/src/OpenClaw.Tray.WinUI/App.xaml.cs b/src/OpenClaw.Tray.WinUI/App.xaml.cs index 8e29154e..bfbe0158 100644 --- a/src/OpenClaw.Tray.WinUI/App.xaml.cs +++ b/src/OpenClaw.Tray.WinUI/App.xaml.cs @@ -216,6 +216,12 @@ public App() Logger.Warn($"[App] Ignoring invalid OPENCLAW_LANGUAGE value: {langOverride}"); } + // Wire the GatewayHostAccess localization indirection to LocalizationHelper. + // The classifier defaults to identity (returns the resource key as-is) for unit-test + // contexts that lack a WinUI runtime; in-app we point it at the real resource lookup. + GatewayHostAccessLocalization.GetString = LocalizationHelper.GetString; + GatewayHostAccessLocalization.Format = (key, args) => LocalizationHelper.Format(key, args); + InitializeComponent(); s_runMarker.Check(); diff --git a/src/OpenClaw.Tray.WinUI/Pages/AgentEventsPage.xaml.cs b/src/OpenClaw.Tray.WinUI/Pages/AgentEventsPage.xaml.cs index 8858c022..a6da904c 100644 --- a/src/OpenClaw.Tray.WinUI/Pages/AgentEventsPage.xaml.cs +++ b/src/OpenClaw.Tray.WinUI/Pages/AgentEventsPage.xaml.cs @@ -96,7 +96,7 @@ private void UpdateLiveBadge() { LiveDot.Fill = new Microsoft.UI.Xaml.Media.SolidColorBrush( Microsoft.UI.ColorHelper.FromArgb(255, 255, 68, 68)); - LiveText.Text = "Live"; + LiveText.Text = LocalizationHelper.GetString("AgentEventsPage_Status_Live"); LiveText.Foreground = new Microsoft.UI.Xaml.Media.SolidColorBrush( Microsoft.UI.ColorHelper.FromArgb(255, 255, 68, 68)); LiveBadge.Background = new Microsoft.UI.Xaml.Media.SolidColorBrush( @@ -106,7 +106,7 @@ private void UpdateLiveBadge() { LiveDot.Fill = new Microsoft.UI.Xaml.Media.SolidColorBrush( Microsoft.UI.ColorHelper.FromArgb(255, 128, 128, 128)); - LiveText.Text = "Offline"; + LiveText.Text = LocalizationHelper.GetString("AgentEventsPage_Status_Offline"); LiveText.Foreground = new Microsoft.UI.Xaml.Media.SolidColorBrush( Microsoft.UI.ColorHelper.FromArgb(255, 128, 128, 128)); LiveBadge.Background = new Microsoft.UI.Xaml.Media.SolidColorBrush( diff --git a/src/OpenClaw.Tray.WinUI/Pages/BindingsPage.xaml.cs b/src/OpenClaw.Tray.WinUI/Pages/BindingsPage.xaml.cs index 6f68d2b2..fcff127e 100644 --- a/src/OpenClaw.Tray.WinUI/Pages/BindingsPage.xaml.cs +++ b/src/OpenClaw.Tray.WinUI/Pages/BindingsPage.xaml.cs @@ -1,5 +1,6 @@ using Microsoft.UI.Xaml; using Microsoft.UI.Xaml.Controls; +using OpenClawTray.Helpers; using OpenClawTray.Services; using System; using System.Collections.Generic; @@ -153,15 +154,15 @@ private void UpdateLoadingVisuals() private void ShowDisconnected() { - ConnectionInfoBar.Title = "Gateway disconnected"; - ConnectionInfoBar.Message = "Connect to a gateway to load bindings."; + ConnectionInfoBar.Title = LocalizationHelper.GetString("BindingsPage_GatewayDisconnected.Title"); + ConnectionInfoBar.Message = LocalizationHelper.GetString("BindingsPage_GatewayDisconnected.Message"); ConnectionInfoBar.Severity = InfoBarSeverity.Warning; ConnectionInfoBar.IsOpen = true; } private void ShowLoadFailure(Exception ex) { - ConnectionInfoBar.Title = "Could not load bindings"; + ConnectionInfoBar.Title = LocalizationHelper.GetString("BindingsPage_CouldNotLoadBindings"); ConnectionInfoBar.Message = ex.Message; ConnectionInfoBar.Severity = InfoBarSeverity.Error; ConnectionInfoBar.IsOpen = true; diff --git a/src/OpenClaw.Tray.WinUI/Pages/ConfigPage.xaml.cs b/src/OpenClaw.Tray.WinUI/Pages/ConfigPage.xaml.cs index 7bfdc975..04ccd306 100644 --- a/src/OpenClaw.Tray.WinUI/Pages/ConfigPage.xaml.cs +++ b/src/OpenClaw.Tray.WinUI/Pages/ConfigPage.xaml.cs @@ -1133,20 +1133,20 @@ private void UpdatePermissionBanner() switch (GetConfigPermissionState()) { case ConfigPermissionState.Checking: - PermissionInfoBar.Title = "Checking config permissions"; + PermissionInfoBar.Title = LocalizationHelper.GetString("ConfigPage_CheckingConfigPermissions"); PermissionInfoBar.Message = "Waiting for the gateway to report this operator's permissions."; PermissionInfoBar.Severity = InfoBarSeverity.Informational; SetInfoBarOpen(PermissionInfoBar, true); break; case ConfigPermissionState.NoRead: ClearConfigViewForNoRead(); - PermissionInfoBar.Title = "Config unavailable"; + PermissionInfoBar.Title = LocalizationHelper.GetString("ConfigPage_ConfigUnavailable"); PermissionInfoBar.Message = "This operator token lacks operator.read permission, so the gateway config cannot be loaded here."; PermissionInfoBar.Severity = InfoBarSeverity.Error; SetInfoBarOpen(PermissionInfoBar, true); break; case ConfigPermissionState.ReadOnly: - PermissionInfoBar.Title = "Config is read-only"; + PermissionInfoBar.Title = LocalizationHelper.GetString("ConfigPage_ConfigIsReadOnly"); PermissionInfoBar.Message = "This operator token can read config but lacks operator.write permission. You can inspect and validate drafts, but Save is disabled."; PermissionInfoBar.Severity = InfoBarSeverity.Warning; SetInfoBarOpen(PermissionInfoBar, true); diff --git a/src/OpenClaw.Tray.WinUI/Pages/ConnectionPage.xaml.cs b/src/OpenClaw.Tray.WinUI/Pages/ConnectionPage.xaml.cs index 2cdb2590..1f7432dc 100644 --- a/src/OpenClaw.Tray.WinUI/Pages/ConnectionPage.xaml.cs +++ b/src/OpenClaw.Tray.WinUI/Pages/ConnectionPage.xaml.cs @@ -465,9 +465,9 @@ private void ApplyGatewayHostAccess(ConnectionPagePlan plan) return; } - GatewayHostControlsTitleText.Text = "WSL gateway"; - GatewayHostControlsDescriptionText.Text = - $"Open a shell or manage the local gateway service in {_activeHostAccessPlan.DistroName}."; + GatewayHostControlsDescriptionText.Text = LocalizationHelper.Format( + "ConnectionPage_GatewayHostControlsDescription_Format", + _activeHostAccessPlan.DistroName); GatewayHostOpenTerminalButton.IsEnabled = !_gatewayHostActionInProgress && _activeHostAccessPlan.CanOpenTerminal; GatewayHostStartButton.IsEnabled = !_gatewayHostActionInProgress; GatewayHostStopButton.IsEnabled = !_gatewayHostActionInProgress; @@ -478,6 +478,9 @@ private void ApplyGatewayHostAccess(ConnectionPagePlan plan) ? Visibility.Visible : Visibility.Collapsed; ToolTipService.SetToolTip(GatewayHostOpenTerminalButton, _activeHostAccessPlan.TerminalTooltip); + Microsoft.UI.Xaml.Automation.AutomationProperties.SetName( + GatewayHostOpenTerminalButton, + _activeHostAccessPlan.TerminalLabel); } private void SetGatewayHostActionStatus(string message, bool isError = false) diff --git a/src/OpenClaw.Tray.WinUI/Pages/CronPage.xaml.cs b/src/OpenClaw.Tray.WinUI/Pages/CronPage.xaml.cs index 1c756d32..ee0d4192 100644 --- a/src/OpenClaw.Tray.WinUI/Pages/CronPage.xaml.cs +++ b/src/OpenClaw.Tray.WinUI/Pages/CronPage.xaml.cs @@ -517,8 +517,8 @@ private void ShowJobCompletedNotification(string jobName) _infoDismissCts = new CancellationTokenSource(); var cts = _infoDismissCts; - JobCompletedInfoBar.Title = "Job completed"; - JobCompletedInfoBar.Message = $"\"{jobName}\" ran successfully and was removed."; + JobCompletedInfoBar.Title = LocalizationHelper.GetString("CronPage_JobCompleted"); + JobCompletedInfoBar.Message = LocalizationHelper.Format("CronPage_JobCompletedRanSuccessfully", jobName); JobCompletedInfoBar.IsOpen = true; DispatcherQueue?.TryEnqueue(async () => { @@ -863,8 +863,8 @@ private void UpdateCronLoadingVisuals() private void ShowDisconnected() { - ConnectionInfoBar.Title = "Gateway disconnected"; - ConnectionInfoBar.Message = "Connect to a gateway to load cron jobs."; + ConnectionInfoBar.Title = LocalizationHelper.GetString("CronPage_GatewayDisconnected.Title"); + ConnectionInfoBar.Message = LocalizationHelper.GetString("CronPage_GatewayDisconnected.Message"); ConnectionInfoBar.Severity = InfoBarSeverity.Warning; ConnectionInfoBar.IsOpen = true; } diff --git a/src/OpenClaw.Tray.WinUI/Pages/DebugPage.xaml.cs b/src/OpenClaw.Tray.WinUI/Pages/DebugPage.xaml.cs index ed46f08d..737d73a5 100644 --- a/src/OpenClaw.Tray.WinUI/Pages/DebugPage.xaml.cs +++ b/src/OpenClaw.Tray.WinUI/Pages/DebugPage.xaml.cs @@ -150,27 +150,27 @@ private void UpdateStatusInfoBar() { case ConnectionStatus.Connected: StatusInfoBar.Severity = InfoBarSeverity.Success; - StatusInfoBar.Title = "Connected"; + StatusInfoBar.Title = LocalizationHelper.GetConnectionStatusText(status); StatusInfoBar.Message = $"OpenClaw is connected to {gatewayDisplay}."; break; case ConnectionStatus.Connecting: StatusInfoBar.Severity = InfoBarSeverity.Informational; - StatusInfoBar.Title = "Connecting"; + StatusInfoBar.Title = LocalizationHelper.GetConnectionStatusText(status); StatusInfoBar.Message = $"Connecting to {gatewayDisplay}…"; break; case ConnectionStatus.Disconnected: StatusInfoBar.Severity = InfoBarSeverity.Warning; - StatusInfoBar.Title = "Disconnected"; + StatusInfoBar.Title = LocalizationHelper.GetConnectionStatusText(status); StatusInfoBar.Message = $"Not connected. Gateway: {gatewayDisplay}."; break; case ConnectionStatus.Error: StatusInfoBar.Severity = InfoBarSeverity.Error; - StatusInfoBar.Title = "Connection error"; + StatusInfoBar.Title = LocalizationHelper.GetConnectionStatusText(status); StatusInfoBar.Message = $"Last gateway: {gatewayDisplay}. See the event timeline."; break; default: StatusInfoBar.Severity = InfoBarSeverity.Informational; - StatusInfoBar.Title = "Status unknown"; + StatusInfoBar.Title = LocalizationHelper.GetConnectionStatusText(status); StatusInfoBar.Message = $"Gateway: {gatewayDisplay}."; break; } diff --git a/src/OpenClaw.Tray.WinUI/Pages/SessionsPage.xaml.cs b/src/OpenClaw.Tray.WinUI/Pages/SessionsPage.xaml.cs index f47d8093..d7862b5c 100644 --- a/src/OpenClaw.Tray.WinUI/Pages/SessionsPage.xaml.cs +++ b/src/OpenClaw.Tray.WinUI/Pages/SessionsPage.xaml.cs @@ -3,6 +3,7 @@ using Microsoft.UI.Xaml.Controls; using Microsoft.UI.Xaml.Media; using OpenClaw.Shared; +using OpenClawTray.Helpers; using OpenClawTray.Services; using OpenClawTray.Windows; using System; @@ -359,8 +360,8 @@ private static string FormatTokenCount(long n) private void ShowDisconnected() { - ConnectionInfoBar.Title = "Gateway disconnected"; - ConnectionInfoBar.Message = "Connect to a gateway to load sessions."; + ConnectionInfoBar.Title = LocalizationHelper.GetString("SessionsPage_GatewayDisconnected.Title"); + ConnectionInfoBar.Message = LocalizationHelper.GetString("SessionsPage_GatewayDisconnected.Message"); ConnectionInfoBar.Severity = InfoBarSeverity.Warning; ConnectionInfoBar.IsOpen = true; RefreshButton.IsEnabled = false; diff --git a/src/OpenClaw.Tray.WinUI/Pages/SkillsPage.xaml.cs b/src/OpenClaw.Tray.WinUI/Pages/SkillsPage.xaml.cs index a1f247bc..ef7cd93d 100644 --- a/src/OpenClaw.Tray.WinUI/Pages/SkillsPage.xaml.cs +++ b/src/OpenClaw.Tray.WinUI/Pages/SkillsPage.xaml.cs @@ -2,6 +2,7 @@ using Microsoft.UI.Xaml.Controls; using Microsoft.UI.Xaml.Media; using OpenClaw.Shared; +using OpenClawTray.Helpers; using OpenClawTray.Services; using System.Collections.Generic; using System.ComponentModel; @@ -204,12 +205,12 @@ private void RebuildCards() foreach (var s in disabled) DisabledPanel.Children.Add(BuildCard(s)); - EnabledHeaderText.Text = $"Enabled ({enabled.Count})"; - DisabledHeaderText.Text = $"Disabled ({disabled.Count})"; + EnabledHeaderText.Text = LocalizationHelper.Format("SkillsPage_EnabledHeaderFormat", enabled.Count); + DisabledHeaderText.Text = LocalizationHelper.Format("SkillsPage_DisabledHeaderFormat", disabled.Count); DisabledExpander.Visibility = disabled.Count > 0 ? Visibility.Visible : Visibility.Collapsed; var total = _allSkills.Count; - CountText.Text = total > 0 ? $"({enabled.Count}/{total} enabled)" : ""; + CountText.Text = total > 0 ? LocalizationHelper.Format("SkillsPage_CountFormat", enabled.Count, total) : ""; if (total > 0) { @@ -256,7 +257,7 @@ private Grid BuildCard(SkillData s) }; badge.Child = new TextBlock { - Text = s.IsEnabled ? "Enabled" : "Disabled", + Text = LocalizationHelper.GetString(s.IsEnabled ? "SkillsPage_BadgeEnabled" : "SkillsPage_BadgeDisabled"), FontSize = 11, FontWeight = Microsoft.UI.Text.FontWeights.SemiBold, Foreground = (Brush)Application.Current.Resources[badgeFgKey], diff --git a/src/OpenClaw.Tray.WinUI/Pages/UsagePage.xaml.cs b/src/OpenClaw.Tray.WinUI/Pages/UsagePage.xaml.cs index c2ad6b89..a606f8ae 100644 --- a/src/OpenClaw.Tray.WinUI/Pages/UsagePage.xaml.cs +++ b/src/OpenClaw.Tray.WinUI/Pages/UsagePage.xaml.cs @@ -2,6 +2,7 @@ using Microsoft.UI.Xaml.Controls; using OpenClaw.Connection; using OpenClaw.Shared; +using OpenClawTray.Helpers; using OpenClawTray.Services; using System; using System.Collections.Generic; @@ -330,8 +331,8 @@ private void UpdateProviderLoadingVisuals() private void ShowDisconnected() { - ConnectionInfoBar.Title = "Gateway disconnected"; - ConnectionInfoBar.Message = "Connect to a gateway to load usage data."; + ConnectionInfoBar.Title = LocalizationHelper.GetString("UsagePage_GatewayDisconnected.Title"); + ConnectionInfoBar.Message = LocalizationHelper.GetString("UsagePage_GatewayDisconnected.Message"); ConnectionInfoBar.Severity = InfoBarSeverity.Warning; ConnectionInfoBar.IsOpen = true; } diff --git a/src/OpenClaw.Tray.WinUI/Services/CommandCenterStateBuilder.cs b/src/OpenClaw.Tray.WinUI/Services/CommandCenterStateBuilder.cs index 713c97d7..44f1b970 100644 --- a/src/OpenClaw.Tray.WinUI/Services/CommandCenterStateBuilder.cs +++ b/src/OpenClaw.Tray.WinUI/Services/CommandCenterStateBuilder.cs @@ -46,7 +46,7 @@ internal GatewayCommandCenterState Build() { Severity = GatewayDiagnosticSeverity.Critical, Category = "auth", - Title = "Gateway authentication failed", + Title = LocalizationHelper.GetString("CommandCenter_AuthFailed"), Detail = _snapshot.AuthFailureMessage }); } @@ -58,7 +58,7 @@ internal GatewayCommandCenterState Build() { Severity = GatewayDiagnosticSeverity.Warning, Category = "pairing", - Title = "Node is waiting for approval", + Title = LocalizationHelper.GetString("CommandCenter_NodePendingApproval"), Detail = $"Approve device {_snapshot.NodeService.ShortDeviceId} from the gateway CLI, then re-open the command center after reconnect.", RepairAction = "Copy approval command", CopyText = approvalCommand @@ -71,7 +71,7 @@ internal GatewayCommandCenterState Build() { Severity = GatewayDiagnosticSeverity.Critical, Category = "gateway", - Title = "Gateway connection error", + Title = LocalizationHelper.GetString("CommandCenter_GatewayConnectionError"), Detail = "The tray is not currently connected to the gateway." }); } @@ -81,7 +81,7 @@ internal GatewayCommandCenterState Build() { Severity = GatewayDiagnosticSeverity.Warning, Category = "gateway", - Title = "Gateway is not connected", + Title = LocalizationHelper.GetString("CommandCenter_GatewayNotConnected"), Detail = $"Current connection state is {_snapshot.Status}." }); } @@ -93,7 +93,7 @@ internal GatewayCommandCenterState Build() { Severity = GatewayDiagnosticSeverity.Warning, Category = "gateway", - Title = "Gateway health is stale", + Title = LocalizationHelper.GetString("CommandCenter_GatewayHealthStale"), Detail = $"Last health check was {_snapshot.LastCheckTime:t}. Run a health check or verify the localhost tunnel." }); } @@ -104,7 +104,7 @@ internal GatewayCommandCenterState Build() { Severity = GatewayDiagnosticSeverity.Info, Category = "channel", - Title = "No channels reported", + Title = LocalizationHelper.GetString("CommandCenter_NoChannelsReported"), Detail = "The gateway health payload did not report any channels." }); } @@ -114,7 +114,7 @@ internal GatewayCommandCenterState Build() { Severity = GatewayDiagnosticSeverity.Info, Category = "gateway", - Title = "Waiting for gateway health", + Title = LocalizationHelper.GetString("CommandCenter_WaitingForGatewayHealth"), Detail = "Node mode is connected. Channel/session inventories are filled from gateway health events when available." }); } @@ -124,7 +124,7 @@ internal GatewayCommandCenterState Build() { Severity = GatewayDiagnosticSeverity.Warning, Category = "channel", - Title = "No channels are currently running", + Title = LocalizationHelper.GetString("CommandCenter_NoChannelsRunning"), Detail = "Channels are configured but none are reporting a running/ready state." }); } @@ -135,7 +135,7 @@ internal GatewayCommandCenterState Build() { Severity = GatewayDiagnosticSeverity.Info, Category = "node", - Title = "No nodes reported", + Title = LocalizationHelper.GetString("CommandCenter_NoNodesReported"), Detail = "node.list did not report any connected nodes. Pair a Windows node or verify the operator token has node inventory access." }); } @@ -146,7 +146,7 @@ internal GatewayCommandCenterState Build() { Severity = GatewayDiagnosticSeverity.Info, Category = "usage", - Title = "Some usage costs are missing", + Title = LocalizationHelper.GetString("CommandCenter_UsageCostsMissing"), Detail = $"{_snapshot.UsageCost.Totals.MissingCostEntries} usage entr{(_snapshot.UsageCost.Totals.MissingCostEntries == 1 ? "y is" : "ies are")} missing cost data." }); } @@ -196,7 +196,7 @@ private IEnumerable BuildBrowserProxyAuthWarnings(IRea { Severity = GatewayDiagnosticSeverity.Info, Category = "browser", - Title = "Browser proxy auth may need a gateway token", + Title = LocalizationHelper.GetString("CommandCenter_BrowserProxyAuthMayNeed"), Detail = "This Windows node is advertising browser.proxy without a saved gateway shared token. QR/bootstrap pairing can connect the node, but an authenticated browser-control host may still require the same gateway token in Settings.", RepairAction = "Copy browser proxy auth guidance", CopyText = "If browser.proxy returns an auth error, enter the gateway shared token in Settings > Gateway Token, or configure the browser-control host to use auth compatible with the Windows node. Do not paste QR bootstrap tokens into the normal gateway token field." @@ -218,7 +218,7 @@ private static IEnumerable BuildPortDiagnosticWarnings { Severity = GatewayDiagnosticSeverity.Warning, Category = "port", - Title = "SSH tunnel port is not listening", + Title = LocalizationHelper.GetString("CommandCenter_SshTunnelPortNotListening"), Detail = port.Detail }; } @@ -231,7 +231,7 @@ private static IEnumerable BuildPortDiagnosticWarnings { Severity = GatewayDiagnosticSeverity.Info, Category = "port", - Title = "No local gateway listener detected", + Title = LocalizationHelper.GetString("CommandCenter_NoLocalGatewayListener"), Detail = port.Detail }; } @@ -245,7 +245,7 @@ private static IEnumerable BuildPortDiagnosticWarnings { Severity = GatewayDiagnosticSeverity.Info, Category = "browser", - Title = "Browser proxy SSH forward is not listening", + Title = LocalizationHelper.GetString("CommandCenter_BrowserProxySshForwardNotListening"), Detail = $"browser.proxy over SSH needs a companion local forward for port {port.Port}. Add the browser-control forward to the same tunnel, or enable the managed SSH tunnel so Windows starts both forwards.", RepairAction = "Copy browser proxy SSH forward", CopyText = BuildBrowserProxySshForwardHint(port.Port, tunnel) @@ -257,7 +257,7 @@ private static IEnumerable BuildPortDiagnosticWarnings { Severity = GatewayDiagnosticSeverity.Info, Category = "browser", - Title = "Browser proxy host not detected", + Title = LocalizationHelper.GetString("CommandCenter_BrowserProxyHostNotDetected"), Detail = "browser.proxy needs a compatible browser-control host listening on the gateway port + 2.", RepairAction = "Copy browser setup guidance", // string formatter — no UI diff --git a/src/OpenClaw.Tray.WinUI/Services/GatewayHostAccess.cs b/src/OpenClaw.Tray.WinUI/Services/GatewayHostAccess.cs index aa776496..8967457e 100644 --- a/src/OpenClaw.Tray.WinUI/Services/GatewayHostAccess.cs +++ b/src/OpenClaw.Tray.WinUI/Services/GatewayHostAccess.cs @@ -1,3 +1,4 @@ +using System; using OpenClaw.Connection; namespace OpenClawTray.Services; @@ -9,6 +10,18 @@ internal enum GatewayTerminalTarget Ssh } +/// +/// Localization indirection for / . +/// Defaults are identity (return the resource key unchanged) so the file is unit-testable +/// without a WinUI runtime. App.xaml.cs wires these up to LocalizationHelper +/// at startup so the running app sees real localized strings. +/// +internal static class GatewayHostAccessLocalization +{ + public static Func GetString { get; set; } = key => key; + public static Func Format { get; set; } = (key, _) => key; +} + internal sealed record GatewayHostAccessPlan( string? GatewayId, GatewayTerminalTarget TerminalTarget, @@ -26,6 +39,7 @@ internal sealed record GatewayHostAccessPlan( public static GatewayHostAccessPlan None(string? gatewayId = null, string? disabledReason = null) { + var defaultReason = disabledReason ?? GatewayHostAccessLocalization.GetString("GatewayHostAccess_NoTerminalAccess"); return new GatewayHostAccessPlan( gatewayId, GatewayTerminalTarget.None, @@ -33,9 +47,9 @@ public static GatewayHostAccessPlan None(string? gatewayId = null, string? disab null, null, false, - "Open terminal", - disabledReason ?? "This gateway does not have WSL or SSH terminal access.", - disabledReason ?? "This gateway does not have WSL or SSH terminal access."); + GatewayHostAccessLocalization.GetString("GatewayHostAccess_OpenTerminalLabel"), + defaultReason, + defaultReason); } } @@ -61,8 +75,8 @@ public static GatewayHostAccessPlan Classify(GatewayRecord? record) sshUser, sshHost, true, - "Open terminal", - $"Open a terminal in the {distroName} WSL gateway.", + GatewayHostAccessLocalization.GetString("GatewayHostAccess_OpenTerminalLabel"), + GatewayHostAccessLocalization.Format("GatewayHostAccess_OpenTerminalInWslTooltip_Format", new object?[] { distroName }), null); } @@ -75,14 +89,14 @@ public static GatewayHostAccessPlan Classify(GatewayRecord? record) sshUser, sshHost, false, - "Open SSH terminal", - $"Open an SSH terminal to {sshUser}@{sshHost}.", + GatewayHostAccessLocalization.GetString("GatewayHostAccess_OpenSshTerminalLabel"), + GatewayHostAccessLocalization.Format("GatewayHostAccess_OpenSshTerminalTooltip_Format", new object?[] { sshUser, sshHost }), null); } return GatewayHostAccessPlan.None( record.Id, - "This gateway was not created with WSL and does not have an SSH tunnel."); + GatewayHostAccessLocalization.GetString("GatewayHostAccess_NoWslOrSshDisabled")); } private static string? Normalize(string? value) diff --git a/src/OpenClaw.Tray.WinUI/Strings/en-us/Resources.resw b/src/OpenClaw.Tray.WinUI/Strings/en-us/Resources.resw index 7740514b..3079bc89 100644 --- a/src/OpenClaw.Tray.WinUI/Strings/en-us/Resources.resw +++ b/src/OpenClaw.Tray.WinUI/Strings/en-us/Resources.resw @@ -5527,4 +5527,244 @@ Check your connection settings and try again. Restart WSL gateway + + Live + + + Offline + + + Could not load bindings + + + Agent event log + + + Go to Agent Events + + + Gateway bindings + + + Go to Bindings + + + Gateway channels + + + Go to Channels + + + Open chat + + + Go to Chat + + + Gateway configuration + + + Go to Config + + + Gateway, node, saved gateways + + + Go to Connection + + + Scheduled tasks + + + Go to Cron ({0}) + + + Logs, support bundle, device identity, developer tools + + + Go to Diagnostics + + + About this app + + + Go to Info + + + Gateway instances + + + Go to Instances + + + Capabilities, exec policy & allowlists + + + Go to Permissions + + + All sessions + + + Go to Sessions + + + Application settings + + + Go to Settings + + + Registered skills + + + Go to Skills + + + Usage statistics + + + Go to Usage + + + Workspace files + + + Go to Workspace ({0}) + + + Open standalone chat + + + Open Chat Window + + + Open web dashboard + + + Open Dashboard + + + Currently OFF + + + Currently ON + + + Toggle Browser Control + + + Toggle Camera + + + Toggle Canvas + + + Toggle Node Mode + + + Toggle Screen Capture + + + Gateway authentication failed + + + Browser proxy auth may need a gateway token + + + Browser proxy host not detected + + + Browser proxy SSH forward is not listening + + + Gateway connection error + + + Gateway health is stale + + + Gateway is not connected + + + No channels reported + + + No channels are currently running + + + Node is waiting for approval + + + No local gateway listener detected + + + No nodes reported + + + SSH tunnel port is not listening + + + Some usage costs are missing + + + Waiting for gateway health + + + Checking config permissions + + + Config is read-only + + + Config unavailable + + + Open a shell or manage the local gateway service in {0}. + + + Job completed + + + "{0}" ran successfully and was removed. + + + This gateway does not have WSL or SSH terminal access. + + + This gateway was not created with WSL and does not have an SSH tunnel. + + + Open SSH terminal + + + Open an SSH terminal to {0}@{1}. + + + Open a terminal in the {0} WSL gateway. + + + Open terminal + + + Open in chat + + + Open this session in Chat + + + Disabled + + + Enabled + + + ({0}/{1} enabled) + + + Disabled ({0}) + + + Enabled ({0}) + diff --git a/src/OpenClaw.Tray.WinUI/Strings/fr-fr/Resources.resw b/src/OpenClaw.Tray.WinUI/Strings/fr-fr/Resources.resw index 94d9d813..6d422a05 100644 --- a/src/OpenClaw.Tray.WinUI/Strings/fr-fr/Resources.resw +++ b/src/OpenClaw.Tray.WinUI/Strings/fr-fr/Resources.resw @@ -5479,4 +5479,244 @@ Vérifiez vos paramètres de connexion et réessayez. Redémarrer la passerelle WSL + + En direct + + + Hors ligne + + + Could not load bindings + + + Agent event log + + + Go to Agent Events + + + Gateway bindings + + + Go to Bindings + + + Gateway channels + + + Go to Channels + + + Open chat + + + Go to Chat + + + Gateway configuration + + + Go to Config + + + Gateway, node, saved gateways + + + Go to Connection + + + Scheduled tasks + + + Go to Cron ({0}) + + + Logs, support bundle, device identity, developer tools + + + Go to Diagnostics + + + About this app + + + Go to Info + + + Gateway instances + + + Go to Instances + + + Capabilities, exec policy & allowlists + + + Go to Permissions + + + All sessions + + + Go to Sessions + + + Application settings + + + Go to Settings + + + Registered skills + + + Go to Skills + + + Usage statistics + + + Go to Usage + + + Workspace files + + + Go to Workspace ({0}) + + + Open standalone chat + + + Open Chat Window + + + Open web dashboard + + + Open Dashboard + + + Currently OFF + + + Currently ON + + + Toggle Browser Control + + + Toggle Camera + + + Toggle Canvas + + + Toggle Node Mode + + + Toggle Screen Capture + + + Gateway authentication failed + + + Browser proxy auth may need a gateway token + + + Browser proxy host not detected + + + Browser proxy SSH forward is not listening + + + Gateway connection error + + + Gateway health is stale + + + Gateway is not connected + + + No channels reported + + + No channels are currently running + + + Node is waiting for approval + + + No local gateway listener detected + + + No nodes reported + + + SSH tunnel port is not listening + + + Some usage costs are missing + + + Waiting for gateway health + + + Checking config permissions + + + Config is read-only + + + Config unavailable + + + Open a shell or manage the local gateway service in {0}. + + + Job completed + + + "{0}" ran successfully and was removed. + + + This gateway does not have WSL or SSH terminal access. + + + This gateway was not created with WSL and does not have an SSH tunnel. + + + Open SSH terminal + + + Open an SSH terminal to {0}@{1}. + + + Open a terminal in the {0} WSL gateway. + + + Open terminal + + + Open in chat + + + Open this session in Chat + + + Désactivée + + + Activée + + + ({0}/{1} activées) + + + Désactivées ({0}) + + + Activées ({0}) + diff --git a/src/OpenClaw.Tray.WinUI/Strings/nl-nl/Resources.resw b/src/OpenClaw.Tray.WinUI/Strings/nl-nl/Resources.resw index c6631660..8ca0450e 100644 --- a/src/OpenClaw.Tray.WinUI/Strings/nl-nl/Resources.resw +++ b/src/OpenClaw.Tray.WinUI/Strings/nl-nl/Resources.resw @@ -5480,4 +5480,244 @@ Controleer uw verbindingsinstellingen en probeer het opnieuw. WSL-gateway opnieuw starten + + Actueel + + + Niet verbonden + + + Could not load bindings + + + Agent event log + + + Go to Agent Events + + + Gateway bindings + + + Go to Bindings + + + Gateway channels + + + Go to Channels + + + Open chat + + + Go to Chat + + + Gateway configuration + + + Go to Config + + + Gateway, node, saved gateways + + + Go to Connection + + + Scheduled tasks + + + Go to Cron ({0}) + + + Logs, support bundle, device identity, developer tools + + + Go to Diagnostics + + + About this app + + + Go to Info + + + Gateway instances + + + Go to Instances + + + Capabilities, exec policy & allowlists + + + Go to Permissions + + + All sessions + + + Go to Sessions + + + Application settings + + + Go to Settings + + + Registered skills + + + Go to Skills + + + Usage statistics + + + Go to Usage + + + Workspace files + + + Go to Workspace ({0}) + + + Open standalone chat + + + Open Chat Window + + + Open web dashboard + + + Open Dashboard + + + Currently OFF + + + Currently ON + + + Toggle Browser Control + + + Toggle Camera + + + Toggle Canvas + + + Toggle Node Mode + + + Toggle Screen Capture + + + Gateway authentication failed + + + Browser proxy auth may need a gateway token + + + Browser proxy host not detected + + + Browser proxy SSH forward is not listening + + + Gateway connection error + + + Gateway health is stale + + + Gateway is not connected + + + No channels reported + + + No channels are currently running + + + Node is waiting for approval + + + No local gateway listener detected + + + No nodes reported + + + SSH tunnel port is not listening + + + Some usage costs are missing + + + Waiting for gateway health + + + Checking config permissions + + + Config is read-only + + + Config unavailable + + + Open a shell or manage the local gateway service in {0}. + + + Job completed + + + "{0}" ran successfully and was removed. + + + This gateway does not have WSL or SSH terminal access. + + + This gateway was not created with WSL and does not have an SSH tunnel. + + + Open SSH terminal + + + Open an SSH terminal to {0}@{1}. + + + Open a terminal in the {0} WSL gateway. + + + Open terminal + + + Open in chat + + + Open this session in Chat + + + Uitgeschakeld + + + Ingeschakeld + + + ({0}/{1} ingeschakeld) + + + Uitgeschakeld ({0}) + + + Ingeschakeld ({0}) + diff --git a/src/OpenClaw.Tray.WinUI/Strings/zh-cn/Resources.resw b/src/OpenClaw.Tray.WinUI/Strings/zh-cn/Resources.resw index 106bb16a..6799c423 100644 --- a/src/OpenClaw.Tray.WinUI/Strings/zh-cn/Resources.resw +++ b/src/OpenClaw.Tray.WinUI/Strings/zh-cn/Resources.resw @@ -5480,4 +5480,244 @@ 重启 WSL 网关 + + 实时 + + + 离线 + + + Could not load bindings + + + Agent event log + + + Go to Agent Events + + + Gateway bindings + + + Go to Bindings + + + Gateway channels + + + Go to Channels + + + Open chat + + + Go to Chat + + + Gateway configuration + + + Go to Config + + + Gateway, node, saved gateways + + + Go to Connection + + + Scheduled tasks + + + Go to Cron ({0}) + + + Logs, support bundle, device identity, developer tools + + + Go to Diagnostics + + + About this app + + + Go to Info + + + Gateway instances + + + Go to Instances + + + Capabilities, exec policy & allowlists + + + Go to Permissions + + + All sessions + + + Go to Sessions + + + Application settings + + + Go to Settings + + + Registered skills + + + Go to Skills + + + Usage statistics + + + Go to Usage + + + Workspace files + + + Go to Workspace ({0}) + + + Open standalone chat + + + Open Chat Window + + + Open web dashboard + + + Open Dashboard + + + Currently OFF + + + Currently ON + + + Toggle Browser Control + + + Toggle Camera + + + Toggle Canvas + + + Toggle Node Mode + + + Toggle Screen Capture + + + Gateway authentication failed + + + Browser proxy auth may need a gateway token + + + Browser proxy host not detected + + + Browser proxy SSH forward is not listening + + + Gateway connection error + + + Gateway health is stale + + + Gateway is not connected + + + No channels reported + + + No channels are currently running + + + Node is waiting for approval + + + No local gateway listener detected + + + No nodes reported + + + SSH tunnel port is not listening + + + Some usage costs are missing + + + Waiting for gateway health + + + Checking config permissions + + + Config is read-only + + + Config unavailable + + + Open a shell or manage the local gateway service in {0}. + + + Job completed + + + "{0}" ran successfully and was removed. + + + This gateway does not have WSL or SSH terminal access. + + + This gateway was not created with WSL and does not have an SSH tunnel. + + + Open SSH terminal + + + Open an SSH terminal to {0}@{1}. + + + Open a terminal in the {0} WSL gateway. + + + Open terminal + + + Open in chat + + + Open this session in Chat + + + 已禁用 + + + 已启用 + + + ({0}/{1} 已启用) + + + 已禁用 ({0}) + + + 已启用 ({0}) + diff --git a/src/OpenClaw.Tray.WinUI/Strings/zh-tw/Resources.resw b/src/OpenClaw.Tray.WinUI/Strings/zh-tw/Resources.resw index e22f5630..0054849c 100644 --- a/src/OpenClaw.Tray.WinUI/Strings/zh-tw/Resources.resw +++ b/src/OpenClaw.Tray.WinUI/Strings/zh-tw/Resources.resw @@ -5480,4 +5480,244 @@ 重新啟動 WSL 閘道 + + 即時 + + + 離線 + + + Could not load bindings + + + Agent event log + + + Go to Agent Events + + + Gateway bindings + + + Go to Bindings + + + Gateway channels + + + Go to Channels + + + Open chat + + + Go to Chat + + + Gateway configuration + + + Go to Config + + + Gateway, node, saved gateways + + + Go to Connection + + + Scheduled tasks + + + Go to Cron ({0}) + + + Logs, support bundle, device identity, developer tools + + + Go to Diagnostics + + + About this app + + + Go to Info + + + Gateway instances + + + Go to Instances + + + Capabilities, exec policy & allowlists + + + Go to Permissions + + + All sessions + + + Go to Sessions + + + Application settings + + + Go to Settings + + + Registered skills + + + Go to Skills + + + Usage statistics + + + Go to Usage + + + Workspace files + + + Go to Workspace ({0}) + + + Open standalone chat + + + Open Chat Window + + + Open web dashboard + + + Open Dashboard + + + Currently OFF + + + Currently ON + + + Toggle Browser Control + + + Toggle Camera + + + Toggle Canvas + + + Toggle Node Mode + + + Toggle Screen Capture + + + Gateway authentication failed + + + Browser proxy auth may need a gateway token + + + Browser proxy host not detected + + + Browser proxy SSH forward is not listening + + + Gateway connection error + + + Gateway health is stale + + + Gateway is not connected + + + No channels reported + + + No channels are currently running + + + Node is waiting for approval + + + No local gateway listener detected + + + No nodes reported + + + SSH tunnel port is not listening + + + Some usage costs are missing + + + Waiting for gateway health + + + Checking config permissions + + + Config is read-only + + + Config unavailable + + + Open a shell or manage the local gateway service in {0}. + + + Job completed + + + "{0}" ran successfully and was removed. + + + This gateway does not have WSL or SSH terminal access. + + + This gateway was not created with WSL and does not have an SSH tunnel. + + + Open SSH terminal + + + Open an SSH terminal to {0}@{1}. + + + Open a terminal in the {0} WSL gateway. + + + Open terminal + + + Open in chat + + + Open this session in Chat + + + 已停用 + + + 已啟用 + + + ({0}/{1} 已啟用) + + + 已停用 ({0}) + + + 已啟用 ({0}) + diff --git a/src/OpenClaw.Tray.WinUI/Windows/HubWindow.xaml.cs b/src/OpenClaw.Tray.WinUI/Windows/HubWindow.xaml.cs index 1670ee4e..da5dd021 100644 --- a/src/OpenClaw.Tray.WinUI/Windows/HubWindow.xaml.cs +++ b/src/OpenClaw.Tray.WinUI/Windows/HubWindow.xaml.cs @@ -339,12 +339,12 @@ private void NavigateInternal(string tag) private void UpdateTitleBarStatus(ConnectionStatus status) { - var (color, text) = status switch + var color = status switch { - ConnectionStatus.Connected => (Microsoft.UI.Colors.LimeGreen, "Connected"), - ConnectionStatus.Connecting => (Microsoft.UI.Colors.Orange, "Connecting…"), - ConnectionStatus.Error => (Microsoft.UI.Colors.Red, "Error"), - _ => (Microsoft.UI.Colors.Gray, "Disconnected") + ConnectionStatus.Connected => Microsoft.UI.Colors.LimeGreen, + ConnectionStatus.Connecting => Microsoft.UI.Colors.Orange, + ConnectionStatus.Error => Microsoft.UI.Colors.Red, + _ => Microsoft.UI.Colors.Gray }; TitleStatusDot.Fill = new Microsoft.UI.Xaml.Media.SolidColorBrush(color); @@ -353,7 +353,7 @@ private void UpdateTitleBarStatus(ConnectionStatus status) if (status == ConnectionStatus.Connected && LastGatewaySelf is { ServerVersion: { Length: > 0 } ver }) TitleStatusText.Text = $"v{ver}"; else - TitleStatusText.Text = text; + TitleStatusText.Text = LocalizationHelper.GetConnectionStatusText(status); // Update role indicator dots var snapshot = CurrentApp.ConnectionManager?.CurrentSnapshot; @@ -751,60 +751,62 @@ internal List BuildCommandList() var commands = new List { // Navigation - new() { Icon = "🔌", Title = "Go to Connection", Subtitle = "Gateway, node, saved gateways", Tag = "connection" }, - new() { Icon = "💬", Title = "Go to Chat", Subtitle = "Open chat", Tag = "chat" }, - new() { Icon = "🧠", Title = "Go to Sessions", Subtitle = "All sessions", Tag = "sessions" }, - new() { Icon = "🧠", Title = "Go to Agent Events", Subtitle = "Agent event log", Tag = "agentevents" }, - new() { Icon = "🧠", Title = "Go to Skills", Subtitle = "Registered skills", Tag = "skills" }, - new() { Icon = "🧠", Title = $"Go to Cron ({agentId})", Subtitle = "Scheduled tasks", Tag = $"agent:{agentId}:cron" }, - new() { Icon = "🧠", Title = $"Go to Workspace ({agentId})", Subtitle = "Workspace files", Tag = $"agent:{agentId}" }, - new() { Icon = "📡", Title = "Go to Channels", Subtitle = "Gateway channels", Tag = "channels" }, - new() { Icon = "📡", Title = "Go to Instances", Subtitle = "Gateway instances", Tag = "instances" }, - new() { Icon = "📡", Title = "Go to Config", Subtitle = "Gateway configuration", Tag = "config" }, - new() { Icon = "📡", Title = "Go to Usage", Subtitle = "Usage statistics", Tag = "usage" }, - new() { Icon = "📡", Title = "Go to Bindings", Subtitle = "Gateway bindings", Tag = "bindings" }, - new() { Icon = "🛡️", Title = "Go to Permissions", Subtitle = "Capabilities, exec policy & allowlists", Tag = "permissions" }, - new() { Icon = "⚙️", Title = "Go to Settings", Subtitle = "Application settings", Tag = "settings" }, - new() { Icon = "🐛", Title = "Go to Diagnostics", Subtitle = "Logs, support bundle, device identity, developer tools", Tag = "debug" }, - new() { Icon = "ℹ️", Title = "Go to Info", Subtitle = "About this app", Tag = "info" }, + new() { Icon = "🔌", Title = LocalizationHelper.GetString("Command_GoToConnection_Title"), Subtitle = LocalizationHelper.GetString("Command_GoToConnection_Subtitle"), Tag = "connection" }, + new() { Icon = "💬", Title = LocalizationHelper.GetString("Command_GoToChat_Title"), Subtitle = LocalizationHelper.GetString("Command_GoToChat_Subtitle"), Tag = "chat" }, + new() { Icon = "🧠", Title = LocalizationHelper.GetString("Command_GoToSessions_Title"), Subtitle = LocalizationHelper.GetString("Command_GoToSessions_Subtitle"), Tag = "sessions" }, + new() { Icon = "🧠", Title = LocalizationHelper.GetString("Command_GoToAgentEvents_Title"), Subtitle = LocalizationHelper.GetString("Command_GoToAgentEvents_Subtitle"), Tag = "agentevents" }, + new() { Icon = "🧠", Title = LocalizationHelper.GetString("Command_GoToSkills_Title"), Subtitle = LocalizationHelper.GetString("Command_GoToSkills_Subtitle"), Tag = "skills" }, + new() { Icon = "🧠", Title = LocalizationHelper.Format("Command_GoToCron_Title", agentId), Subtitle = LocalizationHelper.GetString("Command_GoToCron_Subtitle"), Tag = $"agent:{agentId}:cron" }, + new() { Icon = "🧠", Title = LocalizationHelper.Format("Command_GoToWorkspace_Title", agentId), Subtitle = LocalizationHelper.GetString("Command_GoToWorkspace_Subtitle"), Tag = $"agent:{agentId}" }, + new() { Icon = "📡", Title = LocalizationHelper.GetString("Command_GoToChannels_Title"), Subtitle = LocalizationHelper.GetString("Command_GoToChannels_Subtitle"), Tag = "channels" }, + new() { Icon = "📡", Title = LocalizationHelper.GetString("Command_GoToInstances_Title"), Subtitle = LocalizationHelper.GetString("Command_GoToInstances_Subtitle"), Tag = "instances" }, + new() { Icon = "📡", Title = LocalizationHelper.GetString("Command_GoToConfig_Title"), Subtitle = LocalizationHelper.GetString("Command_GoToConfig_Subtitle"), Tag = "config" }, + new() { Icon = "📡", Title = LocalizationHelper.GetString("Command_GoToUsage_Title"), Subtitle = LocalizationHelper.GetString("Command_GoToUsage_Subtitle"), Tag = "usage" }, + new() { Icon = "📡", Title = LocalizationHelper.GetString("Command_GoToBindings_Title"), Subtitle = LocalizationHelper.GetString("Command_GoToBindings_Subtitle"), Tag = "bindings" }, + new() { Icon = "🛡️", Title = LocalizationHelper.GetString("Command_GoToPermissions_Title"), Subtitle = LocalizationHelper.GetString("Command_GoToPermissions_Subtitle"), Tag = "permissions" }, + new() { Icon = "⚙️", Title = LocalizationHelper.GetString("Command_GoToSettings_Title"), Subtitle = LocalizationHelper.GetString("Command_GoToSettings_Subtitle"), Tag = "settings" }, + new() { Icon = "🐛", Title = LocalizationHelper.GetString("Command_GoToDiagnostics_Title"), Subtitle = LocalizationHelper.GetString("Command_GoToDiagnostics_Subtitle"), Tag = "debug" }, + new() { Icon = "ℹ️", Title = LocalizationHelper.GetString("Command_GoToInfo_Title"), Subtitle = LocalizationHelper.GetString("Command_GoToInfo_Subtitle"), Tag = "info" }, // Actions - new() { Icon = "💬", Title = "Open Chat Window", Subtitle = "Open standalone chat", Tag = "chat" }, - new() { Icon = "🌐", Title = "Open Dashboard", Subtitle = "Open web dashboard", Execute = () => ((IAppCommands)Application.Current).OpenDashboard(null) }, + new() { Icon = "💬", Title = LocalizationHelper.GetString("Command_OpenChatWindow_Title"), Subtitle = LocalizationHelper.GetString("Command_OpenChatWindow_Subtitle"), Tag = "chat" }, + new() { Icon = "🌐", Title = LocalizationHelper.GetString("Command_OpenDashboard_Title"), Subtitle = LocalizationHelper.GetString("Command_OpenDashboard_Subtitle"), Execute = () => ((IAppCommands)Application.Current).OpenDashboard(null) }, }; // Toggle commands var settings = CurrentApp.Settings; if (settings != null) { + var on = LocalizationHelper.GetString("Command_Subtitle_CurrentlyOn"); + var off = LocalizationHelper.GetString("Command_Subtitle_CurrentlyOff"); commands.Add(new CommandItem { - Icon = "🔌", Title = "Toggle Node Mode", - Subtitle = settings.EnableNodeMode ? "Currently ON" : "Currently OFF", + Icon = "🔌", Title = LocalizationHelper.GetString("Command_ToggleNodeMode_Title"), + Subtitle = settings.EnableNodeMode ? on : off, Execute = () => { settings.EnableNodeMode = !settings.EnableNodeMode; settings.Save(); RaiseSettingsSaved(); } }); commands.Add(new CommandItem { - Icon = "📷", Title = "Toggle Camera", - Subtitle = settings.NodeCameraEnabled ? "Currently ON" : "Currently OFF", + Icon = "📷", Title = LocalizationHelper.GetString("Command_ToggleCamera_Title"), + Subtitle = settings.NodeCameraEnabled ? on : off, Execute = () => { settings.NodeCameraEnabled = !settings.NodeCameraEnabled; settings.Save(); RaiseSettingsSaved(); } }); commands.Add(new CommandItem { - Icon = "🎨", Title = "Toggle Canvas", - Subtitle = settings.NodeCanvasEnabled ? "Currently ON" : "Currently OFF", + Icon = "🎨", Title = LocalizationHelper.GetString("Command_ToggleCanvas_Title"), + Subtitle = settings.NodeCanvasEnabled ? on : off, Execute = () => { settings.NodeCanvasEnabled = !settings.NodeCanvasEnabled; settings.Save(); RaiseSettingsSaved(); } }); commands.Add(new CommandItem { - Icon = "🖥️", Title = "Toggle Screen Capture", - Subtitle = settings.NodeScreenEnabled ? "Currently ON" : "Currently OFF", + Icon = "🖥️", Title = LocalizationHelper.GetString("Command_ToggleScreenCapture_Title"), + Subtitle = settings.NodeScreenEnabled ? on : off, Execute = () => { settings.NodeScreenEnabled = !settings.NodeScreenEnabled; settings.Save(); RaiseSettingsSaved(); } }); commands.Add(new CommandItem { - Icon = "🌐", Title = "Toggle Browser Control", - Subtitle = settings.NodeBrowserProxyEnabled ? "Currently ON" : "Currently OFF", + Icon = "🌐", Title = LocalizationHelper.GetString("Command_ToggleBrowserControl_Title"), + Subtitle = settings.NodeBrowserProxyEnabled ? on : off, Execute = () => { settings.NodeBrowserProxyEnabled = !settings.NodeBrowserProxyEnabled; settings.Save(); RaiseSettingsSaved(); } }); } diff --git a/tests/OpenClaw.Tray.Tests/LocalizationValidationTests.cs b/tests/OpenClaw.Tray.Tests/LocalizationValidationTests.cs index b3892f24..9582d19f 100644 --- a/tests/OpenClaw.Tray.Tests/LocalizationValidationTests.cs +++ b/tests/OpenClaw.Tray.Tests/LocalizationValidationTests.cs @@ -181,6 +181,97 @@ public class LocalizationValidationTests "SandboxPage_1MiB.Content", "SandboxPage_64MiB.Content", "SandboxPage_SystemRun.Text", + // SessionsPage runtime accessibility strings — seeded English-only across + // all 5 locales using the deferred-translation pattern. These are + // tooltip / AutomationProperties.Name overrides on the OpenChat button. + // Same precedent as the PermissionsPage / InstancesPage / ConfigPage + // runtime keys above. + "SessionsPage_OpenChatButton.[using:Microsoft.UI.Xaml.Controls]ToolTipService.ToolTip", + "SessionsPage_OpenChatButton.[using:Microsoft.UI.Xaml.Automation]AutomationProperties.Name", + // CronPage / InfoBar / HubWindow nav / CommandCenter runtime strings — + // seeded English-only across all 5 locales using the deferred-translation + // pattern. Fetched at runtime via LocalizationHelper. Same precedent as + // the PermissionsPage / InstancesPage / SessionsPage runtime keys above. + "CronPage_JobCompleted", + "CronPage_JobCompletedRanSuccessfully", + "BindingsPage_CouldNotLoadBindings", + "ConfigPage_CheckingConfigPermissions", + "ConfigPage_ConfigUnavailable", + "ConfigPage_ConfigIsReadOnly", + // ConnectionPage gateway terminal controls — surfaced after PR #597 + // landed in master. Seeded English-only across all 5 locales using the + // same deferred-translation pattern as the AgentEventsPage / SkillsPage + // / CronPage entries above. The Description_Format key takes the WSL + // distro name as {0} and is formatted in ConnectionPage.xaml.cs. + "ConnectionPage_GatewayHostControlsDescription_Format", + // GatewayHostAccess plan strings (terminal label / tooltip / disabled + // reasons). Resolved in the classifier via LocalizationHelper so the + // OpenTerminal button and any consumers of DisabledReason show + // localized text. + "GatewayHostAccess_OpenTerminalLabel", + "GatewayHostAccess_OpenSshTerminalLabel", + "GatewayHostAccess_OpenTerminalInWslTooltip_Format", + "GatewayHostAccess_OpenSshTerminalTooltip_Format", + "GatewayHostAccess_NoTerminalAccess", + "GatewayHostAccess_NoWslOrSshDisabled", + "Command_GoToConnection_Title", + "Command_GoToConnection_Subtitle", + "Command_GoToChat_Title", + "Command_GoToChat_Subtitle", + "Command_GoToSessions_Title", + "Command_GoToSessions_Subtitle", + "Command_GoToAgentEvents_Title", + "Command_GoToAgentEvents_Subtitle", + "Command_GoToSkills_Title", + "Command_GoToSkills_Subtitle", + "Command_GoToCron_Title", + "Command_GoToCron_Subtitle", + "Command_GoToWorkspace_Title", + "Command_GoToWorkspace_Subtitle", + "Command_GoToChannels_Title", + "Command_GoToChannels_Subtitle", + "Command_GoToInstances_Title", + "Command_GoToInstances_Subtitle", + "Command_GoToConfig_Title", + "Command_GoToConfig_Subtitle", + "Command_GoToUsage_Title", + "Command_GoToUsage_Subtitle", + "Command_GoToBindings_Title", + "Command_GoToBindings_Subtitle", + "Command_GoToPermissions_Title", + "Command_GoToPermissions_Subtitle", + "Command_GoToSettings_Title", + "Command_GoToSettings_Subtitle", + "Command_GoToDiagnostics_Title", + "Command_GoToDiagnostics_Subtitle", + "Command_GoToInfo_Title", + "Command_GoToInfo_Subtitle", + "Command_OpenChatWindow_Title", + "Command_OpenChatWindow_Subtitle", + "Command_OpenDashboard_Title", + "Command_OpenDashboard_Subtitle", + "Command_ToggleNodeMode_Title", + "Command_ToggleCamera_Title", + "Command_ToggleCanvas_Title", + "Command_ToggleScreenCapture_Title", + "Command_ToggleBrowserControl_Title", + "Command_Subtitle_CurrentlyOn", + "Command_Subtitle_CurrentlyOff", + "CommandCenter_AuthFailed", + "CommandCenter_NodePendingApproval", + "CommandCenter_GatewayConnectionError", + "CommandCenter_GatewayNotConnected", + "CommandCenter_GatewayHealthStale", + "CommandCenter_NoChannelsReported", + "CommandCenter_WaitingForGatewayHealth", + "CommandCenter_NoChannelsRunning", + "CommandCenter_NoNodesReported", + "CommandCenter_UsageCostsMissing", + "CommandCenter_BrowserProxyAuthMayNeed", + "CommandCenter_SshTunnelPortNotListening", + "CommandCenter_NoLocalGatewayListener", + "CommandCenter_BrowserProxySshForwardNotListening", + "CommandCenter_BrowserProxyHostNotDetected", }; private static readonly string[] RequiredRuntimeOnboardingKeys =