Skip to content

feat(ui): bundle Noto Sans JP locally + UI font picker with system fonts#364

Merged
appergb merged 1 commit intoOpen-Less:betafrom
katanumahotori:feat/ui-font-picker-and-noto-sans-jp
May 8, 2026
Merged

feat(ui): bundle Noto Sans JP locally + UI font picker with system fonts#364
appergb merged 1 commit intoOpen-Less:betafrom
katanumahotori:feat/ui-font-picker-and-noto-sans-jp

Conversation

@katanumahotori
Copy link
Copy Markdown
Contributor

@katanumahotori katanumahotori commented May 8, 2026

User description

Why

OpenLess on a Japanese (or any non-zh) host renders the UI with Microsoft YaHei because the font stack falls through to a generic CJK family that Windows resolves to a zh-Hans face. Glyphs are technically correct but visibly off (variant kanji forms, narrower kana). Users want either Noto Sans JP shipped with the app or to point the UI at their installed Yu Gothic / Meiryo / Hiragino / arbitrary font.

Also, the existing capsule overlay shows transient labels (translating / processing / 'N characters inserted' / cancelled) that distract during dictation. Some users just want errors.

What

  • Bundles @fontsource/noto-sans-jp and @fontsource/inter via npm so we don't need to relax CSP to allow Google Fonts CDN.
  • New src/lib/fontFamily.ts with localStorage-backed preset stacks (auto / notoSansJp / yuGothic / meiryo / hiragino / custom) and querySystemFonts() via the Web Local Font Access API.
  • tokens.css exposes --ol-font-sans-active so the runtime override can swap the body font without a CSS rebuild.
  • Adds a UI font row to PersonalizeSection in SettingsModal: select with presets, 'Load all fonts' button (one-shot user-gesture-gated permission prompt), free-form custom name, error reporting.
  • Default cascade in tokens.css now puts Noto Sans JP before any CJK fallback, so Japanese hosts no longer get rendered with Microsoft YaHei.
  • New 'Quiet mode' toggle in the same section: capsule suppresses transient labels. Errors stay visible. quietMode.ts holds the small localStorage helper + ol:quiet-mode-changed event.

Note

The i18n diffs in this PR include keys that are only consumed by follow-up PRs (#TBD translation toggle, custom polish styles, per-app overrides). They are no-ops on this branch alone but kept together to avoid 5 follow-up i18n-only conflicts. PRs that do consume those keys will be filed against this branch's keys; if PR ordering shifts, those PRs will rebase i18n.


PR Type

Bug fix, Enhancement


Description

  • Bundle local Inter and Noto Sans JP

  • Add selectable UI font presets

    • Load installed fonts on demand
    • Persist custom font names locally
  • Add quiet mode toggle

    • Suppress transient capsule labels
    • Keep errors visible

Diagram Walkthrough

flowchart LR
  S["SettingsModal"] -- "persist font choice" --> F["fontFamily.ts"]
  S -- "persist quiet mode" --> Q["quietMode.ts"]
  M["main.tsx"] -- "load local fonts" --> W["@fontsource Inter / Noto Sans JP"]
  F -- "set CSS variable" --> T["tokens.css body font"]
  I["i18n locales"] -- "new labels" --> S
Loading

File Walkthrough

Relevant files
Dependencies
1 files
package.json
Add font source dependencies                                                         
+2/-0     
Enhancement
9 files
main.tsx
Import bundled fonts and initializer                                         
+10/-0   
fontFamily.ts
Persist and apply selectable font stacks                                 
+140/-0 
quietMode.ts
Persist quiet mode preference flag                                             
+20/-0   
SettingsModal.tsx
Add UI font and quiet controls                                                     
+149/-0 
en.ts
Add English labels for new settings                                           
+52/-0   
ja.ts
Add Japanese labels for new settings                                         
+54/-2   
ko.ts
Add Korean labels for new settings                                             
+52/-0   
zh-CN.ts
Add Simplified Chinese labels for new settings                     
+52/-0   
zh-TW.ts
Add Traditional Chinese labels for new settings                   
+52/-0   
Bug fix
1 files
tokens.css
Prioritize bundled Japanese font cascade                                 
+10/-5   

- Bundles @fontsource/noto-sans-jp and @fontsource/inter via npm so we
  don't need to relax CSP to allow Google Fonts CDN.
- New src/lib/fontFamily.ts with localStorage-backed preset stacks
  (auto / notoSansJp / yuGothic / meiryo / hiragino / custom) and
  querySystemFonts() via the Web Local Font Access API.
- tokens.css exposes --ol-font-sans-active so the runtime override can
  swap the body font without a CSS rebuild.
- Adds a "UI font" row to PersonalizeSection in SettingsModal: select
  with presets, "Load all fonts" button (one-shot user-gesture-gated
  permission prompt), free-form custom name, error reporting.
- Default cascade in tokens.css now puts Noto Sans JP before any CJK
  fallback, so Japanese hosts no longer get rendered with Microsoft
  YaHei (zh-Hans glyph variants).

Also adds a "Quiet mode" toggle in the same section: when on, the
capsule suppresses transient labels (translating / processing /
"N characters inserted" / cancelled). Errors stay visible. quietMode.ts
holds the small localStorage helper + 'ol:quiet-mode-changed' event.

Note: i18n strings here include keys for follow-up PRs (translation
toggle, custom polish styles, per-app overrides). They are scoped to
the new sections in those PRs and are no-ops on this branch alone.
@chatgpt-codex-connector
Copy link
Copy Markdown

Codex usage limits have been reached for code reviews. Please check with the admins of this repo to increase the limits by adding credits.
Credits must be used to enable repository wide code reviews.

@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 8, 2026

PR Reviewer Guide 🔍

Here are some key observations to aid the review process:

⏱️ Estimated effort to review: 3 🔵🔵🔵⚪⚪
🧪 No relevant tests
🔒 No security concerns identified
⚡ Recommended focus areas for review

Possible Issue

The setQuietCompletion function writes to localStorage but does not dispatch the ol:quiet-mode-changed event mentioned in the PR description (and the file export only exposes a getter/setter). If the capsule overlay only reads ol-quiet-completion on mount, toggling quiet mode in settings will not update the overlay until it is reopened — the toggle appears non‑functional. The intended event‑based notification is missing.

export function setQuietCompletion(value: boolean): void {
  try {
    window.localStorage.setItem(QUIET_COMPLETION_KEY, value ? 'true' : 'false');
  } catch {
    /* localStorage unavailable: ignore */
  }

katanumahotori pushed a commit to katanumahotori/openless that referenced this pull request May 8, 2026
Capsule.tsx's quiet-mode gating depends on src/lib/quietMode.ts which
is otherwise added in Open-Less#364. Including the file here keeps this PR
buildable in isolation. The file is identical to Open-Less#364's; if both PRs
land, the second merge is a no-op.
@appergb appergb merged commit 57f7e13 into Open-Less:beta May 8, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants