React多语言PDF渲染下载问题:寻求@react-pdf/renderer替代方案
解决@react-pdf/renderer多语言PDF显示 tofu 字符的方案
先修正你的字体配置错误
你当前把所有语言的Noto字体都注册到同一个family且相同fontWeight下,@react-pdf没法自动匹配对应语言的字体文件,这才导致了tofu(方块)字符。正确的做法是给每个语言的字体单独注册家族,或者直接给不同语言的文本指定对应字体。
修正后的注册代码
import NotoSansMedium from '../assets/fonts/noto/NotoSans-Medium.ttf'; import NotoSansArabic from '../assets/fonts/noto/NotoSansArabic-Medium.ttf'; import NotoSansHebrew from '../assets/fonts/noto/NotoSansHebrew-Medium.ttf'; import NotoSansJP from '../assets/fonts/noto/NotoSansJP-Medium.ttf'; import NotoSansKR from '../assets/fonts/noto/NotoSansKR-Medium.ttf'; import NotoSansSC from '../assets/fonts/noto/NotoSansSC-Medium.ttf'; import NotoSansTC from '../assets/fonts/noto/NotoSansTC-Medium.ttf'; // 为每种语言单独注册字体家族 Font.register({ family: 'NotoSans', src: NotoSansMedium, fontWeight: 'medium' }); Font.register({ family: 'NotoSansArabic', src: NotoSansArabic, fontWeight: 'medium' }); Font.register({ family: 'NotoSansHebrew', src: NotoSansHebrew, fontWeight: 'medium' }); Font.register({ family: 'NotoSansJP', src: NotoSansJP, fontWeight: 'medium' }); Font.register({ family: 'NotoSansKR', src: NotoSansKR, fontWeight: 'medium' }); Font.register({ family: 'NotoSansSC', src: NotoSansSC, fontWeight: 'medium' }); Font.register({ family: 'NotoSansTC', src: NotoSansTC, fontWeight: 'medium' });
渲染时给对应语言的文本指定字体:
<Text fontFamily="NotoSans">English content</Text> <Text fontFamily="NotoSansArabic">النص العربي</Text> <Text fontFamily="NotoSansHebrew">טקסט עברי</Text> <Text fontFamily="NotoSansSC">中文简体内容</Text>
替代方案
如果觉得手动指定字体太繁琐,试试下面这些工具:
1. pdf-lib
pdf-lib 对字体嵌入和文本布局支持更灵活,你可以给不同语言的文本块单独嵌入对应字体,也可以用包含全语言字符的Noto通用字体(注意文件体积会很大)。
示例代码:
import { PDFDocument, rgb } from 'pdf-lib'; import NotoSansSC from '../assets/fonts/noto/NotoSansSC-Medium.ttf'; import NotoSansArabic from '../assets/fonts/noto/NotoSansArabic-Medium.ttf'; async function createMultiLangPDF() { const pdfDoc = await PDFDocument.create(); const page = pdfDoc.addPage([600, 800]); // 嵌入所需字体 const chineseFont = await pdfDoc.embedFont(NotoSansSC); const arabicFont = await pdfDoc.embedFont(NotoSansArabic); // 添加中文文本 page.drawText('中文简体内容', { x: 50, y: 700, font: chineseFont, size: 16, color: rgb(0, 0, 0), }); // 添加阿拉伯文本(RTL布局需额外处理) page.drawText('النص العربي', { x: 50, y: 650, font: arabicFont, size: 16, color: rgb(0, 0, 0), }); const pdfBytes = await pdfDoc.save(); // 触发下载 const blob = new Blob([pdfBytes], { type: 'application/pdf' }); const link = document.createElement('a'); link.href = URL.createObjectURL(blob); link.download = 'multi-lang.pdf'; link.click(); }
2. jsPDF + html2canvas
如果你的内容是基于HTML的,先通过html2canvas把包含多语言的HTML转成图片,再用jsPDF生成PDF。只要浏览器能正常显示多语言,生成的PDF就没问题。
示例代码:
import jsPDF from 'jspdf'; import html2canvas from 'html2canvas'; async function generatePDF() { const targetElement = document.getElementById('multi-lang-content'); const canvas = await html2canvas(targetElement); const imgData = canvas.toDataURL('image/png'); const pdf = new jsPDF('p', 'mm', 'a4'); const imgWidth = 210; const pageHeight = 297; const imgHeight = (canvas.height * imgWidth) / canvas.width; let remainingHeight = imgHeight; let yPosition = 0; pdf.addImage(imgData, 'PNG', 0, yPosition, imgWidth, imgHeight); remainingHeight -= pageHeight; // 处理长内容分页 while (remainingHeight >= 0) { yPosition = remainingHeight - imgHeight; pdf.addPage(); pdf.addImage(imgData, 'PNG', 0, yPosition, imgWidth, imgHeight); remainingHeight -= pageHeight; } pdf.save('multi-lang.pdf'); }
3. Puppeteer(服务器端生成)
如果前端方案有局限,用Puppeteer在Node.js端渲染HTML页面生成PDF。它依赖Chrome的渲染引擎,对多语言、复杂样式的支持是最好的。
示例代码(Node.js环境):
const puppeteer = require('puppeteer'); async function generatePDF() { const browser = await puppeteer.launch(); const page = await browser.newPage(); // 加载目标HTML页面(本地文件或远程URL都可以) await page.goto('file:///path/to/your/multi-lang-page.html', { waitUntil: 'networkidle0' }); // 生成PDF await page.pdf({ path: 'multi-lang.pdf', format: 'A4', printBackground: true }); await browser.close(); }
内容的提问来源于stack exchange,提问作者Zephyr
相关产品推荐
相关产品推荐

