Skip to content

Translate the app menu's standard items, which Electron labels in English - #664

Merged
ryanwelcher merged 1 commit into
trunkfrom
fix/translate-menu-role-labels
Oct 8, 2026
Merged

ryanwelcher merged 1 commit into
trunkfrom
fix/translate-menu-role-labels

Conversation

@ryanwelcher

Copy link
Copy Markdown
Collaborator

Why

The app menu is built from Electron roles, and a role item takes its label from Electron's own English. So only three items were translated (Settings…, Open App Log, Show Logs Folder). Every menu title and every other item stayed in English in every language. Found in the en-XA walk.

What changes

Root cause: role items had no label, so Electron filled in its English default.

  • Every item in src/menu.js now has a label: __('…'). The role still supplies the action and the shortcut, and only the label is overridden.
  • A role that is given a submenu loses its default items. So Edit, View and Window, and File on macOS, are now written out item by item, matching Electron 43.6.0's defaults for each platform. That includes Edit's Substitutions and Speech submenus on macOS.
  • Each label uses Electron's wording for its platform. On macOS, About, Hide and Quit name the app (sprintf with a translator comment, with app.name passed in from main.js). Quit is "Exit" on Windows and "Quit" on Linux. Window's "Close" is "Close Window" under File on macOS. Window › Zoom gets a context (_x), because on macOS it means filling the screen.
  • The menu titles File, Edit, View, Window and Help are labelled too. The macOS app menu gets no label, because macOS always titles it with the app's name.

How to test this

Platforms: both macOS and Windows, because each has its own set of items. Build: the Buildkite artifact for the current head commit, or a local run from the repository root as described below.

The journey the app menu and the native file dialogs are translated in main in tests/e2e/journeys/i18n.spec.js walks the whole application menu under en-XA. It fails if any item that is not a separator lacks the pseudo-locale brackets. On trunk it is red and lists 41 untranslated items. Run it from the repository root:

npx playwright test --project=journeys -g "the app menu and the native"

That journey runs on the platform it is launched on, so it covers macOS and Windows in CI. It cannot show that the shortcuts and native items still behave the same, so check that by hand:

Starting state: any state. From the repository root, run npm run build:once, then npx electron . --lang=en-XA.

  1. Open each menu: the app menu (macOS), File, Edit, View, Window and Help. Every item except the macOS app menu's title is bracketed and accented, for example [Úñðó~~], including Edit › Substitutions and Edit › Speech and their items on macOS.
  2. On macOS, the app menu's About, Hide and Quit items contain the app's name inside the brackets.
  3. Click into a text field, type a word, and press Cmd/Ctrl+Z. The word is undone. Press Cmd/Ctrl+A, then Cmd/Ctrl+C, and paste somewhere else. The text is pasted.
  4. Press Cmd/Ctrl+Plus, then Cmd/Ctrl+0. The window zooms in, then goes back to actual size.
  5. Quit the app and run npx electron . with no --lang. Every item reads in plain English, with the same wording as on trunk.

What must not have happened:

  • No item from the old menu is missing on either platform. Compare against trunk: macOS Edit still has Paste and Match Style, Substitutions and Speech, and macOS Window still has Bring All to Front. Windows Window still has Close, and Windows File still ends with Exit.
  • No shortcut is gone from any item (for example ⌘H on Hide, Ctrl+Shift+I on Toggle Developer Tools on Windows).
  • On macOS, the Window menu still lists the open windows, and Help still has its search field. Both depend on the roles, which are kept.

Risks and limitations

  • The menus now copy Electron 43.6.0's default item lists instead of inheriting them. If a future Electron changes its defaults, this menu will not follow. tests/unit/menu.test.cjs pins the lists per platform, and Electron is pinned anyway (see AGENTS.md).
  • The unit tests check exact wording only for About, Hide and Quit. Every other label was compared with Electron's source by hand.
  • Items that macOS itself adds to the Edit menu (such as Start Dictation and Emoji & Symbols) come from the OS, in the OS's language, and are outside this change.
  • Self-review: no findings.

Related

Fixes #657. Part of #622.


Design decisions and alternatives considered
  • app.name is passed in, not imported. menu.js stays free of Electron imports, as its header says, so main supplies the name the same way it supplies the click handlers. It is the same value Electron's own labels use: the package name in development and the product name when packaged.
  • _x only for Zoom. "Close" and "Copy" share an msgid with the renderer and mean the same thing there. On macOS, Zoom in the Window menu means filling the screen, not zooming in, so translators need the context.
  • One shared toggleDevTools entry for View and Help, as the Settings… item is shared. buildFromTemplate makes a separate MenuItem from each entry.
Review outcome (required — see AGENTS.md)

0 [fix here] · 0 [follow-up].

  • Review: completed by a separate agent with fresh context. Covered the working-tree changes later committed as e3eeeb6, on head 4835fba and base origin/trunk 4835fba. It checked every item, order, separator and label against Electron v43.6.0's menu-item-roles.ts, checked that accelerators and actions still come from the role, checked that the translator comments and the msgctxt reach the .pot, and checked that the tests fail on the old code. Outcome: no findings across the five dimensions. Style notes: (1) only About, Hide and Quit have their exact wording pinned by a unit test; (2) appName defaults to '', so a future caller that leaves it out would get "About " on macOS (main.js is the only caller and passes it). Both were left as they are.
  • Since review: the reviewed working tree was committed unchanged as e3eeeb6.
  • CodeRabbit: not requested yet.
Implementation notes
  • Electron's role definitions: lib/browser/api/menu-item-roles.ts at v43.6.0. menu-item.ts applies the role's default label only when no label is given, and always applies the role's accelerator.
  • Tests:
    • tests/unit/menu.test.cjs pins each menu's items per platform, the app-named and per-platform quit labels, and checks under the pseudo-locale that every label is bracketed. 4 of its 11 tests fail on trunk.
    • The en-XA journey walks the real Menu.getApplicationMenu().
  • Commands run, from the repository root:
    • npm run lint: clean.
    • npm test: 2093 pass, 0 fail, 2 skipped.
    • npm run test:electron: 2094 pass, 0 fail, 1 skipped.
    • npx playwright test --project=journeys tests/e2e/journeys/i18n.spec.js: 32 passed.
    • npx playwright test --project=journeys tests/e2e/journeys/settings.spec.js, which opens Settings from the menu: 6 passed.
Screenshots or recording

To add: the Edit and Window menus under --lang=en-XA, on macOS and on Windows.

🤖 Generated with Claude Code

…lish

A menu item built from a role takes its label from Electron's own English defaults, so only Settings…, Open App Log and Show Logs Folder were translated. Every menu title and every other item stayed English in every language.

Each item now has a label of ours, and the role still supplies its action and shortcut. Giving a role a submenu drops its default items, so Edit, View, Window and File on macOS are written out item by item as Electron 43 has them on each platform, with About, Hide and Quit naming the app as Electron's labels do. The en-XA journey now checks every menu item that is not a separator.

Fixes #657
@coderabbitai

coderabbitai Bot commented Oct 8, 2026 •

Copy link
Copy Markdown

Warning

Review limit reached

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Next included review available in 46 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used the included review currently available.

Learn how review limits work.

Review configuration:

⚙️ Run configuration
  • Configuration used: Repository: WordPress/contributor-toolkit/.coderabbit.yaml
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 80ef46ec-74ce-47a7-ae1e-96c62c5bb9ec
📥 Commits

Reviewing files that changed from the base of the PR and between 4835fba and e3eeeb6.

📒 Files selected for processing (4)
  • src/main.js
  • src/menu.js
  • tests/e2e/journeys/i18n.spec.js
  • tests/unit/menu.test.cjs
  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@ryanwelcher

Copy link
Copy Markdown
Collaborator Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Oct 8, 2026 •

Copy link
Copy Markdown
⚠️ Action not completed

Review rate limited.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@ryanwelcher
ryanwelcher requested a review from zaerl October 8, 2026 13:25

@zaerl zaerl left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tested on macOS and Windows. 👍

@ryanwelcher
ryanwelcher merged commit 7ee3ead into trunk Oct 8, 2026
13 checks passed
@ryanwelcher
ryanwelcher deleted the fix/translate-menu-role-labels branch October 8, 2026 14:01
ryanwelcher added a commit that referenced this pull request Oct 13, 2026
## Why

41 commits have reached trunk since `v1.2.1`, and milestone
`v2.0.0-beta.1` has 77 closed issues and none open. The main changes are
the redesign on the WordPress Design System (#591), a settings dialog
with language, theme, PHP version and debug flags (#638 to #651), and
translation of the whole interface (#634 to #664). This is a beta: it
ships with `--prerelease`, so `releases/latest` stays on `v1.2.1`.

`electron-builder` names the artifacts after `package.json`, so the
version has to move before the tag and artifacts exist.

## What changes

- **The version.** The three root version fields in `package.json` and
`package-lock.json` move from `1.2.1` to `2.0.0-beta.1`. No dependency
versions change.
- **The first shipped translations.** `npm run i18n:download` added a
catalog for each of the seven locales at 80% or more on
translate.wordpress.org. None was removed, and no right-to-left locale
was held back.

| Locale | Translated | Strings |
| --- | --- | --- |
| cs | 94% | 1001 |
| en-ca | 100% | 1062 |
| en-gb | 100% | 1062 |
| gl | 100% | 1062 |
| hu | 100% | 1062 |
| nl | 100% | 1062 |
| pl | 96% | 1028 |

## How to test this

**Platforms:** any for steps 1 to 3. The artifact checks need macOS for
`Info.plist` and Windows for the `.exe`.

**Starting state:** this branch checked out with `node_modules`
installed. Run every command from the repository root.

1. `npm run lint` is clean and `npm test` passes.
2. `node -e "console.log(require('./package.json').version)"` prints
`2.0.0-beta.1`.
3. `python3 -c "import
json;d=json.load(open('package-lock.json'));print(d['version'],
d['packages']['']['version'])"` prints `2.0.0-beta.1 2.0.0-beta.1`.
4. On the Buildkite build for the current head, the artifacts are named
`wordpress-contributor-toolkit-2.0.0-beta.1-*`. The `app.asar` root
holds exactly `node_modules`, `package.json` and `src`, with npm 11
under `node_modules/npm` and no `.codesigning`. On macOS,
`CFBundleShortVersionString` reads `2.0.0-beta.1`.
5. In the installed app, set the language to Dutch in the settings and
relaunch. The interface is in Dutch.

**What must not have happened:** no dependency version may change. `git
diff trunk -- . ':!src/languages'` shows exactly three changed lines,
all of them the root version.

## Risks and limitations

`npm test` run from an interactive terminal fails two integration tests
on macOS. That is a test bug, fixed separately in #680. It does not
affect CI or the app.

## Related

Milestone `v2.0.0-beta.1`. Release notes follow on the release.

---

<details>
<summary>Review outcome (required — see AGENTS.md)</summary>

0 [fix here] · 0 [follow-up]. Automatic checks only, as in #533: this
change has no logic to review.

- **Review:** completed, deterministic layer, in session; head `9853082`
/ base `5d5f701` (trunk). `npm run lint` passes, `npm test` passes (2098
tests, 0 failures, 2 skipped), both files are valid JSON, and the diff
outside `src/languages/` is the three root version fields. Outcome:
nothing to fix.
- **Since review:** none.

</details>

🤖 Generated with [Claude Code](https://claude.com/claude-code)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

i18n: Translate the app menu's standard items, which Electron labels in English

2 participants