Skip to content

Translate the Terminal and Logs output - #646

Open
ryanwelcher wants to merge 4 commits into
trunkfrom
fix/627-terminal-and-logs-strings
Open

ryanwelcher wants to merge 4 commits into
trunkfrom
fix/627-terminal-and-logs-strings

Conversation

@ryanwelcher

@ryanwelcher ryanwelcher commented Oct 6, 2026 •

Copy link
Copy Markdown
Collaborator

Why

The Terminal and the Logs were plain English in a translated window: the terminal's help and refusals, every line the setup, update and apply chains write there, the build watch and dev server lines, the Logs' tabs and empty-pane notes, and main's own lines from the trunk update, the pull request switch, the npm runner and the server start. This is the #627 batch of #622.

What changes

  • Every line written to the Terminal or a Logs pane goes through __/_n/sprintf, with commands, paths, keys and file names passed in as %s. Each line is one or more whole sentences, so the terminal can show a translated line on its own.
  • Sentences that were spliced together are written whole. The apply chain built "The ${noun} is ${verb}" and "${verb} — …" from five verb and noun pairs; it is now a table of whole sentences per pair (applyLines in watch-activity.cjs), the way applyDoneMessage in confirmations.cjs works. applyFinishMessage used to regex the English "— open the site to try it out." out of a line; the caller now passes the line without it. The switch progress (switch-progress.cjs), the setup's Status: ${phase}, main's Update failed during ${stage} and the npm "letting go" line each get one sentence per case.
  • Inline markup (the hints under the terminal, the empty Logs panes) uses createInterpolateElement, with npm run build, help, Ctrl+C, package.json, src/, build/ and error_log() passed in as elements.
  • The dev server's "see Help → Open App Log" takes the menu item as %s, from the same __('Open App Log') the menu uses (left over from Load the translation catalog in main, and translate the menu and dialog titles #634).
  • Module-level constants became functions: COPY_BUTTON_LABELS, SETUP_END_MESSAGES and the setup status line move from index.jsx to confirmations.cjs as copyButtonLabel, setupEndMessage and setupStatusLine, where the suite can reach them; STALE_ASSETS and main's ENGINE_RETRY_NOTICE become functions too.

110 new strings. Not wrapped, per #622 or because the text is not ours: Git's own progress phases (Updating files 3/10), npm's and the server's output, the stub appendNpm buffer nothing shows, the 42% progress figure, and the lines owned by sibling batches (SKIP_INSTALL_MESSAGE and the dirty-tree errors are #626's in #636; the patch apply lines in main are #628's; the blocked-site errors are #629's).

How to test this

The new journeys cover both trays in the pseudo-locale. Run them from the repository root, on either platform:

npx playwright test --project=journeys tests/e2e/journeys/i18n.spec.js -g "Terminal is fully|Logs are fully"

Both fail without this change (checked by stashing src/ and rebuilding). The Terminal journey opens the tray on a built site, reads the help printed at start, types help and an unknown command, joins the terminal's rows into whole lines and checks every printed line starts with [, then scans the hints under it. The Logs journey scans the empty Build watch and Debug.log panes, starts the dev server with stubbed handlers so the watch starts and the server refuses, and scans the server's failure line, the watch's start and exit lines and the tab titles as they change.

What the journeys cannot reach: they stub IPC, so main's lines (trunk update, PR switch, npm runner, server start) never reach the screen in them, and neither do the apply, update and setup chains, which need a real install and build. Unit tests cover those in the pseudo-locale instead: watch-activity, update-handoff, dev-server-command, switch-progress, confirmations, trunk-update-fetch.integration and three in ipc-wiring (the server's start failure, the trunk update's failure lines and the engine retry notice). To see the chains on screen by hand (either platform, current head):

  1. From the repository root, run npx electron . --lang=en-XA.
  2. Open a built Core site, open the Terminal tray and type help.
    • Expected: every line except the $ prompt is accented and in brackets, and the help's descriptions still start in one column.
  3. Click Update to latest trunk (in its pseudo-localised form) and let it run.
    • Expected: the lines the app writes ("Fetching latest trunk…", "Now on trunk as of …", "Running npm run build…", "Update complete — …") are bracketed; Git's and npm's own output is not.

What must not have happened: no English an English speaker sees has changed, apart from the one line break and the one plural named in Risks. All 132 journeys pass with their exact English strings, including terminal.spec.js, tray.spec.js, logs.spec.js, build-watch.spec.js and dev-server.spec.js.

Risks and limitations

Related

Fixes #627. Part of #622. Follows #634 and #635.


Design decisions and alternatives considered
  • The help's columns. Each help line is one string, %s Show this help text, with the command padded into %s, so every printed line opens with the translated string's bracket and the descriptions still line up after the command column. The alternative, a translated description after an untranslated command, would leave each line starting in English.
  • The apply sentences as a table, not a frame like "%1$s but the build failed": a translation cannot rely on "The patch is applied" fitting in front of "but". The two Restored lines share their English but have a _x context per noun, so a language with gendered participles can say them differently.
  • "Start the build watch, or run %s in the Terminal." is its own sentence after the one saying the site still runs the old assets, instead of being copied into ten strings.
  • Setup status per phase: main sends only cloning and done; each gets its own line and anything else says "Status update", where it used to print the code.
  • Debug.log and Debug.log (%d) are wrapped so a translator can name the tab in their language; the file name in sentences is left as is.
Review outcome (required — see AGENTS.md)

3 [fix here] · 3 [follow-up]. All 3 [fix here] findings are fixed.

  • 🟡 copyButtonLabel, setupStatusLine and setupEndMessage were branches choosing user-facing sentences inside index.jsx, which the suite cannot load. Fixed: moved to confirmations.cjs with a test in English and in the pseudo-locale.

  • 🔵 engineRetryNotice was made a function so it is translated when shown, and nothing checked it. Fixed: an ipc-wiring test drives the engine retry in the pseudo-locale.

  • 🔵 The Terminal journey dropped any line starting with [, so translated text followed by English would pass. Fixed: each line must be one bracketed string from its first character to its last.

  • Follow-up: the apply flow in the terminal is still partly English (main's "Applying …" line, patch-apply.js, SKIP_INSTALL_MESSAGE). Those belong to Translate patch and pull request apply failures #628 and Translate the setup checklist and the trunk update banners #626 (Translate the setup checklist and the trunk update banners #636), not this batch.

  • Follow-up: the five compiling sentences in applyLines repeat compilingMessage()'s text, on purpose, so each can be translated whole; the test now pins all five against compilingMessage().

  • Follow-up: npmLetGoLine reads process.platform, so only one platform's branch runs in a test. The split was already inline before this branch; injecting the platform is a separate change.

  • One review note was checked and not taken: it said the renderer no longer imports switch-progress.cjs, but index.jsx still does, so that module's header comment stays.

  • Review: completed. Fresh agent context (Explore subagent given the diff and the review instructions), head c7a1ba8 / base 9fd167e. Lint clean, npm test passing, read-only, so it did not run the journeys.

  • Since review: c7a1ba8 → 274bb2d. The review fixes above, then a rebase onto trunk e94f507 after Translate the Review & submit dialog #635 merged (only i18n.spec.js conflicted: both appended tests). Checked by the authoring session, not re-reviewed by a fresh context: npm run lint clean, npm test 2044 pass / 0 fail, all 132 journeys pass, npm run i18n:pot clean.

  • After CI: 274bb2d → 6179bd9. The Terminal journey failed on CI's macOS runner: it waited for the help's first line, which on that window had scrolled out of the rows xterm draws, because pseudo-locale lines are longer and wrap. It now waits for the help's last line. Reproduced locally at 1024×640 (failed before, passes after). Test-only change, checked by the authoring session, not re-reviewed: the i18n and terminal journeys pass (20).

Screenshots or recording

None. Nothing changes on screen in English beyond the help's line break, and the pseudo-locale journeys are the check for the translated state.

🤖 Generated with Claude Code

Every line the app writes in the Terminal and in the Logs' panes goes
through the translation functions: the terminal's help and refusals, the
setup, update and apply chains, the build watch and dev server lines, the
Logs tabs and empty-pane notes, the switch progress, and main's lines from
the trunk update, the pull request switch, the npm runner and the server
start.

Sentences built from a verb and a noun, a stage code or a phase code are
written whole, one per case. The dev server's "see Help → Open App Log"
names the menu item by the string the menu uses.

Fixes #627.
…ighten the tests from the review

The three sentences chosen by a branch in index.jsx move to a module the
suite can load, with a test. The Terminal journey checks each printed
line is one bracketed string whole, the engine retry notice gets an
ipc-wiring test, and every apply line's compiling sentence is pinned to
compilingMessage().
@coderabbitai

coderabbitai Bot commented Oct 6, 2026 •

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration
  • Configuration used: Repository: WordPress/contributor-toolkit/.coderabbit.yaml
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 403b4e4f-b753-4506-8d36-8d6cfbd14bec

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
  • 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.

xterm draws only the rows on screen. In the pseudo-locale the help's
lines are longer and wrap, so on CI's macOS window its first line had
scrolled out of view and the journey timed out waiting for it.
@ryanwelcher

Copy link
Copy Markdown
Collaborator Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Oct 6, 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 added a commit that referenced this pull request Oct 6, 2026
## Why

The Open a pull request card, its GitHub sign-in, and the errors main
sends it were plain English in a translated window. This is the #625
batch of #622, which needed the catalog in main from #634.

## What changes

- **The card** (`pull-request-destination.jsx`) wraps every string.
Sentences with a link or code in them use `createInterpolateElement`,
with logins, branches and repository names passed in as elements so they
are never read as markup. The failure messages are a function instead of
a module-level constant.
- **Per-project text** in `project-type.cjs` (`cards.*`) is getters,
read when the card renders. Main's refusal with nothing linked used to
splice the work item's label into a sentence; it is now
`cards.prNeedsWorkItem`, one sentence per project type.
- **Main process:** the sign-in errors in `github-auth.cjs` and the pull
request errors in `github-pr.cjs` are wrapped, including the step labels
passed to `failure()`, which the issue did not list. The "Trunk has
moved" message uses `_n`, and a GitHub failure is composed with `%1$s:
%2$s%3$s` so a translator can change the punctuation. GitHub's own
reason and the bracketed diagnostic for GitHub support stay as they are.

Not wrapped, per #622: the pull request body and the default pull
request title, because they leave the app.

## How to test this

The new journeys cover the card in the pseudo-locale on both projects.
Run them from the repository root on either platform:

```
npx playwright test --project=journeys tests/e2e/journeys/i18n.spec.js -g "pull request card"
```

Both fail without this change. The Core journey walks every state #625
lists: signed out, "Not now" and "Show this again", the device code,
signed in with the form and its fold, a `rate-limited` failure, a dry
run, and a pull request opened from a checkout behind trunk. The
Gutenberg one walks signed out, signed in with the fold open, and the
opened pull request, checking the words that are Gutenberg's own.

What the journeys cannot reach is a real GitHub. They stub every
`github:*` handler, so the main-process errors never reach the screen in
them. Unit tests in `github-auth`, `github-pr` and `pr-stage` cover
those strings in the pseudo-locale instead. To see one on screen by hand
(either platform, current head):

1. From the repository root, run `npx electron . --lang=en-XA`.
2. Open a Core site with a linked ticket and an edit, and click **Review
& submit changes**.
3. In **Open a pull request**, click **Sign in with GitHub** and finish
in the browser.
- Expected: every line of the card is accented and in brackets, apart
from your login, your fork's name, the code and the branch.

**What must not have happened:** no English an English speaker sees has
changed. The English journeys in `open-pull-request.spec.js`,
`review-changes.spec.js` and `pr-checkout.spec.js` still pass with their
exact strings.

## Risks and limitations

- The other open batches (#636, #644, #645, #646) also append tests to
the end of `i18n.spec.js`, so whichever merges later resolves that by
keeping both.
- One finding is deferred: `prFailureMessage` decides between five
user-facing strings inside a `.jsx` file the suite cannot load. It
predates this PR (it was the old constant map), so moving it to a `.cjs`
module with a test is a follow-up.

## Related

Fixes #625. Part of #622. Follows #634.

---

<details>
<summary>Design decisions and alternatives considered</summary>

- **Not stacked on #635.** #622 asks for batches that review on their
own. Now that #635 has merged, its `unwrapped()` scanner change and the
`@wordpress/element` dependency, which this PR also needed, come from
trunk.
- **The textarea placeholder** is three strings joined with a newline. A
single `__()` with `\n` in it is refused by
`@wordpress/i18n-no-collapsible-whitespace`.
- **"Signed in as …"** is wrapped in its own `<span>`, so the sentence
and the **Sign out** button beside it are separate elements, as in #635.

</details>

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

2 [fix here] · 1 [follow-up]. Both [fix here] findings are fixed; the
follow-up is deferred (see Risks).

- 🟡 The Gutenberg journey linked no issue, so it never showed the form,
the fold or the loop-back. Fixed: it links one in the record and walks
those states.
- 🔵 No test showed the main-process strings or the stage labels come out
translated. Fixed: pseudo-locale unit tests for the scope refusal, a
composed `failure()`, the plural stale message and `prStageLabel`.
- Style: three dead entries in the journey's `THEIRS` filter were
removed.

- **Review:** completed. Fresh agent context, head `11ef362` / base
`c34aa45`. `npm run lint` clean, `npm test` 2002 pass / 0 fail, i18n and
PR journeys 25 pass.
- **Since review:** `11ef362 → ef457fd`. The only change is the test
fixes above, checked by the authoring session, not re-reviewed by a
fresh context. `src` and `tests` lint clean, unit suite 2005 pass / 0
fail, i18n journeys 12 pass. The review did not run the journeys itself;
it was read-only.
- **After #635 merged:** `ef457fd → 9559a1f` (trunk merged from GitHub)
→ `012fca8` (trunk at `e94f507` merged; `i18n.spec.js` resolved as
trunk's file plus this PR's two tests, nothing else changed). Checked by
the authoring session, not re-reviewed: `src` and `tests` lint clean,
unit suite 2036 pass / 0 fail, i18n, open-pull-request, review-changes
and pr-checkout journeys 31 pass.

</details>

<details>
<summary>Screenshots or recording</summary>

None. Nothing changes on screen in English, and the pseudo-locale
journeys are the check for the translated state.

</details>

🤖 Generated with [Claude Code](https://claude.com/claude-code)
…-logs-strings

# Conflicts:
#	tests/e2e/journeys/i18n.spec.js

This branch has not been deployed

No deployments
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.

Translate the Terminal and Logs output

1 participant