Renderizar HTML árabe da direita para a esquerda
Visão geral
Seção intitulada “Visão geral”Renderize HTML da direita para a esquerda (RTL) em PDF com writeHtml(). Defina a propriedade CSS direction: rtl e registre uma fonte com suporte a árabe. O motor reordena o texto para a ordem visual com o Algoritmo Bidirecional Unicode (UAX #9) e molda as letras árabes em formas contextuais. Esta receita renderiza uma pequena fatura em árabe. RTL é usado em árabe, hebraico, persa e urdu. O hebraico é reordenado, mas não moldado, o que é correto para essa escrita.
Instalação
Seção intitulada “Instalação”composer require nextpdf/coreVocê também precisa de uma fonte TrueType ou OpenType com suporte a árabe. O mapa de caracteres dela deve cobrir o bloco Arabic Presentation Forms-B. Noto Naskh Arabic e Amiri são fontes adequadas com licença aberta.
Visão geral conceitual
Seção intitulada “Visão geral conceitual”Você precisa de dois elementos para a renderização RTL: a propriedade CSS direction: rtl e uma fonte árabe registrada.
direction: rtl indica ao layout que posicione o texto da direita para a esquerda. O motor então usa o Algoritmo Bidirecional Unicode (UAX #9) para resolver a ordem visual. Conteúdo misto é ordenado corretamente: palavras em latim, palavras em árabe e dígitos preservam suas próprias direções. Um número que segue texto em árabe mantém os dígitos da esquerda para a direita.
O árabe é uma escrita cursiva, portanto cada letra usa um glifo diferente conforme seus vizinhos. O motor seleciona a forma inicial, medial, final ou isolada de cada letra e aplica a ligadura Lam-Alef. Essa moldagem contextual precisa de uma fonte cujo mapa de caracteres cubra o bloco Arabic Presentation Forms-B. Uma fonte apenas latina, incluindo as fontes standard-14, não consegue renderizar árabe.
Em uma tabela, cada célula é reordenada e moldada de forma independente, e as células se alinham à borda inicial: a borda direita sob direction: rtl. Os valores lógicos de text-align start e end são resolvidos em relação à direção; portanto, start mapeia para a borda direita em conteúdo RTL.
Defina a direção com a propriedade CSS direction. O atributo HTML dir não é mapeado para ela. Consulte RTL — limitações atuais para conhecer os limites atuais da implementação.
Superfície da API
Seção intitulada “Superfície da API”| Símbolo | Localização | Função |
|---|---|---|
Document::writeHtml(string $html): static | NextPDF\Core\Concerns\HasTextOutput | Renderiza o fragmento HTML na posição atual do cursor. |
FontRegistry::register(string $fontFile, string $alias = '', int $fontIndex = 0): FontInfo | NextPDF\Typography\FontRegistry | Registra a fonte árabe sob um alias. |
DocumentFactory::create(): Document | NextPDF\Core\DocumentFactory | Cria um documento que lê seu registro preenchido. |
O exemplo usa estas propriedades CSS: direction, font-family, text-align. Referencie a fonte registrada no CSS font-family pelo alias de registro.
Exemplo de código — Início rápido
Seção intitulada “Exemplo de código — Início 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');O título é renderizado da direita para a esquerda, e os dígitos 380.00 permanecem da esquerda para a direita dentro da frase em árabe.
Exemplo de código — Produção
Seção intitulada “Exemplo de código — Produção”Este exemplo autossuficiente renderiza uma tabela de fatura em árabe. Cada célula define direction: rtl e a fonte árabe registrada; com isso, o motor reordena e molda cada linha e, em seguida, alinha as células à borda direita.
<?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 extremos e pegadinhas
Seção intitulada “Casos extremos e pegadinhas”- Registre a fonte antes de construir o documento.
Document::createStandalone()constrói seu próprio registro e não consegue acessar uma fonte que você registrou em outro lugar. Construa por meio deDocumentFactorypara que o escritor leia seu registro, como fazem os dois exemplos. - Faça o CSS
font-familycorresponder ao alias de registro. O nome que você passa pararegister(..., alias: 'ArabicFont')é o nome que você referencia no CSS. - Use o CSS
direction, não o atributo HTMLdir. Apenas a propriedade CSS alterna o layout. - Um número após texto em árabe permanece da esquerda para a direita. Isso segue o UAX #9: um número europeu após uma letra árabe resolve-se como número árabe e mantém a ordem dos dígitos; portanto,
380.00não é invertido.
RTL — limitações atuais
Seção intitulada “RTL — limitações atuais”A implementação atual reordena e molda o texto RTL e alinha as células de tabela. As limitações abaixo permanecem. Cada uma depende de uma futura caixa de linha de formatação inline por linha:
- Alinhamento de bloco e inline fora de tabelas. Texto em nível de bloco e inline fora de células de tabela é reordenado e moldado, mas é renderizado a partir da borda inicial (esquerda). O alinhamento à direita ou ao centro para texto fora de tabela, e a distribuição
text-align: justify, ainda não são aplicados. As células de tabela são alinhadas. - O atributo HTML
dirnão mapeia paradirection. Defina a direção com a propriedade CSSdirection. - A resolução bidirecional é por sequência de texto (run). Caracteres neutros não são resolvidos entre dois elementos inline, como um
<span>ao lado de um<b>, na mesma linha. - Colunas árabes estreitas medem com base no texto lógico. As quebras de linha são medidas com base no texto lógico, anterior à moldagem, então uma coluna árabe muito estreita pode quebrar uma linha um pouco cedo ou tarde demais.
- O árabe moldado precisa da cobertura de Presentation Forms-B. A fonte deve cobrir o bloco Arabic Presentation Forms-B. Fontes que dependem apenas da substituição OpenType GSUB, e o caminho de moldagem HarfBuzz, ficam para trabalho futuro. Uma fonte não árabe não consegue renderizar árabe.
Desempenho
Seção intitulada “Desempenho”A renderização escala linearmente com o número de glifos. A reordenação bidirecional e a moldagem contextual são executadas por linha e adicionam um pequeno fator constante em relação ao texto da esquerda para a direita. O orçamento desta receita é wall_ms: 1500, peak_mb: 64.
Notas de segurança
Seção intitulada “Notas de segurança”Valide o comprimento das strings fornecidas pelo usuário para limitar o tamanho da saída. O motor renderiza o texto; ele não o interpreta nem executa scripts. Se você carregar uma fonte por meio de uma origem remota @font-face, a política de recurso externo seguro controla a busca; prefira um arquivo de fonte local para uma saída previsível.
Conformidade
Seção intitulada “Conformidade”| Declaração | Spec | Cláusula | reference_id |
|---|---|---|---|
| A ordem visual é produzida invertendo as sequências de caracteres do nível mais alto até o menor nível ímpar. | Unicode UAX #9 | §3.3.6 Rule L2 (uax9#3.3.6.p13) | 814977a77019d728dc562a612098a82dc260f6844f5998eca5fe7a3baf3394af |
| Um número europeu após uma letra árabe resolve-se como número árabe, então seus dígitos mantêm a ordem da esquerda para a direita. | Unicode UAX #9 | §3.3.4 Rule W2 (uax9#3.3.4.p9) | 5747405357772797d62b3f4ba79328557fa0c4273a1dd5ffa8d996f24c78e120 |
A moldagem contextual do árabe (formas inicial, medial, final e isolada, além da ligadura Lam-Alef) é uma capacidade verificada do motor, coberta pela suíte de testes, e não uma declaração de conformidade separada. Ela requer uma fonte cujo mapa de caracteres cubra o bloco Arabic Presentation Forms-B.
Contexto comercial
Seção intitulada “Contexto comercial”Não aplicável.
Consulte também
Seção intitulada “Consulte também”- HTML: subsistema de renderização HTML+CSS para PDF — o motor
writeHtml()e seu suporte a RTL. - Tipografia: registro de fontes, subsetting, CMap, codificação, BiDi — o motor bidirecional que resolve o UAX #9.
- Matriz de suporte de fontes e escritas — quais escritas cada classe de fonte pode renderizar.
- Renderizar HTML em uma página PDF — o ponto de partida para conteúdo da esquerda para a direita.