Aller au contenu

Afficher du HTML arabe de droite à gauche

Rends du HTML de droite à gauche (RTL) au format PDF avec writeHtml(). Définis la propriété CSS direction: rtl et enregistre une police compatible avec l’arabe. Le moteur réordonne le texte dans l’ordre visuel avec l’algorithme bidirectionnel Unicode (UAX #9) et met en forme les lettres arabes selon leurs formes contextuelles. Cette recette génère une petite facture en arabe. Le mode RTL s’applique à l’arabe, à l’hébreu, au persan et à l’ourdou. L’hébreu est réordonné, mais pas mis en forme, ce qui est correct pour cette écriture.

Fenêtre de terminal
composer require nextpdf/core

Il te faut aussi une police TrueType ou OpenType compatible avec l’arabe. Sa table de caractères doit couvrir le bloc Arabic Presentation Forms-B. Noto Naskh Arabic et Amiri sont des polices sous licence ouverte qui conviennent.

Le rendu RTL nécessite deux éléments en entrée : la propriété CSS direction: rtl et une police arabe enregistrée.

direction: rtl indique à la mise en page de placer le texte de droite à gauche. Le moteur utilise ensuite l’algorithme bidirectionnel Unicode (UAX #9) pour résoudre l’ordre visuel. Le contenu mixte est ordonné correctement : les mots latins, les mots arabes et les chiffres conservent chacun leur propre direction. Un nombre qui suit du texte arabe conserve ses chiffres de gauche à droite.

Comme l’arabe est une écriture cursive, chaque lettre utilise un glyphe différent selon ses voisines. Le moteur sélectionne la forme initiale, médiane, finale ou isolée pour chaque lettre et applique la ligature Lam-Alef. Cette mise en forme contextuelle nécessite une police dont la table de caractères couvre le bloc Arabic Presentation Forms-B. Une police uniquement latine, y compris les fontes standard-14, ne peut pas dessiner l’arabe.

Dans un tableau, chaque cellule est réordonnée et mise en forme individuellement, et les cellules s’alignent sur le bord de début : le bord droit sous direction: rtl. Les valeurs logiques start et end de text-align sont résolues selon la direction ; start correspond donc au bord droit pour un contenu RTL.

Définis la direction avec la propriété CSS direction. L’attribut HTML dir n’est pas relié à cette propriété. Consulte RTL — limites actuelles pour connaître les limites actuelles de l’implémentation.

SymboleEmplacementRôle
Document::writeHtml(string $html): staticNextPDF\Core\Concerns\HasTextOutputRend le fragment HTML à la position actuelle du curseur.
FontRegistry::register(string $fontFile, string $alias = '', int $fontIndex = 0): FontInfoNextPDF\Typography\FontRegistryEnregistre la police arabe sous un alias.
DocumentFactory::create(): DocumentNextPDF\Core\DocumentFactoryCrée un document qui utilise le registre renseigné.

L’exemple utilise ces propriétés CSS : direction, font-family, text-align. Fais référence à la police enregistrée dans la propriété CSS font-family via son alias de registre.

<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Core\DocumentFactory;
use NextPDF\Graphics\ImageRegistry;
use NextPDF\Typography\FontRegistry;
$fontRegistry = new FontRegistry();
$fontRegistry->register(__DIR__ . '/NotoNaskhArabic-Regular.ttf', alias: 'ArabicFont');
$documentFactory = new DocumentFactory($fontRegistry, new ImageRegistry(maxCacheBytes: 0));
$doc = $documentFactory->create();
$doc->addPage();
$doc->writeHtml(
'<div style="direction: rtl; font-family: \'ArabicFont\';">'
. '<h1>فاتورة</h1>'
. '<p>المبلغ الإجمالي 380.00</p>'
. '</div>'
);
$doc->save(__DIR__ . '/rtl-arabic.pdf');

Le titre s’affiche de droite à gauche, et les chiffres 380.00 restent de gauche à droite dans la phrase en arabe.

Cet exemple autonome génère un tableau de facture en arabe. Chaque cellule déclare direction: rtl et la police arabe enregistrée, afin que le moteur réordonne et mette en forme chaque ligne, puis aligne les cellules sur le bord droit.

<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Core\DocumentFactory;
use NextPDF\Graphics\ImageRegistry;
use NextPDF\Typography\FontRegistry;
// Supply an Arabic-capable face whose cmap covers Arabic Presentation Forms-B.
// Embed only fonts you are licensed to embed.
$fontPath = __DIR__ . '/NotoNaskhArabic-Regular.ttf';
if (!is_file($fontPath)) {
fwrite(STDERR, "Arabic font not found at {$fontPath}\n");
exit(1);
}
$fontRegistry = new FontRegistry();
$fontRegistry->register($fontPath, alias: 'ArabicFont');
$documentFactory = new DocumentFactory($fontRegistry, new ImageRegistry(maxCacheBytes: 0));
$doc = $documentFactory->create();
$doc->setTitle('Arabic invoice');
$doc->addPage();
$html = <<<'HTML'
<div style="direction: rtl; font-family: 'ArabicFont'; font-size: 12pt;">
<h1>فاتورة</h1>
<table style="width: 100%; border-collapse: collapse;">
<tr>
<th style="border: 1px solid #333; padding: 6px;">الوصف</th>
<th style="border: 1px solid #333; padding: 6px;">المبلغ</th>
</tr>
<tr>
<td style="border: 1px solid #333; padding: 6px;">خدمات استشارية</td>
<td style="border: 1px solid #333; padding: 6px;">380.00</td>
</tr>
<tr>
<td style="border: 1px solid #333; padding: 6px;">الإجمالي</td>
<td style="border: 1px solid #333; padding: 6px;">380.00</td>
</tr>
</table>
</div>
HTML;
$doc->writeHtml($html);
$out = getenv('NEXTPDF_OUT');
$doc->save($out !== false ? $out : __DIR__ . '/render-rtl-arabic-html.pdf');
echo "Wrote the Arabic invoice PDF\n";
HTML;$doc->writeHtml($html);$out = getenv('NEXTPDF_OUT');$doc->save($out !== false ? $out : __DIR__ . '/render-rtl-arabic-html.pdf');echo "Wrote the Arabic invoice PDF\n";">
  • Enregistre la police avant de construire le document. Document::createStandalone() construit son propre registre et ne peut pas voir une police que tu as enregistrée ailleurs. Construis le document via DocumentFactory pour que le moteur d’écriture lise ton registre, comme dans les deux exemples.
  • Fais correspondre la propriété CSS font-family à l’alias de registre. Le nom que tu passes à register(..., alias: 'ArabicFont') est celui auquel tu fais référence dans le CSS.
  • Utilise la propriété CSS direction, pas l’attribut HTML dir. Seule la propriété CSS bascule la mise en page.
  • Un nombre placé après du texte arabe reste de gauche à droite. Cela suit UAX #9 : un nombre européen après une lettre arabe se résout en nombre arabe et conserve l’ordre de ses chiffres, donc 380.00 n’est pas inversé.

L’implémentation actuelle réordonne et met en forme le texte RTL, et aligne les cellules de tableau. Les limites suivantes subsistent. Chacune nécessitera, à l’avenir, une boîte de ligne capable de gérer la mise en forme en ligne, ligne par ligne :

  • Alignement de bloc et en ligne hors des tableaux. Le texte de niveau bloc et en ligne situé hors des cellules de tableau est réordonné et mis en forme, mais il s’affiche depuis le bord de début (gauche). L’alignement à droite ou au centre du texte hors des tableaux, ainsi que la distribution text-align: justify, ne sont pas encore appliqués. Les cellules de tableau, en revanche, s’alignent.
  • L’attribut HTML dir n’est pas relié à direction. Définis la direction avec la propriété CSS direction.
  • La résolution bidirectionnelle s’effectue par séquence de texte. Les caractères neutres ne sont pas résolus entre deux éléments en ligne, par exemple un <span> à côté d’un <b>, sur la même ligne.
  • Les colonnes arabes étroites sont mesurées sur le texte logique. Les sauts de ligne sont mesurés sur le texte logique, avant la mise en forme, donc une colonne arabe très étroite peut couper une ligne légèrement trop tôt ou trop tard.
  • La mise en forme de l’arabe nécessite la couverture Presentation Forms-B. La police doit couvrir le bloc Arabic Presentation Forms-B. Les polices qui reposent uniquement sur la substitution OpenType GSUB, ainsi que le chemin de mise en forme HarfBuzz, restent des travaux futurs. Une police non arabe ne peut pas dessiner l’arabe.

Le rendu évolue linéairement avec le nombre de glyphes. Le réordonnancement bidirectionnel et la mise en forme contextuelle s’exécutent par ligne, avec un petit facteur constant supplémentaire par rapport au texte de gauche à droite. Le budget de cette recette est wall_ms: 1500, peak_mb: 64.

Valide la longueur des chaînes fournies par l’utilisateur pour borner la taille de sortie. Le moteur rend le texte, ne l’interprète pas et n’exécute aucun script. Si tu charges une police via une source @font-face distante, la politique sécurisée des ressources externes régit la récupération ; privilégie un fichier de police local pour une sortie prévisible.

ÉnoncéSpécificationClausereference_id
L’ordre visuel est produit en inversant les séquences de caractères depuis le niveau le plus élevé jusqu’au niveau impair le plus bas.Unicode UAX #9§3.3.6 Rule L2 (uax9#3.3.6.p13)814977a77019d728dc562a612098a82dc260f6844f5998eca5fe7a3baf3394af
Un nombre européen après une lettre arabe se résout en nombre arabe, donc ses chiffres conservent l’ordre de gauche à droite.Unicode UAX #9§3.3.4 Rule W2 (uax9#3.3.4.p9)5747405357772797d62b3f4ba79328557fa0c4273a1dd5ffa8d996f24c78e120

La mise en forme contextuelle de l’arabe (formes initiale, médiane, finale et isolée, plus la ligature Lam-Alef) est une capacité du moteur, vérifiée et couverte par la suite de tests, et non une revendication de conformité distincte. Elle nécessite une police dont la table de caractères couvre le bloc Arabic Presentation Forms-B.

Sans objet.