BlogBooks & scholarship8 min read
Check an Arabic EPUB before you publish it: direction, language, text
A clean EPUBCheck report does not mean an Arabic e-book is ready. Also confirm the package language is Arabic, the spine says rtl, every XHTML file carries lang and dir, the text is real Unicode rather than presentation forms or scanned images, and the digits are consistent. Then read sample pages in the store's own previewer.
You have an Arabic book as an EPUB: a classical edition someone digitized, a translation a typesetter laid out, or a scanned print book turned into a reflowable e-book. Before it goes to Kindle, Apple Books or a client, someone has to say it is ready. Most people run EPUBCheck, see "No errors or warnings detected" and stop there.
That is not enough for Arabic. EPUBCheck checks that the file follows the EPUB specification. It does not check that the book is declared as Arabic, that pages turn right-to-left, or that the words are searchable text. This guide gives five checks that cover those gaps, a short script that runs most of them in seconds, and what to read by eye afterwards. It is written for publishers, editors, translators and DTP staff who sign off on Arabic e-books, and for whoever prepares the files.
What we found when we tested EPUBCheck
While writing this guide we built two tiny one-chapter Arabic EPUB 3 files by hand and ran EPUBCheck 5.1.0 on both:
- File A declared
<dc:language>ar</dc:language>, setpage-progression-direction="rtl"on the spine, and putlang="ar"anddir="rtl"on every XHTML<html>element. - File B declared the book as English (
en), left the spine direction unset, had nolangordiron any page, used presentation-form characters for one word and mixed an Arabic-Indic ٢ with a Persian ۲ in a page number.
EPUBCheck reported "0 fatals / 0 errors / 0 warnings" for both. File B is valid EPUB. It is still a badly prepared Arabic book: a reading app may turn its pages the wrong way, apply English hyphenation and fonts, and fail to find words a reader searches for.
So keep EPUBCheck as the first gate (the W3C project page links the current release), and add the checks below.
Check 1: the book is declared as Arabic
The EPUB 3.3 specification makes dc:language a required element of the package metadata and
says reading systems treat the first dc:language as the primary language of the publication.
For an Arabic book that first value should be ar (or a regional tag such as ar-SA if you
have a reason to use one).
Two details trip people up:
- Converters often default to
en. A book exported from an English-language template, or by a tool whose default was never changed, will say English even when every word is Arabic. - The specification notes that content files do not inherit their language from
dc:language. Each XHTML file needs its ownlang(andxml:lang) on the<html>element. Check 3 covers that.
If you sell on Kindle, KDP's Arabic help page also asks that you choose Arabic as the book's language on the eBook details page, enter the title and author name in Arabic, and make the title page match those details. It lists mismatches here among the most common reasons Arabic files are rejected.
Check 2: pages turn right-to-left
Page-turn direction is set once, on the <spine> element of the package document, with
page-progression-direction. The allowed values are ltr, rtl and default. With
default, or with no attribute at all, the specification and Apple's Books asset guide both
say the reading system chooses the direction. Apple adds that Apple Books paginates
left-to-right by default.
For an Arabic book, set it explicitly:
<spine page-progression-direction="rtl">
KDP's Arabic page is blunter: Arabic is a right-to-left language, and files set to
left-to-right are rejected. Its instructions are written for Word manuscripts. For an EPUB,
the spine attribute and the dir attribute on each page are where direction is declared, so
check both.
Check 3: every page carries lang and dir
The spine controls which way pages turn. It does not set the direction of the text on each
page. That comes from the XHTML. The W3C Internationalization guidance is to add
dir="rtl" to the <html> element whenever a document's overall direction is right-to-left;
without it, HTML's base direction is left-to-right. Getting it right aligns paragraphs to the
right, puts punctuation on the correct side of mixed Arabic and Latin text, and runs table
columns right-to-left.
Each content file should open like this:
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ar" lang="ar" dir="rtl">
Don't forget the navigation document (the table of contents) and any title, copyright or
notes pages. They are separate XHTML files and are often generated from a template that
still says English. If a book mixes in a section that really is left-to-right, such as an
English introduction, give that section's file or element dir="ltr" and lang="en"
deliberately rather than leaving the attribute out.
Check 4: the words are real text
KDP asks for e-books that are reflowable and consist primarily of text, "not scanned pages from a physical book", because readers cannot change the text size of a scan. A digitized book can fail this in two ways that look fine at a glance:
- Image-only pages. Some conversions place each scanned page in the EPUB as a picture, sometimes with a hidden text layer. On a phone the reader sees a tiny fixed image, and search finds nothing.
- Presentation-form characters. Text pulled from some PDFs stores the shaped letter forms (the Unicode block from U+FE70) instead of ordinary Arabic letters. It can look right and still fail search, copy and text-to-speech. Our guide to reversed Arabic text after PDF to Word explains where these come from and how to normalize them, and Arabic search not finding words covers the other look-alike characters (hamza forms, tatweel, Persian kaf and yeh).
Check 5: digits and typos KDP names
KDP's Arabic page lists the typos it sees most: text shown as a tofu box (a missing glyph), numbers in place of letters and the reverse, misplaced tashkeel, broken spacing inside words, and extra characters added to a word. Two of those are easy to look for mechanically:
- Mixed digit systems. Arabic-Indic digits (٠-٩, U+0660-0669) and the extended Persian/Urdu digits (۰-۹, U+06F0-06F9) look alike in many fonts. In an Arabic book, a Persian ۲ or ۴ inside an Arabic-Indic number is usually an OCR slip. (In an Urdu book the extended digits are correct; see our Urdu OCR guide.)
- Tofu boxes. These come from the font, not the text. If the EPUB embeds a font, make sure it covers every character the book uses, including tashkeel and any Quranic marks.
The rest (tashkeel placement, split words, look-alike letters) needs a person reading against the source. Our pre-delivery QA checklist describes how to choose sample pages so the reading is worth the time.
A script that runs checks 1-5 in seconds
An EPUB is a ZIP file, so Python's standard library can read it. This script prints the
declared language and page direction, then lists any XHTML file without lang, without
dir="rtl", with presentation-form characters, with both digit systems, or with an image and
almost no text.
import re, sys, zipfile
def check(path):
z = zipfile.ZipFile(path)
container = z.read("META-INF/container.xml").decode("utf-8")
opf_path = re.search(r'full-path="([^"]+)"', container).group(1)
opf = z.read(opf_path).decode("utf-8")
langs = re.findall(r"<dc:language[^>]*>([^<]+)</dc:language>", opf)
spine = re.search(r"<spine[^>]*>", opf).group(0)
ppd = re.search(r'page-progression-direction="([^"]+)"', spine)
print("Language:", langs[0] if langs else "MISSING")
print("Page direction:", ppd.group(1) if ppd else "not set")
for name in z.namelist():
if not name.endswith((".xhtml", ".html", ".htm")):
continue
text = z.read(name).decode("utf-8")
html_tag = re.search(r"<html[^>]*>", text).group(0)
lang = re.search(r'\blang="([^"]+)"', html_tag)
direction = re.search(r'\bdir="([^"]+)"', html_tag)
body = re.sub(r"<[^>]+>", "", text.split("<body", 1)[-1])
forms = len(re.findall("[ﭐ-﷿ﹰ-]", body))
arabic_digits = bool(re.search("[٠-٩]", body))
persian_digits = bool(re.search("[۰-۹]", body))
problems = []
if not lang:
problems.append("no lang")
if not direction or direction.group(1) != "rtl":
problems.append("dir not rtl")
if forms:
problems.append(f"{forms} presentation-form characters")
if arabic_digits and persian_digits:
problems.append("mixed Arabic-Indic and Persian digits")
if "<img" in text and len(body.strip()) < 20:
problems.append("image with almost no text (scanned page?)")
print(f" {name}: {', '.join(problems) or 'ok'}")
check(sys.argv[1])
Save it as check_arabic_epub.py and run python3 check_arabic_epub.py book.epub. On the two
test files above (Python 3.11), File A printed "Language: ar", "Page direction: rtl" and "ok"
for both pages. File B printed "Language: en", "Page direction: not set", and for its chapter:
"no lang, dir not rtl, 4 presentation-form characters, mixed Arabic-Indic and Persian
digits". A third test file whose chapter held only an image was flagged "image with almost no
text (scanned page?)".
Treat the output as a list of places to look, not a verdict. A file with a deliberate
English section will rightly show dir other than rtl, and a short page such as a
dedication can trip the image check.
Illustrative example
A small publisher receives a 300-page classical text as an EPUB from a conversion vendor.
EPUBCheck passes. The script reports Language: en, Page direction: not set, dir not rtl
on all 40 content files, and mixed digits in three chapters. The fixes take minutes in the
package and XHTML files: change dc:language to ar, add page-progression-direction="rtl",
add lang/dir to each <html> element, and correct the digits after checking each one
against the scan. The publisher then re-runs EPUBCheck and the script, and reads the opening
pages, one page from each chapter that had flagged digits, and the table of contents in the
store's previewer before uploading.
Before you upload: checklist
- EPUBCheck reports no errors or warnings (current release)
- First
dc:languageisar(or a deliberate regional tag) -
<spine page-progression-direction="rtl"> - Every XHTML file, including the navigation document, has
lang="ar"anddir="rtl", or a deliberateltrfor a genuinely left-to-right section - No presentation-form characters; search for three words from the book and find them
- No image-only pages in the body of the book
- One digit system per number; Persian digits only where the language calls for them
- Embedded fonts cover all characters used, including tashkeel (no tofu boxes)
- Title, author and title page in Arabic and matching the store listing
- Opening pages, table of contents and one page per chapter read in the store's previewer (Kindle Previewer for KDP)
Where ScribeTools fits
ScribeTools converts scanned or photographed Arabic books into editable text, and EPUB is one of its outputs, so the result reflows on a phone instead of showing page images. See digitizing Arabic books for how that works. Whichever tool made your EPUB, run the checks above and review the text against the source before you publish or rely on it: conversion output always needs a human read.
Limitations
- We tested EPUBCheck 5.1.0 on small hand-built files. Later releases may add checks; run the current one and read its report rather than assuming it matches ours.
- The script reads only the
<html>element's attributes. It will not noticedirorlangset on<body>or on inner elements, or direction set through CSS, so a page it flags may be fine. It also uses simple patterns rather than a full XML parser. - We did not run Kindle Previewer or Apple Books for this guide. Store rules change; KDP's own Arabic page says its Arabic support is still improving. Check the current help pages.
- No script can tell you whether the Arabic is correct. Tashkeel, look-alike letters and missing words need a reader comparing against the source.
- This guide covers reflowable EPUB. Fixed-layout books (for example, illustrated children's books) have different rules.