Ir al contenido

Representar HTML en árabe de derecha a izquierda

Representar HTML de derecha a izquierda (RTL) en PDF con writeHtml(). Se debe establecer la propiedad CSS direction: rtl y registrar una fuente compatible con el árabe. El motor reordena el texto en orden visual mediante el Algoritmo Bidireccional de Unicode (UAX #9) y modela las letras árabes en formas contextuales. Esta receta muestra cómo representar una pequeña factura en árabe. RTL se aplica al árabe, el hebreo, el persa y el urdu. El hebreo se reordena, pero no se modela, lo cual es correcto para esa escritura.

Ventana de terminal
composer require nextpdf/core

También se necesita una fuente TrueType u OpenType compatible con el árabe. Su mapa de caracteres debe cubrir el bloque Arabic Presentation Forms-B. Noto Naskh Arabic y Amiri son tipos de letra adecuados con licencia abierta.

Para representar contenido RTL se necesitan dos entradas: la propiedad CSS direction: rtl y una fuente árabe registrada.

direction: rtl indica al motor de maquetación que coloque el texto de derecha a izquierda. A continuación, el motor utiliza el Algoritmo Bidireccional de Unicode (UAX #9) para resolver el orden visual. El contenido mixto se ordena correctamente: las palabras latinas, las palabras árabes y los dígitos conservan su propia dirección. Un número que sigue a texto árabe conserva sus dígitos de izquierda a derecha.

El árabe es una escritura cursiva; por eso, cada letra usa un glifo diferente según sus vecinas. El motor selecciona la forma inicial, medial, final o aislada de cada letra y aplica la ligadura Lam-Alef. Este modelado contextual requiere una fuente cuyo mapa de caracteres cubra el bloque Arabic Presentation Forms-B. Una fuente solo latina, incluidos los tipos de letra standard-14, no puede dibujar árabe.

En las tablas, cada celda se reordena y se modela por separado, y las celdas se alinean al borde inicial: el borde derecho con direction: rtl. Los valores lógicos de text-align start y end se resuelven según la dirección, por lo que start se asigna al borde derecho para el contenido RTL.

Establecer la dirección con la propiedad CSS direction. El atributo HTML dir no se asigna a ella. Consultar RTL: limitaciones actuales para conocer los límites actuales de la implementación.

SímboloUbicaciónFunción
Document::writeHtml(string $html): staticNextPDF\Core\Concerns\HasTextOutputRepresenta el fragmento HTML en la posición actual del cursor.
FontRegistry::register(string $fontFile, string $alias = '', int $fontIndex = 0): FontInfoNextPDF\Typography\FontRegistryRegistra el tipo de letra árabe bajo un alias.
DocumentFactory::create(): DocumentNextPDF\Core\DocumentFactoryCrea un documento que lee el registro que ha rellenado.

El ejemplo usa estas propiedades CSS: direction, font-family, text-align. Se debe hacer referencia a la fuente registrada en la propiedad CSS font-family mediante su alias de registro.

<?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');

El encabezado se representa de derecha a izquierda, y los dígitos 380.00 se mantienen de izquierda a derecha dentro de la frase árabe.

Este ejemplo autónomo representa una tabla de factura en árabe. Cada celda incluye direction: rtl y la fuente árabe registrada, de modo que el motor reordena y modela cada línea y, a continuación, alinea las celdas al borde derecho.

<?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";">
  • Registrar la fuente antes de construir el documento. Document::createStandalone() construye su propio registro y no puede ver un tipo de letra registrado en otro lugar. Crear el documento mediante DocumentFactory para que el escritor lea ese registro, como en ambas muestras.
  • Hacer coincidir el font-family de CSS con el alias del registro. El nombre que se pasa a register(..., alias: 'ArabicFont') es el nombre al que se hace referencia en CSS.
  • Usar la propiedad CSS direction, no el atributo HTML dir. Solo la propiedad CSS cambia la maquetación.
  • Un número después de texto árabe permanece de izquierda a derecha. Esto sigue UAX #9: un número europeo después de una letra árabe se resuelve como un número árabe y conserva el orden de sus dígitos, por lo que 380.00 no se invierte.

La implementación actual reordena y modela el texto RTL y alinea las celdas de tabla. Se mantienen estos límites. Cada uno requiere, a futuro, una caja de línea para el formato en línea por línea:

  • Alineación de bloque y en línea fuera de las tablas. El texto de bloque y en línea fuera de las celdas de tabla se reordena y se modela, pero se representa desde el borde inicial (izquierdo). La alineación a la derecha o al centro del texto fuera de tablas, así como la distribución de text-align: justify, todavía no se aplican. Las celdas de tabla sí se alinean.
  • El atributo HTML dir no se asigna a direction. Establecer la dirección con la propiedad CSS direction.
  • La resolución bidireccional se realiza por secuencia de texto. Los caracteres neutros no se resuelven entre dos elementos en línea, como un <span> junto a un <b>, en la misma línea.
  • Las columnas árabes estrechas se miden sobre el texto lógico. Los saltos de línea se calculan sobre el texto lógico, anterior al modelado, por lo que una columna árabe muy estrecha puede partir una línea un poco antes o después.
  • El árabe modelado necesita cobertura de Presentation Forms-B. El tipo de letra debe cubrir el bloque Arabic Presentation Forms-B. Las fuentes que dependen únicamente de la sustitución OpenType GSUB, y la ruta de modelado de HarfBuzz, son trabajo futuro. Una fuente no árabe no puede dibujar árabe.

La representación escala linealmente con el número de glifos. El reordenamiento bidireccional y el modelado contextual se ejecutan por línea y añaden un pequeño factor constante respecto del texto de izquierda a derecha. El presupuesto de esta receta es wall_ms: 1500, peak_mb: 64.

Validar la longitud de las cadenas proporcionadas por el usuario para mantener acotado el tamaño de la salida. El motor representa el texto; no lo interpreta ni ejecuta scripts. Si se carga una fuente a través de un origen remoto @font-face, la política de recursos externos seguros rige la obtención; preferir un archivo de fuente local para una salida predecible.

AfirmaciónEspecificaciónCláusulareference_id
El orden visual se produce invirtiendo las secuencias de caracteres desde el nivel más alto hasta el nivel impar más bajo.Unicode UAX #9§3.3.6 Rule L2 (uax9#3.3.6.p13)814977a77019d728dc562a612098a82dc260f6844f5998eca5fe7a3baf3394af
Un número europeo después de una letra árabe se resuelve como un número árabe, por lo que sus dígitos conservan el orden de izquierda a derecha.Unicode UAX #9§3.3.4 Rule W2 (uax9#3.3.4.p9)5747405357772797d62b3f4ba79328557fa0c4273a1dd5ffa8d996f24c78e120

El modelado contextual del árabe (formas inicial, medial, final y aislada más la ligadura Lam-Alef) es una capacidad del motor verificada y cubierta por el conjunto de pruebas, no una afirmación de conformidad independiente. Requiere una fuente cuyo mapa de caracteres cubra el bloque Arabic Presentation Forms-B.

No aplicable.