Bỏ qua để đến nội dung

Kết xuất HTML tiếng Ả Rập từ phải sang trái

Kết xuất HTML từ phải sang trái (RTL) thành PDF bằng writeHtml(). Đặt thuộc tính CSS direction: rtl và đăng ký phông chữ hỗ trợ tiếng Ả Rập. Engine sắp xếp lại văn bản theo thứ tự hiển thị bằng thuật toán hai chiều Unicode (UAX #9) và tạo hình các chữ cái tiếng Ả Rập thành các dạng theo ngữ cảnh. Công thức này kết xuất một hóa đơn tiếng Ả Rập nhỏ. RTL áp dụng cho tiếng Ả Rập, tiếng Hebrew, tiếng Ba Tư và tiếng Urdu. Tiếng Hebrew được sắp xếp lại nhưng không cần tạo hình; điều này phù hợp với hệ chữ đó.

Terminal window
composer require nextpdf/core

Bạn cũng cần một phông chữ TrueType hoặc OpenType hỗ trợ tiếng Ả Rập. Bản đồ ký tự của phông chữ đó phải bao phủ khối Arabic Presentation Forms-B. Noto Naskh Arabic và Amiri là các phông chữ có giấy phép mở phù hợp.

Để kết xuất RTL, bạn cần hai đầu vào: thuộc tính CSS direction: rtl và một phông chữ tiếng Ả Rập đã đăng ký.

direction: rtl cho hệ thống bố cục biết cần đặt văn bản từ phải sang trái. Sau đó engine dùng thuật toán hai chiều Unicode (UAX #9) để xác định thứ tự hiển thị. Nội dung hỗn hợp được sắp xếp đúng thứ tự: các từ Latin, các từ tiếng Ả Rập và các chữ số đều giữ hướng riêng của mình. Một số đứng sau văn bản tiếng Ả Rập vẫn giữ thứ tự chữ số từ trái sang phải.

Tiếng Ả Rập là hệ chữ nối nét, nên mỗi chữ cái dùng một glyph khác nhau tùy vào các chữ cái lân cận. Engine chọn dạng đầu, dạng giữa, dạng cuối hoặc dạng độc lập cho mỗi chữ cái và áp dụng chữ ghép Lam-Alef. Việc tạo hình theo ngữ cảnh này cần một phông chữ có bản đồ ký tự bao phủ khối Arabic Presentation Forms-B. Một phông chữ chỉ có Latin, kể cả các bộ chữ standard-14, không thể vẽ chữ Ả Rập.

Trong bảng, mỗi ô được sắp xếp lại và tạo hình riêng, rồi được căn về cạnh bắt đầu, tức cạnh phải khi dùng direction: rtl. Các giá trị text-align theo logic là startend được xác định dựa trên hướng, nên start ánh xạ tới cạnh phải đối với nội dung RTL.

Đặt hướng bằng thuộc tính CSS direction. Thuộc tính HTML dir không được ánh xạ sang thuộc tính này. Xem RTL — các giới hạn hiện tại để biết các ranh giới của bản triển khai hiện tại.

Ký hiệuVị tríVai trò
Document::writeHtml(string $html): staticNextPDF\Core\Concerns\HasTextOutputKết xuất đoạn HTML tại vị trí con trỏ hiện tại.
FontRegistry::register(string $fontFile, string $alias = '', int $fontIndex = 0): FontInfoNextPDF\Typography\FontRegistryĐăng ký bộ chữ tiếng Ả Rập dưới một bí danh.
DocumentFactory::create(): DocumentNextPDF\Core\DocumentFactoryTạo một tài liệu đọc registry mà bạn đã điền.

Ví dụ này dùng các thuộc tính CSS sau: direction, font-family, text-align. Trong CSS font-family, hãy tham chiếu phông chữ đã đăng ký bằng bí danh registry của nó.

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

Tiêu đề được kết xuất từ phải sang trái, còn các chữ số 380.00 vẫn giữ thứ tự từ trái sang phải bên trong câu tiếng Ả Rập.

Ví dụ độc lập này kết xuất một bảng hóa đơn tiếng Ả Rập. Mỗi ô có direction: rtl và phông chữ tiếng Ả Rập đã đăng ký, nên engine sắp xếp lại và tạo hình mọi dòng, rồi căn các ô về cạnh phải.

<?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";">
  • Đăng ký phông chữ trước khi bạn tạo tài liệu. Document::createStandalone() tự tạo registry riêng và không thể thấy một phông chữ bạn đã đăng ký ở nơi khác. Hãy tạo tài liệu qua DocumentFactory để trình ghi đọc registry của bạn, như trong cả hai mẫu mã.
  • Đảm bảo CSS font-family khớp với bí danh registry. Tên bạn truyền vào register(..., alias: 'ArabicFont') chính là tên bạn tham chiếu trong CSS.
  • Dùng CSS direction, không dùng thuộc tính HTML dir. Chỉ thuộc tính CSS mới đổi hướng bố cục.
  • Một số đứng sau tiếng Ả Rập vẫn giữ thứ tự từ trái sang phải. Điều này tuân theo UAX #9: số châu Âu đứng sau chữ cái tiếng Ả Rập được giải quyết thành số tiếng Ả Rập và vẫn giữ nguyên thứ tự chữ số, nên 380.00 không bị đảo ngược.

Bản triển khai hiện tại sắp xếp lại và tạo hình văn bản RTL, đồng thời căn các ô bảng. Các ranh giới sau vẫn còn. Trong tương lai, mỗi ranh giới sẽ cần một hộp dòng định dạng inline theo từng dòng:

  • Căn khối và inline bên ngoài bảng. Văn bản cấp khối và văn bản inline bên ngoài các ô bảng được sắp xếp lại và tạo hình, nhưng vẫn kết xuất từ cạnh bắt đầu (bên trái). Căn phải, căn giữa cho văn bản không phải bảng, cũng như phân bố text-align: justify, vẫn chưa được áp dụng. Các ô bảng thì có căn.
  • Thuộc tính HTML dir không ánh xạ tới direction. Hãy đặt hướng bằng thuộc tính CSS direction.
  • Việc giải quyết hai chiều diễn ra theo từng đoạn văn bản chạy. Các ký tự trung tính không được giải quyết qua ranh giới giữa hai phần tử inline, chẳng hạn một <span> đứng cạnh một <b>, trên cùng một dòng.
  • Các cột tiếng Ả Rập hẹp được đo dựa trên văn bản logic. Ngắt dòng được đo trên văn bản logic, trước khi tạo hình, nên một cột tiếng Ả Rập rất hẹp có thể ngắt dòng hơi sớm hoặc hơi muộn.
  • Tiếng Ả Rập đã tạo hình cần độ phủ Presentation Forms-B. Phông chữ phải bao phủ khối Arabic Presentation Forms-B. Việc hỗ trợ các phông chữ chỉ dựa vào thay thế OpenType GSUB, cùng đường tạo hình HarfBuzz, là công việc trong tương lai. Một phông chữ không phải tiếng Ả Rập không thể vẽ chữ Ả Rập.

Thời gian kết xuất tăng tuyến tính theo số lượng glyph. Việc sắp xếp lại hai chiều và tạo hình theo ngữ cảnh chạy theo từng dòng và chỉ thêm một hệ số hằng số nhỏ so với văn bản trái sang phải. Ngân sách của công thức này là wall_ms: 1500, peak_mb: 64.

Hãy xác thực độ dài của các chuỗi do người dùng cung cấp để giữ kích thước đầu ra trong giới hạn. Engine kết xuất văn bản, không diễn giải nội dung đó và không chạy bất kỳ script nào. Nếu bạn nạp một phông chữ qua nguồn @font-face từ xa, chính sách an toàn cho tài nguyên bên ngoài sẽ chi phối việc tải về; hãy ưu tiên một tệp phông chữ cục bộ để có đầu ra dễ dự đoán.

Phát biểuĐặc tảĐiều khoảnreference_id
Thứ tự hiển thị được tạo ra bằng cách đảo ngược các đoạn ký tự chạy từ cấp cao nhất xuống cấp lẻ thấp nhất.Unicode UAX #9§3.3.6 Rule L2 (uax9#3.3.6.p13)814977a77019d728dc562a612098a82dc260f6844f5998eca5fe7a3baf3394af
Một con số châu Âu đứng sau một chữ cái tiếng Ả Rập được giải quyết thành một con số tiếng Ả Rập, nên các chữ số của nó giữ thứ tự từ trái sang phải.Unicode UAX #9§3.3.4 Rule W2 (uax9#3.3.4.p9)5747405357772797d62b3f4ba79328557fa0c4273a1dd5ffa8d996f24c78e120

Việc tạo hình tiếng Ả Rập theo ngữ cảnh (các dạng đầu, giữa, cuối và độc lập cùng chữ ghép Lam-Alef) là một năng lực của engine đã được kiểm chứng và được bộ kiểm thử bao phủ, không phải một tuyên bố tuân thủ riêng. Nó đòi hỏi một phông chữ có bản đồ ký tự bao phủ khối Arabic Presentation Forms-B.

Không áp dụng.