From 49df24b18ccc74f5c7e4ff4d0fbd4277129760d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zolt=C3=A1n=20Papp?= Date: Mon, 1 Jun 2026 16:44:18 +0200 Subject: [PATCH] escape ampersand in tray menu labels on Windows Win32 swallows a lone & in an MFT_STRING menu item as the mnemonic prefix, so "Help & Support" rendered as "Help Support". Add a build-tagged menuLabel() helper that doubles & to && on Windows and is the identity on macOS/Linux (which render & literally), and apply it to the About submenu label. --- client/ui/tray.go | 2 +- client/ui/tray_label_other.go | 9 +++++++++ client/ui/tray_label_windows.go | 16 ++++++++++++++++ 3 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 client/ui/tray_label_other.go create mode 100644 client/ui/tray_label_windows.go diff --git a/client/ui/tray.go b/client/ui/tray.go index 6c9912bc5..9cf52e89b 100644 --- a/client/ui/tray.go +++ b/client/ui/tray.go @@ -459,7 +459,7 @@ func (t *Tray) buildMenu() *application.Menu { SetAccelerator("CmdOrCtrl+,"). OnClick(func(*application.Context) { t.svc.WindowManager.OpenSettings("") }) - aboutLabel := t.loc.T("tray.menu.about") + aboutLabel := menuLabel(t.loc.T("tray.menu.about")) about := menu.AddSubmenu(aboutLabel) about.Add(t.loc.T("tray.menu.github")).OnClick(func(*application.Context) { _ = t.app.Browser.OpenURL(urlGitHubRepo) diff --git a/client/ui/tray_label_other.go b/client/ui/tray_label_other.go new file mode 100644 index 000000000..7274fbb69 --- /dev/null +++ b/client/ui/tray_label_other.go @@ -0,0 +1,9 @@ +//go:build !windows && !android && !ios && !freebsd && !js + +package main + +// menuLabel is the identity on macOS and Linux — both render an ampersand +// literally in tray-menu labels, so no escaping is needed. Windows opts in via +// the sibling tray_label_windows.go file, where a lone "&" would otherwise be +// swallowed as a Win32 mnemonic prefix. +func menuLabel(s string) string { return s } diff --git a/client/ui/tray_label_windows.go b/client/ui/tray_label_windows.go new file mode 100644 index 000000000..f0e575820 --- /dev/null +++ b/client/ui/tray_label_windows.go @@ -0,0 +1,16 @@ +//go:build windows + +package main + +import "strings" + +// menuLabel escapes a tray-menu label for Win32. A single ampersand in an +// MFT_STRING menu item is consumed as the mnemonic (accelerator) prefix and +// never painted — so "Help & Support" renders as "Help Support". Doubling it +// to "&&" tells Win32 to draw a literal ampersand. Wails v3 passes the label +// straight to InsertMenuItem without escaping (see menuitem_windows.go), so we +// do it here. macOS/Linux render "&" literally and use the identity helper in +// the sibling tray_label_other.go. +func menuLabel(s string) string { + return strings.ReplaceAll(s, "&", "&&") +}