Skip to content

feat(i18n): add Simplified Chinese desktop localization - #7777

Open
Asterracy wants to merge 1 commit into
block:mainfrom
Asterracy:i18n-zh-hans
Open

Asterracy wants to merge 1 commit into
block:mainfrom
Asterracy:i18n-zh-hans

Conversation

@Asterracy

Copy link
Copy Markdown

Summary

  • Add bundled desktop i18n with English fallback and Simplified Chinese (zh-Hans).
  • Add a persisted system / en / zh-Hans language preference with immediate switching.
  • Localize the desktop UI across onboarding, agents, channels, communities, forum, home, huddle, messages, profile, projects, settings, sidebar, shared UI, and workflows.
  • Keep the macOS native application menu synchronized with the selected UI language.
  • Add catalog parity checks, a hardcoded-string ratchet, a frozen zh-Hans glossary, and i18n regression tests.
  • Document the branch as an unofficial localization in LOCALIZATION.zh-Hans.md.

Relationship to existing localization work

This PR is intentionally related to and overlaps the existing i18n work:

The existing PRs provide the relevant architectural context. This branch presents a complete zh-Hans desktop implementation for maintainer review. If maintainers prefer #5152 or another base, this PR can be split, rebased, or closed in favor of that direction.

Verification

All checks below were rerun from a clean clone based on the current upstream main:

  • pnpm exec node src/i18n/catalogValidation.mjs — pass (catalog parity ok)
  • pnpm typecheck — pass
  • pnpm check — pass; 2 warnings and 5 infos, no errors
  • pnpm test — 6572 passed, 0 failed, 0 skipped
  • pnpm build — pass; protected feature artifact matrix passed
  • just desktop-tauri-check — pass

The locale catalog contains 4082 leaf keys in both English and Simplified Chinese, with no missing or empty Chinese values.

Scope and attribution

  • Desktop client only; no relay, mobile, or web localization is claimed here.
  • User content, agent output, code identifiers, model names, and protocol fields remain untranslated where appropriate.
  • This is an unofficial community localization and does not claim Block endorsement or Buzz trademark rights.
  • Implemented and reviewed by Asterracy with assistance from OpenAI Codex. The commit author and DCO sign-off are Asterracy.

Review request

Please advise whether maintainers prefer this as one complete locale contribution or as a sequence of smaller infrastructure, catalog, and surface PRs.

@Asterracy
Asterracy requested a review from a team as a code owner September 21, 2026 07:31
@github-actions

github-actions Bot commented Sep 21, 2026 •

Copy link
Copy Markdown

🔐 Codex Security Review

Status: review required for the current range.

The current range is 77729abfb692b25a0f4ec4a69add86af2e32c0dd...3343dee36cb81ae87878cc4bf78a2c95d97237f1.
A new review must complete for this exact range. When manual authorization
is required, a Block organization member must comment exactly
@buzz-security-review 3343dee36cb81ae87878cc4bf78a2c95d97237f1 to authorize a new review.
Any previous review applies only to its recorded range.

ChengLiKe pushed a commit to ChengLiKe/buzz that referenced this pull request Oct 8, 2026
…est upstream

Merge upstream main at d34c9c2 (163 commits past the PR's base 77729ab)
into the zh-hans follow branch, resolving 26 conflict hunks across 15 files.

Resolution keeps upstream's new functionality and preserves the zh-Hans t()
wrapping:
- effort picker: adopt the rebuilt effortPickerState API (backend/choices,
  note) and translate the new note copy via agents.effort.support-unknown and
  agents.effort.maybe-unsupported
- settings: follow upstream's moderation -> relay-admin section rename; nav
  groups keep both `id` (navGroupLabel / i18n) and the canonical English
  `label` that upstream tests look groups up by
- reportErrorMessage falls back through the catalog (i18n.t), keeping the
  exported signature its tests pin
- community leave hint, huddle confirm, canvas labels, timeout banner: t()
  versions of upstream's new copy
- merged test files keep both the i18n bootstrap and the new upstream cases;
  three upstream test files (ChannelCanvas existence / switch-reset, persona
  model discovery jsdom) gain the standard initializeI18n bootstrap that the
  localized code now needs

Catalog: 5 new entries, en/zh-Hans aligned.
Hardcoded-string baseline: the 150 literals merged in with upstream's new
surfaces (admin console, canvas history, pairing) are triaged as
deferred-pr4-surface with a follow-up wave note — the ready-made backlog for
the next localization pass.

Verified: tsc --noEmit, biome check, px-text, pubkey-truncation, catalog
parity, hardcoded-strings gate, 6876 unit + 139 jsdom tests — all green.

Co-Authored-By: Claude Code <[email protected]>
Signed-off-by: Fizz <537fca8a8c780d947a6ec97425ec282d7307baf48fde373f11824212384c31cb@like.communities.buzz.xyz>
matt2e added a commit that referenced this pull request Nov 14, 2026
… closes (#9440)

## Summary
`desktop/src/features/terminal/TerminalSubstrate.test.mjs` can pass
every test and then run the Desktop JS job out of memory several minutes
later. This moves the React Testing Library unmount from `beforeEach` to
`afterEach`, so no tree is still mounted when the jsdom window closes.
Only the test file changes (6 insertions, 2 deletions).

Commit (cherry-picked unchanged from a local flake-fix series):
- `test(desktop): unmount every TerminalSubstrate tree before the window
closes`

### CI sighting

One sighting was found in the CI runs from 7 to 12 November 2026 that
were searched:

- 9 November 2026, "Desktop Domain / Desktop JS", run 42706004493
attempt 1 (on #9227; the rerun passed):
-
https://github.com/block/buzz/actions/runs/42706004493/job/129463488242

In that job the suite reported 6,950 of 6,951 passing. The log shows `An
update to TerminalSubstrate inside a test was not wrapped in act(...)`
at 21:54:33Z, then `FATAL ERROR: Ineffective mark-compacts near heap
limit Allocation failed - JavaScript heap out of memory` at 22:02:17Z,
and the file is reported as failed at file level (`test at
src/features/terminal/TerminalSubstrate.test.mjs:1:1`) after 504.6 s.

### Root cause

The file called `cleanup()` only in `beforeEach`, so the last test's
tree was still mounted when `after(() => dom.window.close())` ran. If
ThemeProvider's asynchronous palette update landed after that close, it
re-rendered the substrate, the splash effect's palette guard passed, and
`requestAnimationFrame` on the closed window started a fresh jsdom
interval that nothing cleared. That 60 Hz loop repainted the banner into
the test's recording `getContext` stub indefinitely, and `paintLog` grew
until the heap limit. No individual test hangs, so a per-test timeout
would not catch it.

### Fix

`afterEach(() => cleanup?.())` unmounts every tree, including the last,
before `after()` closes the window. The `beforeEach` call became
redundant and is removed. No assertions change, and no timeouts, retries
or sleeps are added.

### Related issue
N/A (flake fix). No existing issue or PR for this failure was found.
Three open PRs touch the same test file (#5057, #5485, #7777); none of
them changes where `cleanup` runs.

### Testing
Human testing is still required. This PR does not carry
`buzz-review-completed`; the author has not yet run this test themselves
on this branch.

#### Verification of the fix (before this branch was split out)
- The test file, 5 consecutive runs: 25 of 25 tests passed each time in
about 6.8 s, with no `act` warning.
- The CI out-of-memory failure was not reproduced with the real test
file. Its mechanism was reproduced in a scratch harness with the same
stubs: without cleanup before the window close, 3 of 3 runs left the
palette unresolved at close, added 11,556 `paintLog` entries per 100 ms,
kept one live timer, and never exited. With cleanup before the close, 3
of 3 runs added no entries, left no timers, and exited on their own.

#### Local checks on this branch
The push ran the repository's full pre-push hook set from a checkout of
this branch's head (`7f4117340`), with no lanes excluded and without
`--no-verify`. The branch is one commit behind `main`; that commit
changes only mobile and docs files, none of them touched here.

Ran and passed:
- `branch-skew`, `push-head-scope` and `file-size-check`
- `desktop-check` (`pnpm check`)
- `desktop-typecheck` (`pnpm typecheck`)
- `desktop-test` (`pnpm test`, the full desktop unit suite, which
includes `TerminalSubstrate.test.mjs`)

Did not run:
- `rust-tests`, `desktop-tauri-checks` and `mobile-checks`. The hook
selects lanes by changed path, and this branch changes no Rust, Tauri or
mobile file.
- Desktop builds and the Playwright E2E suites, which are CI-only.
- `just ci`.
- The 5-run repetition and the scratch harness above were not repeated
on this branch.

A green run does not prove the flake is gone: the failure needs the
palette update to land after the window closes.

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

Signed-off-by: mtoohey <[email protected]>
Signed-off-by: Matt Toohey <[email protected]>
Co-authored-by: Claude Fable 5.1 <[email protected]>

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.

1 participant