لماذا يحدث هذا
النص العربي على الشاشة يُخزَّن في ترتيب الكتابة، ثم يقرر المتصفح كيف يرسمه بقواعد اسمها خوارزمية الاتجاه الثنائي (Unicode Bidirectional Algorithm). هذه الخوارزمية تقسم الرموز إلى ثلاث فئات:
- رموز قوية: الحروف العربية اتجاهها من اليمين، والحروف اللاتينية من اليسار. هذه تحسم اتجاه ما حولها.
- رموز ضعيفة: الأرقام وعلامات مثل + و %. لها اتجاه داخلي من اليسار، لكنها لا تحسم موضعها في الجملة.
- رموز محايدة: المسافات والأقواس والنقاط والشرطات وعلامات الاستفهام. هذه تأخذ اتجاه الجار، وهنا تبدأ المشاكل.
حين يقع رمز محايد بين مقطع عربي ومقطع لاتيني، أو في آخر السطر بعد كلمة إنجليزية، تضعه الخوارزمية في مكان منطقي حسابياً لكنه خطأ في عين القارئ. هذه أمثلة حقيقية من مواقع سعودية:
| ما كتبته | ما قد يظهر للزائر | السبب |
|---|---|---|
| الباقة (Pro) متاحة | الباقة (Pro( متاحة أو أقواس معكوسة | القوس المحايد أخذ اتجاه الكلمة اللاتينية |
| اتصل على +966 50 123 4567 | اتصل على 50 123 4567+966 | علامة + ضعيفة فانتقلت لطرف المقطع |
| جهاز iPhone 15 Pro. | النقطة تظهر في بداية السطر | النقطة المحايدة بعد كلمة لاتينية في نهاية الفقرة |
| رقم الطلب: #A-1042 | 1042-A# بترتيب مقلوب | حروف وأرقام ورموز في مقطع واحد |
| تم الدفع عبر Apple Pay (مدى) | الأقواس تلتف حول الكلمة الخطأ | مقطع لاتيني متبوع بقوس ونص عربي |
المهم أن تعرف أن النص محفوظ صحيحاً، والخلل في الرسم فقط. لذلك لا تحاول إصلاحه بإعادة ترتيب الكلمات يدوياً، فهذا يكسر النص في أماكن أخرى مثل نتائج البحث ونسخ النص. الحل الصحيح أن تخبر المتصفح أين يبدأ المقطع المختلف وأين ينتهي.
وقد تسأل: لماذا لا يكفي dir="rtl" على الصفحة؟ لأنه يحدد الاتجاه الأساسي للفقرة فقط، والخوارزمية تعمل داخل الفقرة على كل مقطع. الاتجاه الأساسي يحل مشكلة بداية السطر، لكنه لا يعرف أين ينتهي رقم الطلب وأين تبدأ الجملة العربية بعده. هذا ما تخبره به أنت بالعزل.
الحل خطوة بخطوة في صفحاتك
اعزل المقاطع المتغيّرة بوسم bdi
وسم
<bdi>يعزل ما بداخله عن النص المحيط، فيُحسب اتجاهه وحده. استخدمه لكل قيمة تأتي من قاعدة البيانات أو من المستخدم: اسم منتج، اسم عميل، رقم طلب.code <p>طلبك <bdi>#A-1042</bdi> في الطريق إلى حي النرجس.</p> <p>أضفت <bdi>iPhone 15 Pro</bdi> إلى السلة.</p> <li>الكاتب: <bdi>{{ review.author }}</bdi></li>حدّد الاتجاه صراحة للأرقام والروابط
حين تعرف أن المقطع لاتيني دائماً، مثل رقم جوال أو بريد أو رمز خصم، فحدّد اتجاهه عبر
dir="ltr". هذا أوضح من bdi لأنه لا يترك القرار للتخمين.code <p>للحجز: <span dir="ltr">+966 50 123 4567</span></p> <p>استخدم رمز الخصم <span dir="ltr">RAMADAN-25</span> عند الدفع.</p>طبّق العزل من CSS على مستوى المكوّن
إن كان عندك أصناف متكررة للأسعار أو أرقام الطلبات، فاجعل العزل في CSS بدل تذكّره في كل مكان. القيمة
isolateتعادل ما يفعله bdi، وplaintextتجعل كل فقرة تأخذ اتجاه أول حرف قوي فيها.code .order-id, .sku, .phone, .email { unicode-bidi: isolate; direction: ltr; } /* تعليقات العملاء: قد تكون عربية أو إنجليزية */ .review-text { unicode-bidi: plaintext; text-align: start; }اترك المتصفح يكتشف اتجاه ما يكتبه المستخدم
في حقول البحث والتعليقات وأسماء العملاء، قيمة
dir="auto"تجعل الحقل يتبع أول حرف قوي يكتبه الزائر، عربياً كان أو إنجليزياً.code <input type="search" name="q" dir="auto" placeholder="ابحث عن منتج"> <textarea name="comment" dir="auto"></textarea>استخدم محارف التحكم حين لا يتاح HTML
في عنوان التبويب، والإشعارات، ورسائل SMS، وأسماء الملفات، لا توجد وسوم. هنا تستخدم محارف يونيكود غير مرئية: علامة RLM (U+200F) بعد مقطع لاتيني في نهاية جملة عربية، أو محرفا العزل FSI و PDI حول المقطع.
code // علامة RLM تعيد النقطة إلى مكانها document.title = "طلبك من Riyadh Books\u200F."; // العزل في نص عادي: FSI = U+2068 و PDI = U+2069 const msg = `تم شحن الطلب \u2068${orderId}\u2069 إلى ${city}`; <!-- وفي HTML نفسه --> <p>نسخة Windows 11‏.</p>اعرض الأرقام بالشكل الذي تريده
Intl.NumberFormatمع اللغةar-SAقد يعرض الأرقام بالشكل الهندي (١٢٣). إن أردت الأرقام الغربية فأضف-u-nu-latnإلى رمز اللغة، وتبقى الفواصل والعملة عربية.code const price = new Intl.NumberFormat("ar-SA-u-nu-latn", { style: "currency", currency: "SAR" }).format(1299); // يعرض السعر بأرقام غربية مع رمز الريال، والشكل الدقيق حسب المتصفح const date = new Intl.DateTimeFormat("ar-SA-u-nu-latn-ca-gregory", { dateStyle: "long" }).format(new Date());
إن كانت الصفحات كثيرة، فاطلب من الوكيل أن يطبّق القاعدة على المكوّنات لا على النصوص واحداً واحداً:
أصلح عرض النصوص المختلطة في الموقع دون تغيير التصميم: - كل قيمة متغيّرة داخل نص عربي (اسم منتج، رقم طلب، اسم عميل) ضعها داخل <bdi>. - أرقام الجوال والبريد ورموز الخصم داخل <span dir="ltr">. - أضف unicode-bidi: isolate لأصناف رقم الطلب والسعر ورمز المنتج. - حقول البحث والتعليقات dir="auto". - في عنوان الصفحة والإشعارات أضف \u200F بعد أي كلمة إنجليزية في نهاية الجملة. - اعرض الأسعار عبر Intl.NumberFormat باللغة ar-SA-u-nu-latn وعملة SAR.
حلول هذه الصفحة تكمل حل الاتجاه العام ولا تغني عنه. إن كانت الصفحة كلها من اليسار، فابدأ من لماذا ينكسر التصميم العربي.
وقبل أن تطبّق القواعد، اعرف أين تبحث. هذه الأماكن التي يكثر فيها الانقلاب في المواقع والمتاجر السعودية، فمرّ عليها واحداً واحداً:
- مسار التنقل (breadcrumbs): «الرئيسية / Electronics / iPhone» يتبعثر ترتيبه إن لم تُعزل كل حلقة.
- سطور السلة والفاتورة: اسم المنتج الإنجليزي ثم الكمية ثم السعر في سطر واحد.
- رسائل التأكيد: «تم حجز موعدك رقم BK-2207 يوم 12/05» فيها مقطعان يحتاجان عزلاً.
- الحسابات والوسوم: «تابعنا على @riyadh.roastery» والوسوم التي تبدأ بعلامة #.
- الروابط داخل النص: رابط مثل example.sa/menu في نهاية جملة عربية تقفز نقطته إلى البداية.
- الجداول: عمود رمز المنتج SKU وعمود التاريخ بجانب أعمدة عربية.
ولاحظ العلاقة بين خاصيتي CSS: direction تحدد الاتجاه، و unicode-bidi تحدد هل يُعزل العنصر عمّا حوله أم يمتزج به. لذلك تجدهما معاً في أغلب الحلول، وإضافة direction: ltr وحدها دون عزل قد تُبقي الأقواس المحيطة بالعنصر في غير مكانها.
وبعد التطبيق، اختبر بأصعب جملة يمكن أن تظهر في موقعك، لا بأسهلها. جملة مثل «طلبك #A-1042 (iPhone 15 Pro) بقيمة 4,299 ر.س سيصل الأحد.» فيها كل الحالات معاً: رمز، أرقام، أقواس، كلمات إنجليزية، ونقطة في النهاية. إن ظهرت سليمة، فبقية النصوص ستظهر سليمة.
الحل الأسرع: أوترا
النصوص المختلطة جزء عادي من أي مشروع سعودي: أسعار بالريال، أرقام جوال، أسماء منتجات إنجليزية، وطرق دفع مثل Apple Pay و مدى. أوترا مبنية على تجربة عربية أصيلة بالاتجاه RTL، فتكتب لها طلبك كما تكتبه لعميلك، بالعربي ومعه ما يلزم من كلمات إنجليزية.
اطلب الآن عبر Apple Pay بسعر 49 ريال (شامل VAT).
اطلب الآن عبر Apple Pay بسعر 49 ريال (شامل VAT).
وإن لاحظت في المعاينة رقماً أو قوساً في غير مكانه، فحدّد العنصر واكتب طلبك عليه مباشرة، مثل «رقم الجوال هنا يظهر مقلوباً، أصلحه»، فيُطبَّق التعديل على هذا العنصر تحديداً دون أن يمس بقية الصفحة.