Erzeugung von arabischen / RTL-PDFs
Naiver reportlab-Code produziert Arabisch, das subtil und durchgehend falsch ist: Buchstaben erscheinen unverbunden, Wörter innerhalb einer Zeile laufen rückwärts, und Zeilen innerhalb eines Absatzes tauschen die Plätze. Nichts davon ist im extrahierten Text sichtbar – nur in einer Darstellung. Dieses Skill bündelt einen Builder, der diese Probleme bereits gelöst hat.
Verwenden Sie scripts/arabic_pdf.py anstatt die Neuanordnungslogik von Grund auf neu zu schreiben.
Jeder Fehlermodus unten wurde durch Auftreten in einem echten Dokument gefunden.
Abhängigkeiten
pip install reportlab arabic-reshaper python-bidi pypdfium2
pypdfium2 wird nur für die Vorschau benötigt, aber die Vorschau ist nicht optional – siehe Überprüfung unten.
Erstellen eines Dokuments
Importieren Sie den Builder, indem Sie entweder scripts/arabic_pdf.py neben Ihr Erstellungsskript kopieren oder den scripts/-Ordner dieses Skills zu sys.path hinzufügen:
import pathlib, sys
sys.path.insert(0, str(pathlib.Path.home() / ".claude" / "skills" / "arabic-pdf" / "scripts"))
from arabic_pdf import ArabicPDF, preview
pdf = ArabicPDF("report.pdf", doc_title="عنوان المستند", page_numbers=True)
pdf.title("عنوان المستند")
pdf.subtitle("سطر فرعي")
pdf.heading("أولاً — المقدمة")
pdf.para("فقرة عربية تتضمن مصطلحات لاتينية مثل PostgreSQL و FastAPI.")
pdf.heading("ثانياً — جدول")
pdf.table(
["البند", "التفصيل"], # rechteste Spalte zuerst
[["الواجهة الخلفية", "Python — FastAPI"],
["قاعدة البيانات", "PostgreSQL — SQLAlchemy"]],
[5.0, 11.0], # Spaltenbreiten in cm
)
pdf.bullets(["نقطة أولى", "نقطة ثانية"])
pdf.save()
preview("report.pdf") # ein PNG pro Seite
Passen Sie den Pfad an, falls das Skill woanders liegt – nichts anderes im Builder hängt davon ab, wo es installiert ist.
Methoden können verkettet werden, sodass pdf.heading(...).para(...) ebenfalls funktioniert.
| Methode | Zweck |
|---|---|
title / subtitle | Zentrierter Dokumentenkopf |
heading | Rechtsbündiger, fetter Abschnittstitel |
para | Textabsatz |
bullets(items, marker="–") | Ein rechtsbündiger Eintrag pro Element |
table(header, rows, widths_cm) | RTL-Tabelle; natürliche Lesereihenfolge in der Eingabe, umgekehrte Spalten in der Ausgabe |
spacer(pts) / page_break() | Layoutsteuerung |
save() | Schreibt die Datei, gibt den Pfad zurück |
Zell- und Absatztexte können \n enthalten, um einen Zeilenumbruch zu erzwingen.
Überprüfung – immer rendern und ansehen
Rufen Sie nach save() die Funktion preview() auf und betrachten Sie die PNGs mit dem Read-Tool. Textextraktion kann RTL-Fehler nicht erkennen, da alle Zeichen vorhanden und korrekt sind; nur ihre Reihenfolge und Form sind falsch. Überprüfen Sie gezielt:
- Steht das erste Wort jedes Absatzes oben rechts?
- Sind lateinische Begriffe (
PostgreSQL,FastAPI) an der richtigen Position im Satz, anstatt an den linken Rand der Zeile zu springen? - Sind die Buchstaben verbunden oder stehen sie getrennt wie
ا ل س ل ا م? - Gibt es schwarze Kästchen? Die Schriftart hat diese Glyphen nicht – wählen Sie eine andere.
- Zeigen Klammern in die richtige Richtung –
(20 فأكثر)nicht)20 فأكثر(? - Bleiben Paare in lateinischen Begriffen intakt –
Array<String>,DECIMAL(5,2)? - Wurde eine einzelne Tabellenzeile auf die nächste Seite verschoben?
Die Behebung eines Fehlers, den Sie nie gesucht haben, kostet später viel mehr, wenn das Dokument bereits beim Empfänger ist.
Wie die Korrektheit erreicht wird
Nützlich, wenn Sie den Builder anpassen oder ein ungewöhnliches Dokument debuggen.
- Formgebung –
arabic_reshaperordnet Zeichen positionellen Präsentationsformen zu, sodass Buchstaben verbunden werden. - Bidi mit expliziter Basisrichtung –
get_display(..., base_dir="R"). Ohnebase_dirwird die Richtung aus dem ersten starken Zeichen abgeleitet, sodass eine Zeile, die mit einem lateinischen Wort beginnt, von links nach rechts angeordnet wird und das Arabische danach falsch landet. Dies ist der häufigste Grund für „meistens richtig, aber einige Zeilen sind durcheinandergeraten". - Manueller Zeilenumbruch – umgeformter Text liegt in visueller Reihenfolge vor. Wenn reportlab ihn umbricht, sind die auf die nächste Zeile verschobenen Wörter die logisch ersten, sodass Zeilen durcheinandergeraten. Der Builder bricht zuerst um, formt jede Zeile separat um und verbindet sie mit
<br/>, sodass reportlab nie neu umbricht. Ein 8-Punkt-Sicherheitsabstand gleicht Messunterschiede aus; eine Zeile, die um einen Punkt überläuft, reicht aus, um sie umzukehren. - Spiegelung –
get_displayordnet neu, wendet aber nie die Bidi-Regel L4 an, die besagt, dass ein gespiegeltes Zeichen, das rechts-nach-links angeordnet wird, als sein Gegenstück gezeichnet wird. Ohne dies kommt(20 فأكثر)mit den beiden Klammern in vertauschten Positionen und ihren ursprünglichen Glyphen zurück und gibt)20 فأكثر(aus.prepare()ersetzt sie zuerst, sodass die Neuordnung die korrekte Glyphe verschiebt. - Lateinische Inseln –
<und>werden gespiegelt, sind aber keine Unicode-Klammerpaare, sodass die Regel, dieDECIMAL(5,2)zusammenhält, sie nicht abdeckt; das>vonArray<String>übernimmt die Richtung des Arabischen dahinter und wird an die ferne Seite geworfen. Jeder lateinische Bereich wird inLRI…PDIeingeschlossen und die Isolate werden nach der Neuordnung wieder entfernt, sodass nichts Unsichtbares ins PDF gelangt. - Escape nach der Formgebung – reportlab benötigt Escaping von
&,<,>, aber das zuerst durchgeführte Escaping sendet<als vier Zeichen durch den Bidi-Durchlauf, und sein nachgestelltes;wird an die ferne Seite der Zeile ausgeworfen. Erst formen, dann escapen. - Umgekehrte Tabellenspalten – reportlab ordnet Spalten von links nach rechts an, daher kehrt der Builder sie um, sodass Sie Spalten in natürlicher Lesereihenfolge übergeben können.
KeepTogetherbei Tabellen – verhindert, dass eine einzelne Zeile auf einer neuen Seite strandet.
Die Punkte 4–6 sind die gleiche Fehlerklasse wie die getrennten Klammerläufe, die in arabic-docx beschrieben sind, nur von der entgegengesetzten Seite betrachtet: Dort darf ein Paar nicht über Läufe getrennt werden, hier darf ein Paar nicht halb gespiegelt werden. Jedes gespiegelte Zeichen muss zusammen mit seinem Gegenstück aufgelöst werden.
Schriftarten
register_fonts() sucht nach einer arabisch-fähigen Schriftart: Arial, dann Tahoma unter Windows, Arial unter macOS, Noto Naskh Arabic, dann DejaVu Sans unter Linux. Um eine bestimmte Schriftart zu verwenden (Amiri und Cairo eignen sich gut für formelle Dokumente):
from arabic_pdf import register_fonts
register_fonts("/pfad/Amiri-Regular.ttf", "/pfad/Amiri-Bold.ttf") # vor ArabicPDF(...)
Reportlabs integrierte Schriftarten haben keine Arabisch-Unterstützung, daher muss eine TTF registriert werden – das ist der Grund, warum eine fehlende Schriftart als schwarze Kästchen und nicht als Fehler angezeigt wird.
Übertragen Sie diesen Ansatz niemals auf Word oder PowerPoint
Dies ist die wichtigste Grenze in der gesamten Familie der RTL-Skills.
| reportlab / Pillow | Word / PowerPoint | |
|---|---|---|
| Text-Engine | keine | vollständige bidirektionale Engine |
| Erwartet | endgültige visuelle Glyphen | rohen logischen Unicode |
| Technik | Formen + Bidi + manueller Umbruch | Richtungsflags im XML |
Vorformatierung ist hier erforderlich und dort zerstörerisch: Word und PowerPoint formen zur Renderzeit, daher führt die Übergabe von Präsentationsformen dazu, dass sie ein zweites Mal formen – defekte Glyphen und Text, der nicht mehr durchsucht, kopiert oder rechtschreibgeprüft werden kann. Die beiden Ansätze sind Gegensätze, keine Variationen.
Verwenden Sie arabic-docx für .docx und arabic-pptx für .pptx. Portieren Sie keinen Code zwischen den drei, ohne noch einmal zu lesen, warum sie sich unterscheiden.
Hinweise
arabic_digits("38")→"٣٨"wenn arabisch-indische Ziffern gewünscht sind. Rein kosmetisch; westliche Ziffern sind im arabischen technischen Schreiben völlig normal.- Halten Sie die Formatierung standardmäßig zurückhaltend – schwarzer Text, dünne Linien. Akademische und offizielle arabische Dokumente wirken so glaubwürdiger, und Benutzer, die „einfach" fordern, meinen es ernst.
- Dieselbe Mechanik behandelt Persisch, Urdu und Hebräisch; nur die Schriftart muss die Schrift abdecken.
Woran man erzeugtes Arabisch als erzeugt erkennt
Nicht am Wortschatz – an den Hinzufügungen. Jede der folgenden Gewohnheiten verrät dem Leser etwas darüber, wie das Dokument geschrieben wurde, anstatt über seinen Gegenstand, und ein Leser, der von Hand korrigiert, löscht sie alle. Schreiben Sie den Satz, nicht den Bericht über das Schreiben.
| Gewohnheit | Statt | Schreiben Sie |
|---|---|---|
| Den Schreibakt beschreiben | «الشروط ثلاثة، نذكرها صراحة فيما يلي» | «الشروط ثلاثة:» |
| Auf einen anderen Abschnitt verweisen | «…ونعود إلى هذه النقطة لاحقاً» | Löschen Sie die Phrase |
| Versions- oder Statusbezeichnungen in einem Titel | «الخطة (النسخة الثانية — معتمدة)» | «الخطة» |
| Gegen eine Option argumentieren, die niemand vorgebracht hat | «نحفظ المسار فقط. تخزين الملف كاملاً يضخّم الحجم بلا فائدة.» | «نحفظ المسار فقط.» |
| Eine Wahl damit rechtfertigen, dass die Aufgabe etwas ausgelassen hat | «لم يرد ذلك في الطلب، غير أن طبيعة العمل تفرضه.» | «طبيعة العمل تفرض ذلك.» |
| Erste Person Singular | «وأستطيع لاحقاً تحليل الحالات» | «ويمكن لاحقاً تحليل الحالات» |
| Eine Tatsache wiederholen, die das Dokument bereits nennt | Wiederholung der Information in einem anderen Abschnitt | Löschen Sie die Wiederholung |
Formelles Arabisch bevorzugt die unpersönliche oder die Pluralform gegenüber «أنا»; die Einzahl liest sich wie eine Notiz an sich selbst und nicht wie ein Dokument.