Skip to content

feat: add i18n system with 22 languages#10

Open
WkdXeqtr wants to merge 1 commit into
SteamClientHomebrew:mainfrom
WkdXeqtr:main
Open

feat: add i18n system with 22 languages#10
WkdXeqtr wants to merge 1 commit into
SteamClientHomebrew:mainfrom
WkdXeqtr:main

Conversation

@WkdXeqtr
Copy link
Copy Markdown

@WkdXeqtr WkdXeqtr commented May 24, 2026

Summary

  • Adds a full localization system (Locale class) with auto-detection of system language and runtime switching
  • 22 languages matching Millennium: Brazilian Portuguese, Bulgarian, Danish, Dutch, English, French, German, Hungarian, Indonesian, Italian, Japanese, Korean, Latin American Spanish, Polish, Russian, Simplified Chinese, Spanish, Swedish, Traditional Chinese, Turkish, Ukrainian, Vietnamese
  • Translations embedded into the binary at CMake configure time — no external files needed at runtime
  • Language selector in the title bar (top-right), auto-detects system language on first launch
  • All hardcoded UI strings replaced with Locale::Get()

Font system

Geist — the primary UI font — does not cover CJK scripts or Vietnamese
diacritics. Rather than bundling full CJK fonts (~45 MB across three
typefaces) or a full Vietnamese font (~1 MB), the approach differs
per script:

CJK (Simplified/Traditional Chinese, Japanese, Korean)

  • Tiny embedded subsets (~21 KB total) cover only the characters used
    in the language selector display names (简体中文 繁體中文 日本語 한국어)
  • These glyphs are merged into Geist since CJK and Latin ranges don't
    overlap — the rest of the UI stays on Geist
  • When a CJK language is active, the system font is loaded as primary
    (Windows: msyh/msjh/YuGothic/Malgun; Linux: fc-match; macOS:
    fc-match → PingFang/Hiragino/AppleSDGothicNeo)

Vietnamese

  • Vietnamese diacritics (ế, ệ, …) overlap with Latin ranges that Geist
    already partially covers — merging would cause visual inconsistency
    between mixed glyphs from two typefaces
  • Instead, the system font (Arial/LiberationSans/HelveticaNeue) replaces
    Geist entirely as the primary font when Vietnamese is active
  • The language selector dropdown keeps its Geist appearance via a
    dedicated font slot pushed around the combo widget
  • A small embedded subset (~18 KB) covers the 9 unique codepoints in
    "Tiếng Việt" for the dropdown item specifically

cjk_names.h and viet_name.h are pre-generated static byte arrays —
no tooling required at build time. To regenerate from system fonts:

pip install fonttools brotli
python tools/generate_font_headers.py

- Implement Locale class (i18n.h + locale.cc): auto-detect system
  language, runtime switching, English fallback
- Add locale JSON files for all 22 languages matching Millennium
- Embed translations into binary at CMake configure time via
  generated/locale_data.h (no runtime file I/O)
- Replace all hardcoded UI strings with Locale::Get() across all routes
- Add language selector dropdown to the title bar (top-right)
- Font atlas adapts to the active language:
  · Geist + CJK name subsets (~21 KB embedded) always merged in
  · System CJK font loaded as primary when a CJK locale is active
  · Vietnamese: system Arial/LiberationSans/HelveticaNeue replaces
    Geist as primary font entirely (no merging); dropdown keeps Geist
    appearance via a dedicated font slot (Fonts[3])
  · VietName_Standalone (~18 KB embedded) for the Vietnamese item
    in the dropdown
- Rebuild font atlas on language switch
- Platform support: Windows (WinAPI lang detect + system font paths),
  Linux (fc-match + LiberationSans fallback), macOS (fc-match +
  PingFang/Hiragino/AppleSDGothicNeo/HelveticaNeue fallbacks)
- Add tools/generate_font_headers.py to regenerate embedded subsets
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