Skip to content

Fix: Render Chinese and Japanese characters on invoice PDFs - #1383

Merged
daveearley merged 2 commits into
developfrom
fix/invoice-cjk-font
Oct 11, 2026
Merged

daveearley merged 2 commits into
developfrom
fix/invoice-cjk-font

Conversation

@daveearley

Copy link
Copy Markdown
Contributor

Problem

A customer reported that invoices for Chinese buyers are in the "wrong format everywhere". Invoices are rendered by DomPDF with DejaVu Sans only, which has no CJK glyphs, so every Chinese character (buyer name, address, event title, organiser details, notes and the zh-cn labels) shows as an empty box.

Fix

  • Bundle Noto Sans SC (static Regular and Bold TTF from Google Fonts, OFL) in backend/resources/fonts/ and add it after DejaVu Sans in the invoice font stack. DomPDF 3 picks the font per character, so Latin text stays in DejaVu and only CJK characters use Noto.
  • Turn on font subsetting. Invoices drop from about 880 KB (develop embeds the whole of DejaVu) to about 22 KB for Latin-only and about 25–50 KB for Chinese.
  • The info values (invoice number, date, amount) used font-weight: 500, which neither font has, so DomPDF fell back to Times. That rendered them in serif and would have shown a Chinese invoice prefix as boxes. They now use bold.
  • Both PDF paths (download endpoint and order email attachment) now go through InvoicePdfRenderer. It creates the DomPDF font cache folder when it's missing, which is always the case on Vapor (/tmp/storage/fonts). If the folder isn't writable, it skips the CJK font and logs a warning, so the invoice renders exactly as before instead of failing.

Coverage

  • Fixed: Chinese (Simplified and Traditional) and Japanese.
  • Unchanged and already fine: Latin, Cyrillic, Greek and Vietnamese (DejaVu).
  • Not covered: Korean, Thai and Hindi. Arabic and Hebrew are unchanged because DomPDF has no shaping or right-to-left layout.

Testing

  • New InvoicePdfRendererTest (feature) covers three cases:
    • A Chinese invoice embeds a Noto subset, uses no Times and stays under 200 KB.
    • A Latin-only invoice doesn't embed Noto.
    • An unwritable font cache still renders, without the CJK font, and logs a warning.
  • Rendered on the dev stack and checked visually. Before the fix the Chinese name was boxes; after it, the zh-cn invoice renders correctly in regular and bold.
  • Vapor simulation: with a fresh, empty font cache folder, running as www-data, invoices render.
  • Unwritable font cache in a fresh process: invoices render.
  • The download service and the email attachment both produce valid PDFs.
  • The unit suite and Pint pass.

Deploy notes

  • Adds about 20 MB of font files to the repo and image.
  • The first Chinese invoice after a cold start costs about 0.5 s while DomPDF builds the font metrics, and about 25 MB is written to /tmp.
  • Please download a Chinese invoice on staging before release.

🤖 Generated with Claude Code

Invoices were rendered with DejaVu Sans only, which has no CJK glyphs,
so Chinese names, addresses, event titles and translated labels showed
as empty boxes.

- Bundle Noto Sans SC (Regular/Bold, OFL) and add it after DejaVu Sans
  in the invoice font stack; dompdf falls back per character
- Enable font subsetting (invoices drop from ~880 KB to ~25-50 KB)
- Use bold instead of weight 500 for info values, which fell back to
  Times and could not render CJK
- Route both invoice PDF paths through InvoicePdfRenderer, which skips
  the CJK font and logs a warning when the dompdf font cache is not
  writable, so invoices never fail to render
@railway-app

railway-app Bot commented Oct 11, 2026 •

Copy link
Copy Markdown

🚅 Deployed to the Hi.Events-pr-1383 environment in Hi.Events

Service Status Web Updated
Hi.Events Queue Worker ✅ Success (View Logs) Oct 11, 2026 at 9:28 am UTC
Hi.Events Frontend 😴 Sleeping (View Logs) Web Oct 11, 2026 at 8:34 am UTC
Hi.Events Scheduler ✅ Success (View Logs) Oct 11, 2026 at 8:27 am UTC
Hi.Events API ✅ Success (View Logs) Web Oct 11, 2026 at 8:27 am UTC
1 service not affected by this PR
  • Maildev

@railway-app
railway-app Bot temporarily deployed to Hi.Events / Hi.Events-pr-1383 October 11, 2026 08:23 Destroyed
@railway-app
railway-app Bot temporarily deployed to Hi.Events / Hi.Events-pr-1383 October 11, 2026 08:26 Destroyed
@github-actions

Copy link
Copy Markdown
Contributor

⚠️ E2E · smoke

✅ Passed ❌ Failed ⚠️ Flaky ⏭️ Skipped ⏱️ Duration
95 0 1 0 2m 44s

Flaky (passed on retry)

  • ⚠️ organizer/organizer-management.spec.ts — organizer management › an organizer creates a second organizer from the global menu

View run

@daveearley
daveearley merged commit 722eb2d into develop Oct 11, 2026
10 checks passed
@github-actions github-actions Bot locked and limited conversation to collaborators Oct 11, 2026

This branch was successfully deployed

No deployments
Hi.Events / Hi.Events-pr-1383 — 4e46672f Deployed Oct 11, 2026 by railway-app[bot]
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant