تعريب التطبيقات ومشاكل النص العربي: أين يوجد العطل؟

تعريب التطبيقات ومشاكل النص العربي
في هذه المقالة

تعريب التطبيقات ومشاكل النص العربي لا يُحلّان بإضافة dir="rtl" وترجمة الواجهات فقط؛ لأن العطل قد يكون في التخطيط، أو تشكيل الحروف عند التصدير، أو معالجة النص ثنائي الاتجاه، أو طبقة المقارنة والبحث.

ابدأ بتحديد الطبقة التي تعطلت قبل تعديل النصوص أو CSS: هل العنصر في المكان الخطأ، أم الحروف نفسها تالفة، أم ترتيب الأرقام والرموز مربك، أم أن البحث لا يطابق نصين يبدوان متشابهين؟

كل طبقة لها مكان إصلاح مختلف في الشيفرة، وخلطها يؤدي غالبًا إلى حلول موضعية تنجح في شاشة وتكسر شاشة أخرى.

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

كيف تعرف أي طبقة تعطلت قبل تعديل الشيفرة؟

أول خطوة ليست البحث عن خاصية CSS جديدة، بل تصنيف العطل. المشكلات الأربع قد تظهر للمستخدم تحت وصف واحد مثل «العربي خربان»، لكنها لا تأتي من السبب نفسه.

استخدم هذا الفصل أثناء التشخيص:

ما يراه المستخدمالطبقة المحتملةمكان الإصلاح المعتاد
القائمة تبدأ من الجهة الخطأ أو المسافات معكوسةالاتجاه والتخطيطHTML وCSS ومكوّنات الواجهة
الحروف سليمة على الشاشة ثم تنفصل أو تتغير في الملف الناتجالتشكيل ومحرك الإخراجRenderer، مكتبة PDF، الخطوط
رقم أو رابط أو اسم لاتيني يقفز إلى موضع مربك داخل جملة عربيةBiDiحدود المقاطع واتجاه العناصر النصية
البحث أو الفرز يعطي نتيجة غير متوقعة رغم تشابه النص بصريًاالتطبيع والمقارنةطبقة البحث والمقارنة أو إعداد Collation

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

ما أشرحه هنا يبدأ بعد أن يصل النص الصحيح إلى الواجهة أو إلى محرك الإخراج. أما جودة الترجمة وصياغتها، واختيار مكتبة i18n وبنية ملفات الترجمة، فمسألة منفصلة عن سلوك الاتجاه والتشكيل والمقارنة.

اختبر كل طبقة منفصلة

قبل تعديل التطبيق كله، أنشئ حالة صغيرة يمكن تكرارها:

  • مكوّن واجهة فيه عنوان عربي وزر وأيقونة.
  • فقرة عربية تُصدَّر بالطريقة نفسها التي يستخدمها التطبيق.
  • جملة تجمع العربية مع رقم ورابط واسم لاتيني.
  • استعلام بحث يقارن نصًا مدخلًا من المستخدم بالقيمة الأصلية.

إذا فشل اختبار واحد فقط، صار لديك نطاق أصغر بكثير للمشكلة.

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

لماذا لا يعني RTL أن تقلب كل شيء؟

dir="rtl" يحدد الاتجاه الأساسي لمحتوى العنصر، لكنه لا يعني أن كل مكوّن داخله يجب أن ينعكس بصريًا أو أن كل قيمة نصية تصبح RTL.

المشكلة تظهر عندما يبني التطبيق تخطيطه على left وright ثم يحاول إضافة شروط منفصلة للعربية. هذا يخلق نسختين منطقيتين من الواجهة بدل تخطيط واحد يتكيف مع الاتجاه.

استخدم الخصائص المنطقية بدل الجهات الثابتة

في CSS، فضّل الخصائص التي تعبّر عن بداية السطر ونهايته، مثل:

  • margin-inline-start
  • margin-inline-end
  • padding-inline-start
  • padding-inline-end
  • inset-inline-start
  • text-align: start

هذه الخصائص ترتبط باتجاه الكتابة بدل افتراض أن البداية دائمًا يسار.

الأمر نفسه ينطبق على ترتيب عناصر flex وgrid: لا تعكس row يدويًا لمجرد أن الصفحة عربية إلا إذا كانت دلالة المكوّن نفسه تتطلب ذلك. عندما يتغير اتجاه الحاوية، بعض السلوك يتكيف تلقائيًا، وإضافة انقلاب آخر فوقه قد تعيد العناصر إلى الموضع الخطأ.

ما الذي يبقى باتجاهه الأصلي؟

بعض القيم لها بنية داخلية لا تتبع لغة الجملة المحيطة. من أمثلتها:

  • عنوان البريد الإلكتروني مثل name@example.com
  • رقم الهاتف عند عرضه كسلسلة قابلة للنسخ
  • سطر شيفرة أو اسم متغير
  • مسار ملف مثل C:\Projects\App\logs
  • URL أو Token تقني

هذه العناصر قد تظهر داخل فقرة RTL، لكن من الأفضل عزل اتجاهها الداخلي عند الحاجة بدل قلب محتواها. في HTML يمكن وضع قيمة مستقلة داخل <bdi> أو عنصر ذي dir="ltr" عندما تعرف أن بنيتها LTR.

الفكرة هي فصل «اتجاه الصفحة» عن «اتجاه القيمة». إذا جعلت كل شيء RTL بالقوة، قد يبدو البريد أو المسار وكأنه أعيد ترتيب أجزائه، وهذا يضر القراءة والنسخ حتى لو كانت الأحرف نفسها صحيحة.

ولا تقلب الأيقونات آليًا كلها. الأيقونة التي تعتمد دلالتها على اتجاه التنقل قد تحتاج نسخة معكوسة، بينما شعار أو رمز تقني أو أيقونة لا تحمل معنى اتجاهيًا تبقى كما هي.

لماذا يكون النص صحيحًا في الواجهة ثم يفسد عند التصدير؟

إذا كان النص العربي سليمًا في المتصفح لكنه يخرج في ملف بحروف منفصلة أو ترتيب غير صحيح، فهذه ليست مشكلة ترجمة ولا CSS غالبًا. أنت انتقلت إلى طبقة Rendering مختلفة.

المتصفح يملك محركًا يتعامل مع تشكيل العربية واتجاه النص. مكتبة التصدير قد تستخدم مسارًا مختلفًا تمامًا، وقد تحتاج إلى دعم صريح للخط العربي والتشكيل وBiDi.

ما الذي يحدث فعليًا في طبقة التصدير؟

العربية ليست سلسلة حروف تُرسم كل واحدة منها بصورة ثابتة. شكل الحرف يتغير بحسب موقعه واتصاله بما حوله، كما أن ترتيب العرض قد يختلف عن ترتيب التخزين المنطقي للنص.

لذلك يحتاج مولد الملف إلى أكثر من مجرد Unicode صحيح:

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

إذا كانت مكتبة PDF لا تقوم بهذه الخطوات، فلن يصلح الأمر بتطبيق direction: rtl على القالب وحده.

أين يكون الإصلاح؟

الإصلاح يكون داخل مسار التصدير نفسه: إعداد الخط، واختيار Renderer مناسب، وضبط طريقة تمرير النص، ومراجعة دعم العربية في المكتبة المستخدمة.

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

وإذا كان الخط نفسه لا يحتوي على المحارف العربية المطلوبة، فهذا شيء آخر: نقص الـ Glyphs في ملف الخط يُعالج بتغيير الخط أو تكوينه، وتعديل اتجاه الصفحة لا يفيد فيه.

إذا كان التطبيق ينتج تقارير أو فواتير أو مستندات باستمرار، يمكن فحص هذا المسار عبر مهارة إخراج PDF عربي، لأن المطلوب هنا تدقيق محرك الإخراج والخطوط والتشكيل لا واجهة المستخدم.

ماذا يحدث عندما تختلط العربية بالأرقام والروابط واللاتينية؟

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

Unicode يخزن النص في ترتيب منطقي، ثم يحدد محرك العرض كيف ترتب المقاطع RTL وLTR بصريًا. المشكلة تصبح ظاهرة عندما توجد حدود غير واضحة بين المقاطع، أو عندما تدخل رموز محايدة مثل بعض علامات الترقيم والفواصل حول أرقام أو أسماء لاتينية.

لا تحاول ترتيب السطر يدويًا

إذا كان لديك نص مثل وصف عربي يتضمن API, رقم إصدار، بريدًا، أو رابطًا، فلا تقسّم الجملة ثم تعيد بناء الأجزاء بترتيب بصري من اليسار إلى اليمين أو العكس. اترك النص في ترتيبه المنطقي، ثم حدّد المقاطع التي تحتاج عزلًا.

في واجهة HTML يمكن أن يفيد:

  • <bdi> لعزل جزء قد يكون اتجاهه مختلفًا عن السياق.
  • dir="ltr" لقيمة تعرف أن بنيتها LTR.
  • dir="auto" للمحتوى الذي يكتبه المستخدم عندما لا تعرف مسبقًا اتجاهه الأساسي.
  • unicode-bidi: isolate عند الحاجة إلى عزل مقطع داخل CSS.

العزل مهم لأنه يمنع اتجاه قيمة داخلية من التأثير في العلامات أو الكلمات المجاورة لها.

لماذا البريد والهاتف والشيفرة حالات خاصة؟

لأن ترتيبها يحمل معنى وظيفيًا، وليس بصريًا فقط. إذا تغيّر موضع أجزاء البريد أو الشيفرة، قد يقرأ المستخدم قيمة تختلف عما سينسخه أو يحاول تنفيذه.

رقم الهاتف أيضًا لا ينبغي «تعريبه» بإعادة ترتيب الأرقام. يمكن أن يعيش داخل واجهة RTL مع عنصر مستقل يحافظ على ترتيب السلسلة كما صُممت للقراءة والنسخ.

ونفس الفكرة تنطبق على أسماء الملفات والمسارات: اتجاه الصفحة شيء، وترتيب الرموز داخل القيمة شيء آخر.

وإذا كانت للأرقام والبيانات قواعد عرض محاسبية أو قانونية، فهذه تتبع متطلبات المنتج والجهة التي تستخدمه، ولا يحسمها RTL وحده.

لماذا يفشل البحث والمقارنة والفرز رغم أن النص يبدو متطابقًا؟

الطبقة الرابعة لا تظهر في الرسم، بل في مقارنة السلاسل النصية. قد يرى المستخدم كلمتين بالشكل نفسه تقريبًا، بينما تتعامل الشيفرة معهما كسلاسل مختلفة بسبب Unicode أو التشكيل أو التطويل أو اختلاف صيغ بعض الحروف.

هنا لا تحتاج إلى تعديل ما يُعرض للمستخدم. تحتاج إلى سياسة تطبيع داخل طبقة المقارنة.

والتطبيع خطوة داخل المقارنة وليس بديلًا عن بنية البحث نفسها؛ أما تصميم بحث دلالي أو Full-text Search كامل فخارج ما أشرحه هنا.

احتفظ بالنص الأصلي كما أدخله المستخدم

لا تغيّر القيمة الأصلية المخزّنة لمجرد تسهيل البحث. الحقل الأصلي يجب أن يبقى مصدر العرض والتحرير والاسترجاع.

عندما تريد المقارنة، أنشئ تمثيلًا مخصصًا لها في تلك اللحظة أو داخل مسار البحث. مثلًا:

function normalizeForSearch(value) {
  return value
    .normalize('NFC')
    .replace(/\u0640/g, '');
}

هذا المثال يوحّد Unicode إلى NFC ويزيل التطويل من نسخة المقارنة. ولا يعني أن هذه الخطوات مناسبة لكل منتج؛ إزالة التشكيل أو توحيد أشكال الألف أو غيرها قرار بحثي يعتمد على ما تعتبره أنت تطابقًا مقبولًا.

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

طبّق القاعدة على طرفي المقارنة

التطبيع المفيد ليس أن تغيّر استعلام المستخدم وحده ثم تقارنه بنص خام. طبّق السياسة نفسها على القيم التي تدخل المقارنة، أو استخدم محرك بحث أو Collation يطبق القاعدة المتفق عليها.

والفرز له مشكلة قريبة. المقارنة المباشرة بين Unicode code points لا تعبّر دائمًا عن الترتيب اللغوي الذي يتوقعه المستخدم. في JavaScript مثلًا يمكن استخدام Intl.Collator('ar') بدل ترتيب السلاسل الخام عندما تكون الحاجة فرزًا لغويًا عربيًا.

افصل أيضًا بين «البحث» و«المساواة الصارمة». قد تقبل في البحث اختلافًا في التشكيل أو بعض صور الحروف لتوسيع المطابقة، لكنك لا تريد بالضرورة استخدام السياسة نفسها عند مقارنة معرفات أو قيم يجب أن تكون متطابقة حرفيًا.

عندما تتعدد هذه القواعد، يمكن توحيدها في مسار واضح باستخدام مهارة تطبيع البحث العربي، بدل نشر عمليات replace مختلفة في الواجهة وAPI وقاعدة البيانات.

سؤالان عن dir وعزل البريد داخل الجملة العربية

أضفت dir="rtl"، لماذا ما زالت الواجهة العربية غير صحيحة؟

لأن dir يحدد الاتجاه الأساسي لكنه لا يعالج خصائص CSS المكتوبة يدويًا بـleft وright، ولا يعزل القيم LTR، ولا يصلح محرك PDF أو البحث. حدّد أولًا أي طبقة ما زالت تفشل.

كيف أعرض بريدًا إلكترونيًا داخل جملة عربية بدون أن يتغير ترتيبه؟

اعزل البريد في عنصر مستقل واترك اتجاهه الداخلي LTR، باستخدام <bdi> أو dir="ltr" بحسب بنية المكوّن. لا تقلب البريد نفسه ولا تضف مسافات داخله لتثبيت شكله.