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, "&", "&&") +}