fix(pages): resolve RTL text shaping and layout in PDF export#9187
fix(pages): resolve RTL text shaping and layout in PDF export#9187danialshirali16 wants to merge 3 commits into
Conversation
Register Vazirmatn as a second font family for RTL content. In the backend node renderers, read the TipTap `dir` attribute on paragraph and heading nodes; when `dir === "rtl"`, apply fontFamily "Vazirmatn" and default textAlign to "right" so that Persian/Arabic characters are shaped correctly and flow right-to-left. Mirror the same Vazirmatn Font.register and a `[dir='rtl']` stylesheet rule in the frontend HTML-based export path. LTR (Inter) behaviour is completely unchanged. https://claude.ai/code/session_01BxEgURqex1hukdwboM3XF6
📝 WalkthroughWalkthroughThis PR adds RTL PDF support: Vazirmatn font registration (web + live), an editor RTL stylesheet rule, and RTL-aware paragraph and heading renderers that default to right alignment when dir="rtl". ChangesRTL PDF Export with Vazirmatn Font Support
Sequence DiagramsequenceDiagram
participant NodeRenderer as Paragraph/Heading Renderer
participant RtlHelper as getRtlStyle Helper
participant PdfOutput as PDF Text Styling
NodeRenderer->>NodeRenderer: Read dir attribute
NodeRenderer->>NodeRenderer: Compute effectiveTextAlign (default right for RTL)
NodeRenderer->>RtlHelper: Get RTL font style for dir="rtl"
RtlHelper-->>NodeRenderer: Return Vazirmatn or null
NodeRenderer->>PdfOutput: Apply alignment, flex, background color, RTL font
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@apps/live/src/lib/pdf/plane-pdf-exporter.tsx`:
- Line 56: The vazirmatnFontDir constant uses process.cwd() which is brittle in
monorepos/runtimes; update vazirmatnFontDir so it resolves the fonts directory
relative to the source file rather than the current working directory (e.g.,
derive the base path from __dirname or from import.meta.url and then
path.resolve that base with "fonts/vazirmatn"), replacing the current definition
of vazirmatnFontDir in plane-pdf-exporter.tsx to ensure font lookup is stable
across environments.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 86d27924-7f45-480c-894f-76148edaf127
📒 Files selected for processing (4)
apps/live/src/lib/pdf/node-renderers.tsxapps/live/src/lib/pdf/plane-pdf-exporter.tsxapps/web/core/components/editor/pdf/document.tsxapps/web/core/constants/editor.ts
process.cwd() is fragile in monorepo/runtime environments. tsdown bundles everything into dist/start.js, so resolving relative to import.meta.url (one level up from dist/) gives a stable path to apps/live/fonts/vazirmatn/ regardless of where the process is started. Addresses CodeRabbit review on makeplane#9187. https://claude.ai/code/session_01BxEgURqex1hukdwboM3XF6
process.cwd() is fragile in monorepo/runtime environments. tsdown bundles everything into dist/start.js, so resolving relative to import.meta.url (one level up from dist/) gives a stable path to apps/live/fonts/vazirmatn/ regardless of where the process is started. Addresses CodeRabbit review on makeplane#9187. https://claude.ai/code/session_01BxEgURqex1hukdwboM3XF6
…ont weights
- Inline `dir === "rtl"` directly into effectiveTextAlign in paragraph and
heading renderers — isRtl was only used for that one expression
- Change Vazirmatn fontWeight registration from numeric (400/700) to string
("normal"/"bold") to match the weight strings mark-renderers.ts uses at
render time, avoiding a potential font-lookup mismatch
https://claude.ai/code/session_01BxEgURqex1hukdwboM3XF6
|
I have read the CLA Document and I hereby sign the CLA |
|
@cla-assistant recheck |
036f737 to
2042583
Compare
Description
Pages' PDF export was broken for RTL languages (Persian, Arabic, Hebrew): exported text appeared as disconnected, isolated glyphs flowing left-to-right — unreadable and unusable.
Root cause (three compounding issues):
dirattribute ignored — TipTap setsdir="rtl"on paragraph and heading nodes for RTL content, but the PDF node renderers never read it. Layout always defaulted to LTR.textAlignwere left-aligned instead of right-aligned.Fix:
plane-pdf-exporter.tsx— registers Vazirmatn (a permissively-licensed Persian/Arabic font with full GSUB/GPOS shaping tables) alongside Inter. Path is resolved relative toimport.meta.urlso it stays stable regardless of CWD.node-renderers.tsx—paragraphandheadingrenderers now readnode.attrs.dir; whendir === "rtl",fontFamily: "Vazirmatn"is applied andtextAligndefaults to"right"(explicit alignment by the user is always respected).document.tsx— mirrors the same VazirmatnFont.registerfor the frontend client-side PDF path.editor.ts— adds a[dir='rtl']rule to the HTML→PDF stylesheet used byreact-pdf-html.LTR content is completely unchanged — Inter is still used for all non-RTL text.
Type of Change
Test Scenarios
textAlign: center→ export → center alignment preserved, not overridden to right.References
Fixes #8922