Skip to content

fix: use sequential filenames for embedded fonts#3428

Open
ctjlewis wants to merge 1 commit intodolanmiu:masterfrom
ctjlewis:fix/embedded-font-spaces-and-sig
Open

fix: use sequential filenames for embedded fonts#3428
ctjlewis wants to merge 1 commit intodolanmiu:masterfrom
ctjlewis:fix/embedded-font-spaces-and-sig

Conversation

@ctjlewis
Copy link
Copy Markdown

@ctjlewis ctjlewis commented Apr 30, 2026

Summary

Embedded fonts with spaces (or other non-ASCII characters) in their family name caused Word to show its "Word found unreadable content" recovery prompt on open. The package zip entries were named after the user-facing family (e.g. word/fonts/EB Garamond.odttf), and Word treats those paths as literal filenames that must be plain.

This PR switches to sequential fonts/font1.odttf, fonts/font2.odttf, … in both the relationship Target and the zip entry. The user-facing family name continues to live only in <w:font name="...">, so no API change.

Closes #3019.

Context

Refs #2521 — that issue reported two problems together. PR #2800 fixed one of them (the missing Relationship from document.xml.rels to fontTable.xml). The other (spaces in the package filename) was left unfixed and resurfaced as #3019. This PR completes the pair. May also help #3120 — LibreOffice silently dropping embedded custom fonts.

What changed

  • FontWrapper: relationship Targets are now fonts/font<N>.odttf.
  • next-compiler: zip entries match the same sequential names.
  • The user-facing family name lives only in <w:font name="..."> — unchanged.

Tests

  • New font-wrapper.spec.ts — verifies relationship Targets are sequential.
  • New case in next-compiler.spec.ts — verifies zip entries are font1.odttf etc., with no family-name paths leaking through.

Test plan

  • Existing font tests pass (vitest run src/file/fonts src/export/packer/next-compiler)
  • Generated docx with EB Garamond (space in family name) opens in Word with no recovery prompt
  • New regression tests cover both the relationship Target and the zip entry path

Embedded fonts with spaces (or other non-ASCII characters) in their
family name caused Word to show its "Word found unreadable content"
recovery prompt on open. The package zip entries were named after
the user-facing family (e.g. `word/fonts/EB Garamond.odttf`), and
Word treats those paths as literal filenames that must be plain.

Switch to sequential `fonts/font1.odttf`, `fonts/font2.odttf`, …
in both the relationship Target and the zip entry. The user-facing
family name continues to live in `<w:font name="...">` only.

Closes dolanmiu#3019.
Refs dolanmiu#2521 (PR dolanmiu#2800 fixed
the related fontTable rel-link; this completes the pair).
May also help dolanmiu#3120
(LibreOffice silently dropping embedded custom fonts; same
package-path encoding plausibly the cause, untested locally).
@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 30, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 100.00%. Comparing base (9439c73) to head (49e0a2d).

Additional details and impacted files
@@            Coverage Diff            @@
##            master     #3428   +/-   ##
=========================================
  Coverage   100.00%   100.00%           
=========================================
  Files          310       310           
  Lines         3173      3172    -1     
  Branches       716       716           
=========================================
- Hits          3173      3172    -1     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

ctjlewis added a commit to EvolvingPrograms/legalese that referenced this pull request Apr 30, 2026
Five Google Font families ship in `fonts/` and embed into the rendered
.docx when selected via `style.font:`:

  - EB Garamond     — classic Garamond serif
  - Source Serif 4  — modern, very readable
  - Crimson Pro     — tight Garamond alternative
  - PT Serif        — workhorse legal serif
  - Libre Baskerville — Baskerville substitute

Variable-axis TTFs where available (single file covers all weights via
the wght axis; modern Word interpolates true designed bold). 2.7MB
total — well under the 30MB skill-upload budget.

The font embedding requires an upstream docx fix
(dolanmiu/docx#3428): docx-js was naming
embedded-font zip entries after the user-facing family (e.g.
`word/fonts/EB Garamond.odttf`), and Word rejected paths containing
spaces/non-ASCII with its "found unreadable content" recovery prompt.
The fix switches to sequential `font1.odttf`/`font2.odttf`/...
paths, decoupling the package path from the font family name.

Until the PR merges, `patches/docx@9.6.1.patch` carries the same
change locally — bun applies it on every install. Removing the patch
once the upstream release ships.

`scripts/fetch-fonts.ts` refreshes the bundle from
github.com/google/fonts. Embedding wired in `src/lib/build.ts` —
when `style.font:` matches a bundled family, its TTF is read from
`fonts/manifest.json` and registered with docx's FontOptions.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
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.

Custom fonts with spaces in them corrupt MS word file

1 participant