Arabic and RTL documents
Sahifa renders with the same engine as Google Chrome, so Arabic shaping, right-to-left layout and mixed Arabic and English text work as they do in the browser. This guide covers the details that make Arabic documents look right on paper.
Direction and language
Set both on the root element. lang selects the right shaping and hyphenation rules; dir sets the reading order, table column order and default alignment.
<html dir="rtl" lang="ar">
For English inside Arabic text (names, IBANs, codes), wrap it so it keeps its own direction:
<p>رقم الحساب: <bdi dir="ltr">SA03 8000 0000 6080 1016 7519</bdi></p>
Fonts
These fonts are installed on the server and can be used by name, without loading anything:
| Font | Good for |
|---|---|
Noto Naskh Arabic | Body text of documents; the classic book style. |
Noto Sans Arabic | Clean interface-style text, tables. |
Noto Kufi Arabic | Headings and brand text. |
Amiri | Formal documents, contracts, fully vocalised text. |
DejaVu Sans, Liberation Sans, Liberation Serif | Latin text; Liberation has the same metrics as Arial and Times New Roman. |
Noto Color Emoji | Emoji. |
body { font-family: 'Noto Naskh Arabic', 'Noto Sans', sans-serif; }
Your own fonts work too: load them with @font-face from a public URL or embed them as data: URIs. The renderer waits for web fonts before it creates the file. Fonts on Google Fonts load from Google; if your document must not cause any request outside Saudi Arabia, embed the font or use an installed one.
Numbers and dates
- Arabic-Indic digits (
١٢٣) and Western digits (123) are both fine. Choose one per document; Saudi financial documents commonly use Western digits. - Amounts keep their order inside Arabic text. For columns of amounts, set
direction: ltr; text-align: lefton the cells, andfont-variant-numeric: tabular-numsso decimals line up. - The riyal: write
ر.سorSAR. The new Saudi riyal sign (U+20C1) is not yet in the installed fonts; if you need it, embed a font that has it or use an SVG. - Hijri dates are plain text to the renderer; format them in your application.
Tables that span pages
To repeat a table's header row on every page, put it in <thead> and send use_print: true. Without the print stylesheet the header appears only on the first page.
tr { break-inside: avoid; } /* do not split a row across pages */
thead { display: table-header-group; } /* repeat the header */
Page numbers in Arabic
"footer": { "source": "<div style=\"width:100%;text-align:center;font-size:9px\">صفحة {{page}} من {{total}}</div>" },
"margin": "20mm"
The numbers are Western digits. Give the footer its own inline styles: styles of the main document do not reach it.
ZATCA e-invoice QR codes
Simplified tax invoices in Saudi Arabia carry a QR code with the seller name, VAT number, time stamp, total and VAT in TLV format, Base64-encoded. Generate the image in your application and embed it as a data: URI; Sahifa places it exactly as in your HTML.
<img src="data:image/png;base64,iVBORw0KGgo..." width="120" height="120" alt="ZATCA QR">
Our own test set generates such a code, renders the invoice and reads the code back from the PDF; it matches bit for bit. Keep the QR at least 25 mm wide so phones read it easily from paper.
Known limitation: fully vocalised text in the text layer
With dense diacritics (tashkeel), the text is drawn correctly, but the PDF's hidden text layer, used for search and copy, can miss the last letter of such a line. The printed page is not affected. If your users search inside PDFs, avoid full vocalisation in searchable fields such as names and numbers.