/** Strip invisible bidi / ZWNJ chars that render as tofu in embedded Arabic fonts. */ export function normalizePersianPdfText(text: string): string { return text .replace(/\u200c/g, " ") .replace(/[\u200e\u200f\u202a-\u202e\u2066-\u2069\ufeff]/g, "") .replace(/\u2014/g, "-") .replace(/\s+/g, " ") .trim(); } /** * pdfkit renders glyphs strictly left-to-right. * fontkit already reshapes each word's glyphs into visual (LTR) order, * but it does NOT reorder words — so a multi-word RTL string like * "نام صاحب خودرو" has its words placed LTR on the page and reads * backwards. Reversing the word sequence here makes pdfkit emit the * words in the correct visual order for a right-to-left PDF reader. */ function reverseRtlWords(text: string): string { if (!/[\u0600-\u06FF]/.test(text)) return text; return text.split(" ").reverse().join(" "); } export function pdfKitRtlKeyValue( label: string, value: string, ): { label: string; value: string } { return { label: reverseRtlWords(normalizePersianPdfText(label)), value: reverseRtlWords(normalizePersianPdfText(value)), }; } export function pdfKitRtlParagraph(text: string): string { return reverseRtlWords(normalizePersianPdfText(text)); } export function isMostlyAscii(text: string): boolean { return text.length > 0 && !/[\u0600-\u06FF]/.test(text); }