// IRANYekan *fanum* maps Latin digit codepoints (0-9) to Persian glyphs. // Montserrat (`.en`) keeps real Latin digits — so any Latin-letter run that // also carries model numbers (HP R5, 8GB, EF2126WM…) must render under `.en`. // Pure digit runs (e.g. "13" inside «آیفون 13 پرو») stay on the FA font and // correctly show as Persian digits. const EN_RUN = /[A-Za-z0-9][A-Za-z0-9\s\-_|./+#%]*/g; export type TextSegment = { type: "fa" | "en"; text: string }; export function splitMixedText(text: string): TextSegment[] { const segments: TextSegment[] = []; let cursor = 0; let match: RegExpExecArray | null; const re = new RegExp(EN_RUN.source, "g"); while ((match = re.exec(text)) !== null) { let start = match.index; let end = start + match[0].length; while (end > start && /\s/.test(text[end - 1]!)) end--; const chunk = text.slice(start, end); if (!/[A-Za-z]/.test(chunk)) continue; if (start > cursor) segments.push({ type: "fa", text: text.slice(cursor, start) }); segments.push({ type: "en", text: chunk }); cursor = end; } if (cursor < text.length) segments.push({ type: "fa", text: text.slice(cursor) }); return segments; } /** Wrap Latin runs in a plain string as `.en` spans (text is assumed already HTML-safe). */ export function wrapLatinRuns(text: string): string { return splitMixedText(text) .map((seg) => seg.type === "en" ? `${seg.text}` : seg.text, ) .join(""); } /** Walk HTML text nodes (content between tags) and wrap Latin runs. */ export function wrapLatinInHtml(html: string): string { return html.replace(/(^|>)([^<]+)/g, (_, prefix: string, text: string) => prefix + wrapLatinRuns(text)); }