Skip to content

feat(ui): use a rounded CJK font and check message keys - #40

Merged
nekomeowww merged 2 commits into
nekomeowww/feat/viewer-i18nfrom
nekomeowww/feat/viewer-cjk-font
Oct 21, 2026
Merged

nekomeowww merged 2 commits into
nekomeowww/feat/viewer-i18nfrom
nekomeowww/feat/viewer-cjk-font

Conversation

@nekomeowww

Copy link
Copy Markdown
Contributor

Stacked on #39. Review and merge #39 first; this PR's base is nekomeowww/feat/viewer-i18n.

Problem

  • Misspelled keys get through. t() takes any string, so vue-tsc does not catch a misspelled message key. It shows the raw key at runtime.
  • The Chinese font does not match. The Latin font, Quicksand, is rounded. Noto Sans SC beside it reads as a different typeface. In Preferences, the language trigger also looked larger than its label.

Result

Comparison: 0bf23b4 (head of #39) → 5a2fd40 (head revision of nekomeowww/feat/viewer-cjk-font). Two commits.

38edb53 test(ui): check that every message key the viewer passes exists

  • client/src/i18n/keys.test.ts reads the viewer sources with import.meta.glob(…, { query: '?raw' }). It checks every literal t('…') key, every keypath="…", and every template prefix (t(`states.${…}`)) against the en messages.
    • Checked by hand: renaming one key in CompareMenu.vue makes the test fail and name the file and key.
  • zh-Hans says 执行成功率 for the completion rate on the compare and matrix views too. They said 完成率.
  • countOf is removed from format.ts; nothing calls it.
  • AGENTS.md:
    • The floating-surface examples point to PreferencesMenu.vue.
    • A new rule: viewer text goes through vue-i18n, in both locales, with locale-aware formatting.

5a2fd40 feat(ui): use a rounded CJK font and group the language under Appearance

  • The font: Resource Han Rounded SC 1.910 (Cyano Hao, SIL OFL 1.1), a rounded Source Han Sans. It replaces @fontsource-variable/noto-sans-sc.
    • It is self-hosted as 101 unicode-range WOFF2 slices, about 19 MB, in client/src/assets/fonts/resource-han-rounded-sc, with its LICENSE.
    • The slices cover the same ranges as Fontsource's Noto Sans SC, so a page downloads only the slices it needs. The Scores page loads 14.
  • scripts/buildCjkFont.py rebuilds the slices from the release's ResourceHanRoundedSC-VF.otf (137 MB; not committed).
    • The source is a CFF2 variable font. The browser cannot use the release's TTC.
    • The script shifts the weight axis down by 50. The viewer's 400 / 500 / 600 then draw the font's 450 / 550 / 650, so Chinese text is as dark as the Quicksand beside it. 50 was picked from a side-by-side of +0, +50, and +100.
    • The ROND axis stays variable at its default, 100. Pinning it with fontTools.varLib.instancer fails on this font with InconsistentGlyphOrder. The script's header documents both points.
  • Preferences: an Appearance (外观) group label above Language. The language trigger is compact (text-xs), so its value reads at the size of its label.

The 19 MB of binary fonts go into git. Moving them to Git LFS is a possible follow-up.

CLI changes

No CLI changes.

Report file and viewer API changes

No report file or viewer API changes.

Dependency removed: @fontsource-variable/noto-sans-sc. The built @vieval/ui grows by about 15 MB net (19 MB of slices in, 4.5 MB of Noto Sans SC out).

Validation

At 5a2fd40:

  • pnpm typecheck passes, and pnpm exec eslint packages/ui is clean.
  • Client tests pass: 106, including keys.test.ts.
  • Server tests pass: 140.
  • pnpm -F @vieval/ui build passes, and the 101 slices are in dist/client/assets.
  • The built viewer was checked in a browser:
    • document.fonts reports the Resource Han Rounded SC slices as loaded, and Chinese text renders with them.
    • The Preferences popover and the language menu were checked at desktop width.

🤖 Generated with Claude Code

nekomeowww and others added 2 commits October 21, 2026 08:02
`t()` accepts any string, so vue-tsc does not catch a misspelled key; it shows
the key at runtime. `i18n/keys.test.ts` reads the viewer sources and checks
every literal key, `keypath`, and template prefix against the en messages.

Also:
- zh-Hans says 执行成功率 for the completion rate on the compare and matrix
  views too (they said 完成率)
- remove `countOf` from `format.ts`; nothing calls it after the translation
- AGENTS.md: point floating-surface examples to `PreferencesMenu.vue`, and add
  the rule that viewer text goes through vue-i18n

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Quicksand is rounded and has no CJK glyphs; Noto Sans SC beside it read as a
different typeface. Resource Han Rounded SC 1.910 (Cyano Hao, SIL OFL 1.1) is a
rounded Source Han Sans:

- self-hosted as 101 unicode-range WOFF2 slices (about 19 MB) in
  `client/src/assets/fonts/resource-han-rounded-sc`, loaded per slice like
  Fontsource, with its OFL license
- `scripts/buildCjkFont.py` rebuilds the slices from the release's
  `ResourceHanRoundedSC-VF.otf`; it shifts the weight axis down by 50, so the
  viewer's 400 / 500 / 600 draw the font's 450 / 550 / 650 and Chinese text is
  as dark as the Latin text beside it
- replaces `@fontsource-variable/noto-sans-sc`

Preferences gets an Appearance group label above Language, and the language
trigger is compact (`text-xs`), so its value reads at the size of its label.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
@nekomeowww
nekomeowww merged commit 4b18be5 into nekomeowww/feat/viewer-i18n Oct 21, 2026
@nekomeowww
nekomeowww deleted the nekomeowww/feat/viewer-cjk-font branch October 21, 2026 07: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