Representar HTML en árabe de derecha a izquierda
De un vistazo
Sección titulada «De un vistazo»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.
Instalación
Sección titulada «Instalación»composer require nextpdf/coreTambié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.
Descripción conceptual
Sección titulada «Descripción conceptual»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.
Superficie de la API
Sección titulada «Superficie de la API»| Símbolo | Ubicación | Función |
|---|---|---|
Document::writeHtml(string $html): static | NextPDF\Core\Concerns\HasTextOutput | Representa el fragmento HTML en la posición actual del cursor. |
FontRegistry::register(string $fontFile, string $alias = '', int $fontIndex = 0): FontInfo | NextPDF\Typography\FontRegistry | Registra el tipo de letra árabe bajo un alias. |
DocumentFactory::create(): Document | NextPDF\Core\DocumentFactory | Crea 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.
Muestra de código — Inicio rápido
Sección titulada «Muestra de código — Inicio rápido»<?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.
Muestra de código — Producción
Sección titulada «Muestra de código — Producción»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";Casos límite y trampas
Sección titulada «Casos límite y trampas»- 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 medianteDocumentFactorypara que el escritor lea ese registro, como en ambas muestras. - Hacer coincidir el
font-familyde CSS con el alias del registro. El nombre que se pasa aregister(..., alias: 'ArabicFont')es el nombre al que se hace referencia en CSS. - Usar la propiedad CSS
direction, no el atributo HTMLdir. 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.00no se invierte.
RTL — limitaciones actuales
Sección titulada «RTL — limitaciones actuales»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
dirno se asigna adirection. Establecer la dirección con la propiedad CSSdirection. - 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.
Rendimiento
Sección titulada «Rendimiento»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.
Notas de seguridad
Sección titulada «Notas de seguridad»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.
Conformidad
Sección titulada «Conformidad»| Afirmación | Especificación | Cláusula | reference_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.
Contexto comercial
Sección titulada «Contexto comercial»No aplicable.
Véase también
Sección titulada «Véase también»- HTML: subsistema de representación de HTML+CSS a PDF — el motor
writeHtml()y su compatibilidad con RTL. - Tipografía: registro de fuentes, subconjuntos, CMap, codificación, BiDi — el motor bidireccional que resuelve UAX #9.
- Matriz de compatibilidad de fuentes y escrituras — qué escrituras puede representar cada clase de fuente.
- Representar HTML a una página PDF — el punto de partida de izquierda a derecha.