Skip to content

perf(i18n): load only the active message table at startup - #293

Merged
chaxus merged 3 commits into
mainfrom
perf/i18n-active-locale
Oct 24, 2026
Merged

chaxus merged 3 commits into
mainfrom
perf/i18n-active-locale

Conversation

@chaxus

@chaxus chaxus commented Oct 24, 2026 •

Copy link
Copy Markdown
Member

Follow-up to #292 (now merged); rebased onto main. Baseline numbers are from #292's branch at 39ae686f.

Problem

packages/shared/src/i18n.ts imported all seven message tables statically. That came to 234 KB minified, about 73 KB gzip, in the shared utils-*.js chunk that both /editor and /history fetch before they run. Each visitor reads one of them.

Change

  • English stays in the bundle as the per-key fallback. The other six tables are loaded with a literal import() per locale, and i18n.ts awaits the active one at module top level. Nothing that imports t() runs before its table is in place, so t() stays synchronous and none of its callers change. If the chunk fails to load, the page starts in English.
  • loadLocale(lang) is exported and shares in-flight loads. setLanguage (tests only) switches at once and fires languagechange again when a late table arrives.
  • displayError in the assistant matches saved error text against every language, so presentation.ts awaits all tables. It is not in the startup graph; it costs about 65 KB gzip, and only when the assistant opens. A fresh-context review of the diff found this.
  • Offline: bin/offline-assets.mjs already follows dynamic imports, and a stamped sw.js lists all six locale chunks.

Measurements (static startup graph from .vite/manifest.json, gzip -9)

Page Before (39ae686f) After
/editor 537 KB raw / 162 KB gzip 337 KB raw / 105 KB gzip
/history 400 KB raw / 121 KB gzip 198 KB raw / 61 KB gzip

A non-English visitor also fetches one locale chunk, about 11 KB gzip.

Reverse validation

  • With the static imports restored, both startup-payload cases fail (ja message table is in …/utils-*.js).
  • With the loaders kept but no top-level await, the unit case "reads Japanese as soon as the module resolves" fails, and so does the E2E /history?locale=de heading case (Received: "Saved documents").
  • Without the await in presentation.ts, the new agent-presentation case fails (a Japanese error restored on a German page).

Verification

pnpm run lint:ts, format:check, the full Vitest run (252 files / 6805 tests), and 43 E2E cases: startup payload, editor locales, history page, assistant history, assistant locale, assistant offline assets.

Record: docs/explorations/2026-10-24-active-locale-only.md.

🤖 Generated with Claude Code

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Oct 24, 2026 •

Copy link
Copy Markdown

Deploying document with  Cloudflare Pages  Cloudflare Pages

Latest commit: 7e1f50f
Status: ✅  Deploy successful!
Preview URL: https://a1618276.document-7hm.pages.dev
Branch Preview URL: https://perf-i18n-active-locale.document-7hm.pages.dev

View logs

Base automatically changed from perf/startup-payload-2 to main October 24, 2026 11:45
chaxus and others added 3 commits October 24, 2026 19:46
English stays in the bundle as the per-key fallback; the other six tables
are chunks, and i18n.ts awaits the active one at top level so t() stays
synchronous for every importer. The assistant awaits all tables because
displayError matches error text saved in any language.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@chaxus
chaxus force-pushed the perf/i18n-active-locale branch from e278651 to 7e1f50f Compare October 24, 2026 11:49
@chaxus
chaxus enabled auto-merge (rebase) October 24, 2026 11:49
@chaxus
chaxus merged commit ee33a4e into main Oct 24, 2026
20 checks passed
@chaxus
chaxus deleted the perf/i18n-active-locale branch October 24, 2026 12:10
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