Skip to content

fix(fonts): add unicode fallback for cyrillic#145

Open
fbraz3 wants to merge 1 commit into
mainfrom
fix/issue-144-macos-cyrillic-text
Open

fix(fonts): add unicode fallback for cyrillic#145
fbraz3 wants to merge 1 commit into
mainfrom
fix/issue-144-macos-cyrillic-text

Conversation

@fbraz3
Copy link
Copy Markdown
Owner

@fbraz3 fbraz3 commented May 20, 2026

Summary

Fixes missing Cyrillic UI labels on macOS by improving Unicode fallback font resolution in the W3D font loading path.

Changes

  • Added LoadUnicodeFallbackFont in both game targets:
    • GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/GUI/W3DGameFont.cpp
    • Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/GUI/W3DGameFont.cpp
  • Updated W3DFontLibrary::loadFontData to resolve AlternateUnicodeFont via:
    1. configured localized Unicode font (m_unicodeFontName), then
    2. deterministic fallback list of common system fonts (Arial/Helvetica/Noto/DejaVu).
  • Updated dev diary before commit:
    • docs/DEV_BLOG/2026-05-DIARY.md

Why

Issue #144 reports that Cyrillic labels render as empty on macOS while numbers/Latin render correctly. This points to Unicode glyph fallback not resolving reliably in the active font path.

Validation

  • [Platform] Build GeneralsXZH completed successfully after changes.
  • No diagnostics errors in modified font source files.

Fixes #144

Improve AlternateUnicodeFont resolution on macOS/Linux by trying configured Unicode font first and then a deterministic fallback list of common system fonts.

Also update the May 2026 dev diary before commit as required by project workflow.

Fixes #144
@w1semannn
Copy link
Copy Markdown

w1semannn commented May 21, 2026

Tested the build from PR #145 (artifact: macos-generalsxzh-app, 31 MB) on
macOS Sequoia / Apple M1. Replaced /Applications/GeneralsXZH.app, kept
the previous .app as GeneralsXZH.app.backup.

❌ Cyrillic labels still NOT rendering. Identical reproduction: China skirmish,
building under construction — "Строительство: XX%" label completely absent
over construction site. ASCII overlays (cash, timer, FPS counter) render fine
as before.

Setup unchanged:

  • 00RussianZH.big at $HOME/GeneralsX/GeneralsZH/
  • SHA256: DC9088DD90AB471165D66183C25112EDABB6012603211BB6BE1A94E3B3424A33

Attaching:

  • pr145_still_broken.png — test screenshot
  • 00RussianZH.big — the actual file you requested

────────────────────────────────────────────────────────────────────
New findings from direct .big inspection (after my previous comments)
────────────────────────────────────────────────────────────────────

I wrote a small Python helper to parse the BIGF format and dump the
.big contents + CSF headers (happy to share if useful). Running it on
both 00RussianZH.big and EnglishZH.big surfaced something important
that wasn't visible from the startup logs alone:

────────────────────────────────────────

  1. TWO .big files provide IDENTICAL paths
    ────────────────────────────────────────
Path Russifier (.big) Stock (EnglishZH.big)
Data\English\generals.csf 498,071 B, 3991 labels 928,775 B, 6422 labels
Data\English\Language.ini 2,028 B 2,039 B

So 00RussianZH.big provides a SMALLER, INCOMPLETE generals.csf at exactly
the same path as the stock EnglishZH.big. There's no data/russian/ branch —
the russifier overwrites English in place.

On default launch the russifier's 3991-label CSF wins (confirmed by
textCount=3991 in the log). The stock 6422-label CSF from EnglishZH.big
is silently shadowed. Any label outside the 3991 the russifier translated
resolves to empty at lookup time — which is exactly the on-screen symptom.

────────────────────────────────────────
2) Language.ini delta is ONE line
────────────────────────────────────────

After extracting both Language.ini files from the .big archives and
diffing, the only substantive change is:

Stock : UnicodeFontName = "Arial Unicode MS"
Russifier : UnicodeFontName = "Arial"

All other ~24 lines (DrawableCaptionFont, TooltipFontName, MessageFont,
etc.) are byte-for-byte identical. The russifier author was relying on
the classic Win-era assumption that Windows Arial has Cyrillic in its
core file (it does). On macOS via the bundled fontconfig, that
assumption may not hold.

────────────────────────────────────────
3) Both fonts ARE present on macOS Sequoia
────────────────────────────────────────

/System/Library/Fonts/Supplemental/Arial.ttf (773 KB)
/System/Library/Fonts/Supplemental/Arial Unicode.ttf (23 MB)
└ system_profiler reports Full Name "Arial Unicode MS"

The fonts are physically there with the exact names the engine asks
for. So this isn't a "font not installed" case. If text isn't rendering,
it's downstream of font discovery — either the bundled fontconfig isn't
returning them, or the CSF→glyph→MoltenVK chain breaks on Cyrillic
codepoints from plain Arial (vs Arial Unicode MS).

────────────────────────────────────────
Suggested fix directions
────────────────────────────────────────

(a) Merge .big resources at the same path rather than replace. For
Language.ini: load stock first, overlay russifier keys on top — any
key not redefined keeps its stock value (UnicodeFontName "Arial
Unicode MS" would survive because the russifier doesn't reset it).
For generals.csf: merge at label level, stock as base table,
russifier overrides by label ID.

(b) Or simpler — on missing-label lookup, fall back to the next CSF in
the .big chain instead of returning empty. Closes the 2431-label
gap left by this russifier (and any other community translation
pack with similar coverage).

Either approach would silently fix this and most other incomplete
translation packs that exist for ZH (Polish, Brazilian, Czech, etc.).

Also worth investigating: why setting LANG/LC env vars inverts the .big
override priority. CNC_GENERALS_ZH_PATH is identical in all runs, only
env vars differ — yet the resource that wins changes (russifier on
default-locale, stock English on any ru_RU.* env var).

────────────────────────────────────────

Happy to send any of:

  • the inspect_big.py / extract_from_big.py helpers
  • the dumped .big contents for both archives
  • the extracted Language.ini files (russifier + stock)
  • the full DXVK d3d9 log (~30 MB)
  • all three startup logs (default broken, env-var workaround, stock
    without russifier)

Thanks!

pr145_still_broken

00RussianZH.zip

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.

macOS: Cyrillic text labels not rendered (numbers work, English labels work)

2 participants