Skip to content

Translate the line a screen reader says before each announcement - #654

Merged
ryanwelcher merged 1 commit into
trunkfrom
fix/648-a11y-intro-text
Oct 7, 2026
Merged

ryanwelcher merged 1 commit into
trunkfrom
fix/648-a11y-intro-text

Conversation

@ryanwelcher

Copy link
Copy Markdown
Collaborator

Why

Before each announcement, a screen reader reads a hidden line that @wordpress/a11y adds to the page: "Notifications". The package writes it at DOM-ready, which is before the renderer has loaded its locale from main, so it stayed English in every language.

What changes

Once loadLocale() has applied the locale, it writes that line again with __('Notifications'), next to where it already sets the window's title. It uses the same msgid as @wordpress/a11y and as the notifications region's label, so all three share one translation.

If the paragraph were ever created after the locale loads instead, a11y's own __() would already be translated, and the null check skips the rewrite.

How to test this

A journey covers it, and it's red without the change:

# from the repository root
npm run build:once
npx playwright test --project=journeys tests/e2e/journeys/i18n.spec.js -g "first-run screen"

The first-run en-XA journey now checks that #a11y-speak-intro-text reads [Ñóţíƒíçáţíóñš~~~~]. Without the fix it reads "Notifications".

To look by hand (any platform, current head): run npx electron . --lang=en-XA from the repository root and inspect #a11y-speak-intro-text in DevTools. It's bracketed and accented.

What must not have happened: in English the line still reads "Notifications", and announcements (speak()) still work. The full journey suite passes (147/147).

Risks and limitations

None known. The paragraph lives outside #root, so React never replaces it, and a11y's speak() and clear() only toggle its hidden attribute.

Related

Fixes #648. Part of #622.


Review outcome

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

  • Review: completed by a separate agent with a fresh context, against .github/instructions/code-review.instructions.md. Reviewed head d6ce1eb, base 8303849 (trunk). npm run lint clean, npm test 2078/2078, full journey suite 147/147.
  • Checked:
    • Order: the bundle is loaded with defer, so domReady runs a11y's setup() while it loads, before the locale arrives. The paragraph exists when it's rewritten.
    • Duplicates and resets: the paragraph can't be created twice, and nothing writes English back to it.
    • One copy: there's one copy each of @wordpress/a11y, @wordpress/i18n and @wordpress/hooks, so a11y uses the app's i18n instance.
    • Shared msgid: sharing 'Notifications' with the toast region's label is correct.
    • Module rule: a fixed DOM write beside document.title isn't a decision that belongs in a .cjs module.
    • Journey: it waits for the first render, so it can't race the rewrite.
  • Style note, not applied: the test comment says the scans miss the paragraph because it's hidden. It's also outside #root, which the scans don't look past.
  • Since review: none.

Nothing on screen changes, so there are no screenshots.

🤖 Generated with Claude Code

@wordpress/a11y writes it at DOM-ready, before the renderer has a
locale, so it stayed English in every language. It is written again
once the locale is applied, beside the window's title.

Fixes #648.
@coderabbitai

coderabbitai Bot commented Oct 7, 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 38 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: 590dc788-0dea-4aaa-bcb1-4e3a8a163a56
📥 Commits

Reviewing files that changed from the base of the PR and between 8303849 and d6ce1eb.

📒 Files selected for processing (2)
  • src/renderer/index.jsx
  • tests/e2e/journeys/i18n.spec.js
  • 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 7, 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 merged commit c328144 into trunk Oct 7, 2026
8 checks passed
@ryanwelcher
ryanwelcher deleted the fix/648-a11y-intro-text branch October 7, 2026 16:45
ryanwelcher added a commit that referenced this pull request Oct 8, 2026
…wn (#660)

## Why

Every pull request runs the unit suite and the E2E journeys and packaged
smoke on macOS and Windows, and all six checks are required to merge. A
pull request that only changes Markdown (README, RELEASING.md, AGENTS.md
and the like) waits on all of them even though nothing they test has
changed.

## What changes

A pull request whose changed files all end in `.md` skips the unit
suite, the journeys and the packaged smoke, and still merges.

`paths-ignore` cannot do this. A workflow it skips never reports its
checks, so the required ones would sit at "pending" and block the merge.
Instead, each workflow gets a small `changes` job on Linux that reads
the PR's file list from the API. When only Markdown changed, `*-skipped`
stub jobs report the same required check names as passed, and the real
jobs are skipped. Pushes to trunk always run everything.

Deliberately not in it: anything under `docs/` that is not Markdown
(`tests/unit/download-button-platform.test.cjs` reads
`docs/.vitepress/theme`), screenshots, and Lint, which is quick and also
required.

## How to test this

Platforms: none, this is CI only. The checks on this PR and the next
Markdown-only PR are the test.

**Starting state:** this PR, which changes two workflow files.

1. Look at the checks on this PR. Expected: `changes` reports
`code=true`, and the real `unit`, `Journeys` and `Packaged smoke` jobs
run on macOS and Windows.
2. On a Markdown-only PR opened after this merges (or a throwaway one
against this branch), look at the checks. Expected: the six required
checks show as passed within about a minute, each from a job that prints
"Only Markdown changed", and no macOS or Windows runner starts.
3. Edit that PR's title. Expected: a new run appears with every job
skipped, and the six required checks keep their earlier passes.

**What must not have happened:**

- A PR with any non-Markdown file skipping a suite. The file test was
checked by hand for Markdown only, Markdown plus `.js`, a VitePress
config change, an empty list and a `.js` file renamed to `.md`, and
against the real file lists of #546 (Markdown only, skips) and #654
(code, runs).
- A required check left at "pending" on a Markdown-only PR.
- A title edit cancelling a suite that is still running.

**Cannot be tested here:** the base-move case below needs a stacked pair
of PRs to retarget, which I did not stage.

## Risks and limitations

- If the `changes` job fails (for example the API call errors), both the
real and the stub jobs skip, so the required checks stay pending. That
blocks the merge rather than letting it through, and re-running the
workflow clears it.
- Moving a PR's base re-runs `changes`. Without that, a Markdown-only PR
stacked on a code PR and moved onto trunk by hand would keep its stub
passes while its diff now contains the lower PR's code. The workflows
now listen for `edited` and act only when the base changed. One
unverified detail: whether the PR's file list already reflects the new
base when the `edited` run starts.
- The `changes` script is copied into both workflows rather than shared.
Sharing it would mean a composite action for twenty lines.
- Pre-PR review: 1 finding, fixed (see below).

## Related

None.

---

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

- **`paths-ignore` / `paths`:** rejected, the required checks would
never report.
- **A job-level `if:` on the existing matrix jobs alone:** rejected. A
skipped matrix job is not expanded, so it reports one check named
literally `Journeys (${{ matrix.os }})`, and the required `Journeys
(macos-latest)` never appears. This is already what happens to drafts
today (see #283's checks).
- **A step-level `if:` on every step of the real jobs, with `runs-on`
falling back to Linux:** works, but every new step would need the guard,
and a missed one would run `npm ci` on the wrong runner. The stub jobs
keep the real jobs unchanged apart from `needs` and `if`.
- **Changing the ruleset to require one gate job per workflow:** needs
an admin change to the ruleset and moves the required names; the stubs
need neither.
- **`dorny/paths-filter`:** a third-party action holding a token, for
something `gh api` does in one call.

</details>

<details>
<summary>Review outcome</summary>

1 [fix here] after promotion · 0 left open. Lint clean; unit suite 2081
pass, 0 fail, 2 skipped (local, macOS).

- **Review:** completed, separate agent context, head `ee41b6d` / base
`6d5f334`. One 🟡 finding, raised as follow-up and fixed here at the
author's request: a Markdown-only stacked PR moved onto trunk by hand
kept its stub passes, since neither workflow listened for `edited`. Also
noted, left as is: the `changes` script is duplicated across the two
workflows.
- **Since review:** `ee41b6d → 251885f` re-reviewed by a separate agent
context: finding resolved, no new findings. Checked title-only edits
(earlier passes stand), base-move cancellation, the concurrency group
expression for every event, and drafts.
- **CodeRabbit:** not requested yet.

</details>

<details>
<summary>Implementation notes</summary>

- The file list comes from `gh api --paginate repos/…/pulls/N/files` (up
to 3000 files), taking `previous_filename` too, so a `.js` renamed to
`.md` counts as code.
- The test is `grep -v '\.md$' > /dev/null`, not `grep -qv`. Not every
`grep` handles `-q` with `-v` the same way.
- An empty file list counts as code.
- The `changes` job swaps `contents: read` for `pull-requests: read`; it
never checks out. Fork PRs get that permission too.
- The concurrency group gets an `-edit` suffix only for a title or body
edit, so those runs cancel only each other. A base move joins the normal
group and cancels the stale run.

</details>

Screenshots: nothing on screen changed.

🤖 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.

Translate the screen-reader "Notifications" text that @wordpress/a11y adds before the locale loads

1 participant