* fix(fonts): restore legacy local font names via metric-compatible aliases
Closes#2989.
In v5.0.x the Puppeteer renderer resolved fonts like 'Times New Roman'
or 'Arial' through the browser's font stack. The v5.1 migration to
@react-pdf/renderer requires every font to be Font.register()-ed; the
legacy local-font names were not carried over, so resumes upgraded
from v5.0.x had their typography silently replaced with IBM Plex Serif,
changing line breaks, page counts and overall layout.
This adds a render-time alias layer mapping the old names to
metric-compatible web fonts already shipped in the webfont list:
Times New Roman → Tinos
Cambria → Tinos
Arial → Arimo
Garamond → EB Garamond
Calibri → Source Sans 3
- packages/fonts:
- new `legacyFontAliases` map and `resolveLegacyFontAlias` helper.
- `getFont` falls back to the alias map when the direct lookup misses,
so any caller that asked 'is this a known family?' now answers
truthfully for the legacy names.
- `getFontDisplayName` is intentionally unchanged: the typography
sidebar keeps showing the user's original choice ('Times New Roman'),
while the renderer transparently swaps in the alias target.
- packages/pdf/use-register-fonts:
- `resolvePdfFontFamily` returns the alias target when one applies,
so `Font.register` runs against the right web font and templates
receive a family name they can actually render.
Backwards compatible: families that were never aliased (Roboto, IBM
Plex Serif, the standard PDF fonts, ...) take exactly the same code
path as before. The CJK glyph fallback added in #2986 / PR #3013
continues to apply on top of the resolved primary family.
* fix(fonts): use Carlito (not Source Sans 3) as Calibri alias
Per maintainer review feedback: Carlito is metric-compatible with
Calibri, while Source Sans 3 only matches visually. Switching gives
upgraded resumes the same line widths, line breaks and page counts
they had under v5.0.x.
- packages/fonts/webfontlist.json: add Carlito (Google Fonts, weights
400/700 + italics) so it's a registerable target.
- packages/scripts/fonts/generate.ts: add a getMetricCompatibleFonts
helper and merge it into the output, mirroring how Computer Modern
fonts are appended. This way regenerating the list (`pnpm generate`)
re-emits Carlito automatically and dedupes if it ever enters the
Google Fonts popularity slice.
- packages/fonts/src/index.ts: alias `Calibri → Carlito`.
- packages/fonts/src/index.test.ts: update alias test cases.
Closes#2986.
Since v5.1.0 the renderer was migrated from Puppeteer to
@react-pdf/renderer. The new pipeline only registers the user-selected
typography family (e.g. Roboto, IBM Plex Serif), which contains no CJK
glyphs, so any Chinese / Japanese / Korean characters in the resume
fall back to .notdef and render as garbled boxes in both the in-app
preview and the exported PDF.
@react-pdf/renderer's textkit layer already supports per-codepoint
font substitution when a Text node is styled with `fontFamily` as a
string array — but only if every family in the stack has been
registered via Font.register. This change wires that up:
- packages/fonts: new `getPdfCjkFallbackFontFamily(family)` returns
Noto Sans SC / Noto Serif SC depending on whether the primary font
is sans-serif or serif, and `null` when no fallback is needed
(standard PDF font, or primary already is the fallback). Source Han
Sans/Serif SC covers all CJK-Unified ideographs, so a single font
transparently handles Simplified/Traditional Chinese, Japanese
kanji and Korean hanja.
- packages/pdf/hooks/use-register-fonts: after registering the
primary body/heading fonts as before, additionally register the
resolved CJK fallback (regular weight only — substitution is
per-codepoint, not per-weight, so one face is enough). The
function's return type is widened to a new `PdfTypography` whose
`body.fontFamily` and `heading.fontFamily` become
`[primary, cjkFallback]` two-element stacks.
- packages/pdf/document: cast the widened typography back through the
schema-typed `ResumeData` so the wider runtime value reaches
templates without changing the public `Typography` schema. All 15
templates already consume `metadata.typography.body.fontFamily`
directly, and `StyleSheet.fontFamily` accepts both string and
string[], so no template edits are required.
Latin-only resumes are unaffected:
- `getPdfCjkFallbackFontFamily` returns `null` for standard PDF fonts
and existing CJK selections, so the extra Font.register call is
skipped.
- When no fallback applies, `registerFonts` returns the original
typography reference unchanged (zero allocation).
- Even when the fallback is registered, textkit only consults it for
codepoints the primary font cannot render, so Latin glyphs still
come from the user-selected font with identical metrics.