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

حل انقلاب الأرقام والأقواس والكلمات الإنجليزية في النص العربي

تنقلب الأرقام والأقواس والكلمات الإنجليزية في النص العربي بسبب خوارزمية الاتجاه الثنائي في يونيكود، التي ترتّب الرموز المحايدة حسب ما يجاورها. الحل أن تعزل كل مقطع لاتيني أو رقمي بوسم bdi أو span بخاصية dir="ltr"، وأن تستخدم unicode-bidi: isolate في CSS، ومحرف RLM حين لا يتاح HTML.

آخر تحديث:

لماذا يحدث هذا

النص العربي على الشاشة يُخزَّن في ترتيب الكتابة، ثم يقرر المتصفح كيف يرسمه بقواعد اسمها خوارزمية الاتجاه الثنائي (Unicode Bidirectional Algorithm). هذه الخوارزمية تقسم الرموز إلى ثلاث فئات:

  • رموز قوية: الحروف العربية اتجاهها من اليمين، والحروف اللاتينية من اليسار. هذه تحسم اتجاه ما حولها.
  • رموز ضعيفة: الأرقام وعلامات مثل + و %. لها اتجاه داخلي من اليسار، لكنها لا تحسم موضعها في الجملة.
  • رموز محايدة: المسافات والأقواس والنقاط والشرطات وعلامات الاستفهام. هذه تأخذ اتجاه الجار، وهنا تبدأ المشاكل.

حين يقع رمز محايد بين مقطع عربي ومقطع لاتيني، أو في آخر السطر بعد كلمة إنجليزية، تضعه الخوارزمية في مكان منطقي حسابياً لكنه خطأ في عين القارئ. هذه أمثلة حقيقية من مواقع سعودية:

أمثلة على الانقلاب
ما كتبتهما قد يظهر للزائرالسبب
الباقة (Pro) متاحةالباقة (Pro( متاحة أو أقواس معكوسةالقوس المحايد أخذ اتجاه الكلمة اللاتينية
اتصل على +966 50 123 4567اتصل على 50 123 4567+966علامة + ضعيفة فانتقلت لطرف المقطع
جهاز iPhone 15 Pro.النقطة تظهر في بداية السطرالنقطة المحايدة بعد كلمة لاتينية في نهاية الفقرة
رقم الطلب: #A-10421042-A# بترتيب مقلوبحروف وأرقام ورموز في مقطع واحد
تم الدفع عبر Apple Pay (مدى)الأقواس تلتف حول الكلمة الخطأمقطع لاتيني متبوع بقوس ونص عربي

المهم أن تعرف أن النص محفوظ صحيحاً، والخلل في الرسم فقط. لذلك لا تحاول إصلاحه بإعادة ترتيب الكلمات يدوياً، فهذا يكسر النص في أماكن أخرى مثل نتائج البحث ونسخ النص. الحل الصحيح أن تخبر المتصفح أين يبدأ المقطع المختلف وأين ينتهي.

وقد تسأل: لماذا لا يكفي dir="rtl" على الصفحة؟ لأنه يحدد الاتجاه الأساسي للفقرة فقط، والخوارزمية تعمل داخل الفقرة على كل مقطع. الاتجاه الأساسي يحل مشكلة بداية السطر، لكنه لا يعرف أين ينتهي رقم الطلب وأين تبدأ الجملة العربية بعده. هذا ما تخبره به أنت بالعزل.

الحل خطوة بخطوة في صفحاتك

  1. اعزل المقاطع المتغيّرة بوسم bdi

    وسم <bdi> يعزل ما بداخله عن النص المحيط، فيُحسب اتجاهه وحده. استخدمه لكل قيمة تأتي من قاعدة البيانات أو من المستخدم: اسم منتج، اسم عميل، رقم طلب.

    code
    <p>طلبك <bdi>#A-1042</bdi> في الطريق إلى حي النرجس.</p>
    <p>أضفت <bdi>iPhone 15 Pro</bdi> إلى السلة.</p>
    <li>الكاتب: <bdi>{{ review.author }}</bdi></li>
  2. حدّد الاتجاه صراحة للأرقام والروابط

    حين تعرف أن المقطع لاتيني دائماً، مثل رقم جوال أو بريد أو رمز خصم، فحدّد اتجاهه عبر dir="ltr". هذا أوضح من bdi لأنه لا يترك القرار للتخمين.

    code
    <p>للحجز: <span dir="ltr">+966 50 123 4567</span></p>
    <p>استخدم رمز الخصم <span dir="ltr">RAMADAN-25</span> عند الدفع.</p>
  3. طبّق العزل من CSS على مستوى المكوّن

    إن كان عندك أصناف متكررة للأسعار أو أرقام الطلبات، فاجعل العزل في CSS بدل تذكّره في كل مكان. القيمة isolate تعادل ما يفعله bdi، و plaintext تجعل كل فقرة تأخذ اتجاه أول حرف قوي فيها.

    code
    .order-id, .sku, .phone, .email {
      unicode-bidi: isolate;
      direction: ltr;
    }
    
    /* تعليقات العملاء: قد تكون عربية أو إنجليزية */
    .review-text {
      unicode-bidi: plaintext;
      text-align: start;
    }
  4. اترك المتصفح يكتشف اتجاه ما يكتبه المستخدم

    في حقول البحث والتعليقات وأسماء العملاء، قيمة dir="auto" تجعل الحقل يتبع أول حرف قوي يكتبه الزائر، عربياً كان أو إنجليزياً.

    code
    <input type="search" name="q" dir="auto" placeholder="ابحث عن منتج">
    <textarea name="comment" dir="auto"></textarea>
  5. استخدم محارف التحكم حين لا يتاح 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&rlm;.</p>
  6. اعرض الأرقام بالشكل الذي تريده

    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).

بعد: dir=rtl مع <bdi> للمقاطع اللاتينية

اطلب الآن عبر Apple Pay بسعر 49 ريال (شامل VAT).

عرض حيّ يرسمه متصفحك الآن، وليس لقطة شاشة.

وإن لاحظت في المعاينة رقماً أو قوساً في غير مكانه، فحدّد العنصر واكتب طلبك عليه مباشرة، مثل «رقم الجوال هنا يظهر مقلوباً، أصلحه»، فيُطبَّق التعديل على هذا العنصر تحديداً دون أن يمس بقية الصفحة.

أسئلة شائعة

لا في الغالب. الحروف محفوظة بترتيب كتابتها الصحيح، والانقلاب يحدث عند الرسم على الشاشة فقط. لهذا لا تعدّل ترتيب الكلمات في القاعدة، بل اعزل المقاطع في العرض بوسم bdi أو بخاصية dir أو unicode-bidi.

صفحات ذات صلة