Dev.to WebDev 🛠 Dev 👁 0 📖 2 min read

Arabic PDFs are broken in most renderers. Here's how I fixed it.

I needed to generate PDF invoices for Arabic-speaking clients from HTML templates. Sounds simple. It wasn't — most HTML-to-PDF tools mangle Arabic text in ways that are embarrassing to send to a paying client. This is t

Arabic PDFs are broken in most renderers. Here's how I fixed it.

I needed to generate PDF invoices for Arabic-speaking clients from HTML templates. Sounds simple. It wasn't — most HTML-to-PDF tools mangle Arabic text in ways that are embarrassing to send to a paying client.

This is the story of the three things that go wrong, and how I fixed each one in my own rendering setup.

Problem 1: boxes instead of letters (□□□□)

The classic. Your PDF shows empty boxes where Arabic text should be.

This is almost never a bug in your HTML. It means the machine doing the rendering doesn't have an Arabic font installed. Your laptop has one, so it looks fine in your browser — but the server or Docker container doing the render has nothing, and the PDF renderer silently substitutes... nothing.

The fix: install a proper Arabic font on the render machine. I use Noto Naskh Arabic (great for body text) and Noto Kufi Arabic (great for headings). On Debian:

apt-get install fonts-noto-core
fc-cache -f

And verify what the renderer can actually see with fc-list | grep -i arab. Don't rely on a CSS webfont alone — the PDF engine needs the font locally.

Problem 2: disconnected letters

Arabic letters change shape depending on their neighbors — that's the whole script. Some renderers don't do this "shaping" step, so you get letters standing apart like isolated blocks. It looks broken because it is broken.

This is where your choice of engine matters:

  • wkhtmltopdf: uses a WebKit fork from ~2015. It does not shape Arabic correctly. I wouldn't start a new project on it.
  • WeasyPrint: shapes correctly, good CSS support, no browser needed. Great if your pages don't need JavaScript.
  • Headless Chromium (what I use): shapes correctly, full modern CSS/JS. Heavier, but it renders what the browser renders.

If your invoices need JavaScript to render, Chromium is the only serious option of the three.

Problem 3: the direction is wrong

Even with the right font and shaping, some engines need explicit hints. Always set both on your HTML:

<html lang="ar" dir="rtl">

Without dir="rtl", mixed content (Arabic text with numbers, prices, Latin brand names) lays out in the wrong order, and you'll spend hours thinking it's a font bug.

Putting it together

My setup: HTML invoice template → headless Chromium with Noto Arabic fonts installed in the worker → PDF out. Here's the actual invoice this produces:

Arabic RTL invoice rendered to PDF

Proper glyphs, correct right-to-left layout, connected letters, prices in دج rendering exactly where they should.

I run this as a small API I built for my own freelance work (Snapframe) — POST some HTML, get a PDF back. There's a live demo where you can try it on your own page: https://snapframe.mooo.com

If you're fighting Arabic PDFs right now, check the three things in order: fonts on the render machine, an engine that shapes text, and dir="rtl". Nine times out of ten, it's one of those.

I'm Abdelkader, a systems & security engineer from Algiers. I write about rendering, automation, and the unglamorous parts of running infrastructure.

📰 Read the original article on Dev.to WebDev

Originally published by Dev.to WebDev. Aggregated on AIWithGhost for educational purposes — full credit and traffic to the original publisher.