تخطَّ إلى المحتوى

عرض HTML عربي من اليمين إلى اليسار

اعرض HTML من اليمين إلى اليسار (RTL) في PDF باستخدام writeHtml(). اضبط خاصية CSS‏ direction: rtl وسجّل خطًا يدعم العربية. يعيد المحرك ترتيب النص بصريًا باستخدام خوارزمية Unicode ثنائية الاتجاه ‏(UAX #9)، ويشكّل الحروف العربية بحسب مواضعها السياقية. تعرض هذه الوصفة فاتورة عربية صغيرة. ينطبق RTL على العربية والعبرية والفارسية والأردية. أما العبرية فتُعاد ترتيبها فقط دون تشكيل، وهذا هو السلوك الصحيح لهذه الكتابة.

Terminal window
composer require nextpdf/core

تحتاج أيضًا إلى خط TrueType أو OpenType يدعم العربية. يجب أن يغطي جدول رموزه كتلة Arabic Presentation Forms-B. ويُعد Noto Naskh Arabic وAmiri خطين مناسبين ومفتوحي الترخيص.

لتمكين عرض RTL، تحتاج إلى مدخلين: خاصية CSS‏ direction: rtl وخط عربي مُسجَّل.

توجّه direction: rtl التخطيط إلى وضع النص من اليمين إلى اليسار. ثم يستخدم المحرك خوارزمية Unicode ثنائية الاتجاه ‏(UAX #9) لحل الترتيب البصري. يُرتَّب المحتوى المختلط ترتيبًا صحيحًا: تحتفظ الكلمات اللاتينية والكلمات العربية والأرقام باتجاهاتها الخاصة. والرقم الذي يلي نصًا عربيًا يحتفظ بترتيب أرقامه من اليسار إلى اليمين.

العربية كتابة متصلة، لذلك يتخذ كل حرف شكلًا رسوميًا مختلفًا بحسب الأحرف المجاورة له. يختار المحرك الشكل الابتدائي أو الوسطي أو الختامي أو المنفرد لكل حرف، ويطبّق رابطة Lam-Alef. يتطلب هذا التشكيل السياقي خطًا يغطي جدول رموزه كتلة Arabic Presentation Forms-B. ولا يستطيع خط لاتيني فقط، بما في ذلك وجوه الخطوط الأربعة عشر القياسية، رسم العربية.

داخل الجدول، يُعاد ترتيب محتوى كل خلية ويُشكَّل مستقلًا، وتُحاذى الخلايا إلى حافة البداية: الحافة اليمنى تحت direction: rtl. وتُحلّ قيمتا text-align المنطقيتان start وend وفق الاتجاه، فتشير start إلى الحافة اليمنى لمحتوى RTL.

اضبط الاتجاه بخاصية CSS‏ direction. ولا تُترجَم سمة HTML‏ dir إليها. راجع RTL — القيود الحالية لمعرفة حدود التنفيذ الحالية.

الرمزالموضعالدور
Document::writeHtml(string $html): staticNextPDF\Core\Concerns\HasTextOutputاعرض مقطع HTML عند موضع المؤشر الحالي.
FontRegistry::register(string $fontFile, string $alias = '', int $fontIndex = 0): FontInfoNextPDF\Typography\FontRegistryسجّل وجه الخط العربي باسم مستعار.
DocumentFactory::create(): DocumentNextPDF\Core\DocumentFactoryأنشئ مستندًا يقرأ السجل الذي ملأته.

يستخدم المثال خصائص CSS التالية: direction وfont-family وtext-align. أشِر في CSS‏ font-family إلى الخط المُسجَّل باستخدام اسمه المستعار في السجل.

نموذج الكود — البدء السريع

قسم بعنوان «نموذج الكود — البدء السريع»
<?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');

يظهر العنوان من اليمين إلى اليسار، وتبقى الأرقام 380.00 من اليسار إلى اليمين داخل الجملة العربية.

يعرض هذا المثال المستقل جدول فاتورة عربية. تستخدم كل خلية direction: rtl والخط العربي المُسجَّل، فيعيد المحرك ترتيب كل سطر ويُشكّله، ثم يحاذي الخلايا إلى الحافة اليمنى.

<?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";">
  • سجّل الخط قبل بناء المستند. تُنشئ Document::createStandalone() سجلها الخاص ولا يمكنها رؤية وجه خط سجّلته في موضع آخر. ابنِ المستند عبر DocumentFactory حتى يقرأ الكاتب سجلك، كما في النموذجين.
  • طابِق CSS‏ font-family مع الاسم المستعار في السجل. الاسم الذي تمرره إلى register(..., alias: 'ArabicFont') هو الاسم الذي تشير إليه في CSS.
  • استخدم CSS‏ direction، لا سمة HTML‏ dir. خاصية CSS وحدها هي التي تبدّل التخطيط.
  • الرقم الذي يلي العربية يبقى من اليسار إلى اليمين. يتبع هذا UAX #9: الرقم الأوروبي بعد حرف عربي يُحلّ إلى رقم عربي ويحتفظ بترتيب أرقامه، لذلك لا تُعكس 380.00.

يدعم التنفيذ الحالي إعادة ترتيب نص RTL وتشكيله ومحاذاة خلايا الجدول. وتظل هذه الحدود قائمة. ويحتاج كلٌّ منها مستقبلًا إلى صندوق سطر للتنسيق المضمّن لكل سطر:

  • محاذاة الكتل والمحتوى المضمّن خارج الجداول. يُعاد ترتيب النص الكتلي والمضمّن خارج خلايا الجدول ويُشكَّل، لكنه يُعرض من حافة البداية (اليسرى). ولم تُطبَّق بعد المحاذاة إلى اليمين أو الوسط للنص غير الجدولي، ولا توزيع text-align: justify. أما خلايا الجدول فتُحاذى فعلًا.
  • لا تُترجَم سمة HTML‏ dir إلى direction. اضبط الاتجاه بخاصية CSS‏ direction.
  • يُحلّ الاتجاه الثنائي لكل مقطع نص على حدة. لا تُحلّ المحارف المحايدة عبر عنصرَين مضمّنَين، مثل <span> بجوار <b>، على السطر نفسه.
  • تُقاس الأعمدة العربية الضيقة على النص المنطقي. تُقاس فواصل الأسطر على النص المنطقي السابق للتشكيل، لذلك قد يكسر عمود عربي ضيق جدًا السطر مبكرًا أو متأخرًا قليلًا.
  • يحتاج النص العربي المُشكَّل إلى تغطية Presentation Forms-B. يجب أن يغطي الوجه كتلة Arabic Presentation Forms-B. أما دعم الخطوط التي تعتمد فقط على استبدالات OpenType GSUB، ودعم مسار التشكيل HarfBuzz، فهما عمل مستقبلي. ولا يمكن لخط غير عربي رسم العربية.

يتناسب زمن العرض خطيًا مع عدد المحارف الرسومية. تُنفَّذ إعادة الترتيب الثنائي الاتجاه والتشكيل السياقي لكل سطر، وتضيف عاملًا ثابتًا صغيرًا مقارنة بالنص من اليسار إلى اليمين. وميزانية هذه الوصفة هي wall_ms: 1500, peak_mb: 64.

تحقّق من طول السلاسل النصية المُدخَلة من المستخدم لإبقاء حجم المُخرَج محدودًا. يعرض المحرك النص ولا يفسّره، ولا يشغّل أي سكربت. وإذا حمّلت خطًا من مصدر بعيد عبر @font-face، فإن سياسة الموارد الخارجية الآمنة تحكم عملية الجلب؛ ويُفضَّل استخدام ملف خط محلي للحصول على مُخرَج متوقَّع.

البيانالمواصفةالبندreference_id
يُنتَج الترتيب البصري بعكس مقاطع المحارف من أعلى مستوى نزولًا إلى أدنى مستوى فردي.Unicode UAX #9§3.3.6 Rule L2 (uax9#3.3.6.p13)814977a77019d728dc562a612098a82dc260f6844f5998eca5fe7a3baf3394af
الرقم الأوروبي بعد حرف عربي يُحلّ إلى رقم عربي، فتحتفظ أرقامه بالترتيب من اليسار إلى اليمين.Unicode UAX #9§3.3.4 Rule W2 (uax9#3.3.4.p9)5747405357772797d62b3f4ba79328557fa0c4273a1dd5ffa8d996f24c78e120

التشكيل السياقي للعربية (الأشكال الابتدائية والوسطية والختامية والمنفردة إضافةً إلى رابطة Lam-Alef) قدرة تم التحقق منها في المحرك وتغطّيها مجموعة الاختبارات، وليس ادعاء مطابقة مستقلًا. ويتطلب خطًا يغطي جدول رموزه كتلة Arabic Presentation Forms-B.

غير منطبق.