قبل عامين، أطلقنا أول منتج عربي لنا. اليوم نشغّل أربعة: هذه المدونة، البروبتر العربي، edar.ae، وhelpyard.ae. كلٌّ منها علّمنا شيئًا مختلفًا عن تطوير RTL. ما يلي هو كل ما تمنينا قراءته قبل أن نبدأ.
الدرس الأكبر، والإطار الذي يحكم كل ما سيأتي: ابنِ RTL أولاً، لا RTL أخيرًا. كل مشروع بُني بالاتجاه العربي كالمرجع الأساسي منذ البداية كان أسهل في الإطلاق. وكل مشروع أضفنا إليه العربية “لاحقًا” كلّفنا إعادة عمل ضخمة. RTL-أولاً ليس مجرد تفضيل — بل هو قرار معماري.
الفرق بين دعم RTL وبين RTL-أولاً
معظم أدلة “دعم RTL” تعلّمك كيف تضيف RTL إلى قاعدة كود LTR موجودة. هذه هي المشكلة الخاطئة التي تحاول حلّها. بحلول الوقت الذي تضيف فيه RTL إلى نظام قائم، تكون قد اتخذت بالفعل عشرات القرارات — بشأن اتجاه الأيقونات، وإيقاع التباعد، وتسلسل المكونات — تبدو طبيعية في LTR وتقاومك في RTL.
RTL-أولاً يعني تصميم وبناء التجربة العربية بوصفها المرجع الأساسي، واشتقاق LTR منها. عملياً يبدو ذلك هكذا:
- كتابة CSS للمكونات باستخدام الخصائص المنطقية (
inline-start،block-end) قبل الاختبار في LTR - تأليف التخطيطات بـflex وgrid بحيث تستجيب لتغييرات الـ
dirدون تعديل المكونات - اختبار المكونات الجديدة بالعربية قبل الإنجليزية، لأن النص العربي أطول في المفهوم ويكشف مشاكل الفيض فوراً
في البروبتر العربي تحديداً، صُمِّمت الواجهة بأكملها وأُطلقت بالعربية قبل أن تُضاف الإنجليزية. النتيجة: صفر أخطاء RTL بعد الإطلاق. قارن ذلك بـedar.ae، حيث بنينا الإنجليزية أولاً وأمضينا أسبوعاً كاملاً في حل 47 مشكلة تخطيط عند إضافة العربية.
الخصائص المنطقية في CSS: الأساس الحقيقي
إذا كان هناك تغيير تقني واحد يهم فوق كل شيء آخر في تطوير الويب RTL، فهو التحول الكامل إلى الخصائص المنطقية في CSS. ليس انتقائياً. ليس حيثما كان مناسباً. كاملاً.
يُعيّن نموذج الخاصية المنطقية الاتجاهات المادية (يسار/يمين/أعلى/أسفل) إلى اتجاهات نسبية لتدفق النص (inline-start، inline-end، block-start، block-end). في LTR، inline-start هو اليسار. في RTL، هو اليمين. يتعامل المتصفح مع التبديل — تكتب القاعدة مرة واحدة.
/* مادي — يكسر RTL */
.nav-icon {
margin-right: 0.5rem;
}
/* منطقي — يعمل في كلا الاتجاهين */
.nav-icon {
margin-inline-end: 0.5rem;
}
جدول التعيين الكامل:
| المادي | ما يقابله من المنطقي |
|---|---|
margin-left | margin-inline-start |
margin-right | margin-inline-end |
padding-left | padding-inline-start |
padding-right | padding-inline-end |
left (تمركز) | inset-inline-start |
right (تمركز) | inset-inline-end |
border-left | border-inline-start |
text-align: left | text-align: start |
دعم المتصفحات لكل هذه الخصائص ممتاز — فهي ميزات أساسية في كل متصفح منذ عام 2023. لا حجة للتحسين التدريجي ضد استخدامها.
ما يخطئ فيه الجميع: text-align: start مقابل text-align: left. في LTR يُنتجان نفس النتيجة. في RTL، يُحاذي text-align: start النص إلى اليمين — وهو ما تريده دائماً تقريباً لنص الجسم العربي. أما text-align: left في سياق RTL فيبدو خاطئاً على الفور للقراء الأصليين.
ما لا تغطيه الخصائص المنطقية
تتعامل الخصائص المنطقية مع التباعد والتمركز، لكنها لا تتعامل مع الاتجاه المرئي للأيقونات أو الأسهم أو أي عنصر UI يحمل معنى اتجاهياً جوهرياً.
السهم الأمامي ← يجب أن يشير يميناً في LTR ويساراً في RTL (نحو اتجاه القراءة). النهج التقليدي هو تحويل CSS:
[dir="rtl"] .directional-icon {
transform: scaleX(-1);
}
نلفّ هذا في class مساعدة في جميع مشاريعنا:
.icon-directional {
display: inline-block;
}
[dir="rtl"] .icon-directional {
transform: scaleX(-1);
}
الأيقونات التي تمثل أشياء مادية (كاميرا، ميكروفون، علامة اختيار) لا تحتاج إلى عكس. فقط الأيقونات ذات الاتجاهية الجوهرية (الأسهم، للخلف/للأمام، مؤشرات التقدم) يجب قلبها.
النص ثنائي الاتجاه: الجزء الصعب حقاً
تخطيط RTL آلي وقابل للحل بالأنماط أعلاه. أما النص ثنائي الاتجاه — العربية والإنجليزية المختلطتان في نفس الفقرة أو السطر أو حتى الكلمة — فهو أصعب. يتعامل خوارزمية Unicode bidi مع العرض، لكنها تفترض أموراً قد تُنتج نتيجة خاطئة أحياناً.
أكثر أوضاع الفشل شيوعاً: جملة عربية تنتهي بـURL أو اسم منتج أو مصطلح تقني بالإنجليزية. ستتعامل الخوارزمية مع الجزء الإنجليزي كـLTR، وهو صحيح — لكن علامات الترقيم حوله (نقطتان، قوس، نقطة) قد تقع في موضع غير متوقع بحسب موقعها في الجزء العربي.
مثال: هذا هو الموقع: alsheikhmedia.com. قد تعرض النقطة قبل الـURL في بعض المتصفحات، لأن النقطة غامضة — قد تنتمي للجزء العربي أو الإنجليزي.
الحل هو استخدام محرفي تحكم Unicode bidi صراحة:
<!-- لف محتوى LTR المضمّن في span معزول للـbidi -->
<p>هذا هو الموقع: <span dir="ltr">alsheikhmedia.com</span>.</p>
الـdir="ltr" على الـspan المضمّن يُنشئ حدود عزل bidi. النقطة الآن تنتمي بشكل لا لبس فيه للجملة العربية. نُطبّق هذا تلقائياً على كل URL وعلامة كود واسم منتج يظهر داخل النثر العربي في خط أنابيب عرض نظام إدارة المحتوى لدينا.
الأرقام في السياق العربي
تستخدم المنطقة العربية نظامَي أرقام: الأرقام العربية الهندية (٠١٢٣٤٥٦٧٨٩) والأرقام العربية الغربية (0–9). أسواق الخليج — الإمارات والسعودية والكويت — تستخدم الأرقام الغربية في الغالب في الواجهات الرقمية. لا تفترض أنك بحاجة إلى تحويل إلى أرقام عربية هندية لمجرد أن الواجهة بالعربية.
ومع ذلك: تختلف اتفاقيات ترقيم الأرقام. تستخدم السياقات العربية أحياناً . فاصلاً للآلاف حيث تستخدم الإنجليزية ,، والعكس. إذا كنت تُنسّق الأرقام، لا تُرمّز علامات الترقيم — استخدم واجهة API Intl.NumberFormat مع ضبط اللغة بشكل صريح:
// اللغة العربية الخليجية (تستخدم الأرقام الغربية، اتفاقيات الترقيم الخليجية)
const formatter = new Intl.NumberFormat('ar-AE', {
useGrouping: true,
});
formatter.format(1500000); // يُرجع "1,500,000" في السياق العربي الخليجي
معمارية مكونات Astro لـRTL
نستخدم Astro في جميع منتجاتنا الحالية. يُشكّل نهج RTL-أولاً طريقة كتابتنا للمكونات على كل مستوى.
قشرة التخطيط
جميع الصفحات تمرر lang وdir إلى عنصر <html> الجذر. نشتق dir من lang — لا نخزّنهما بشكل منفصل أبداً، لأن وجود خاصيتين يمكن أن تتعارضا هو مصدر للأخطاء.
---
// Layout.astro
const { lang } = Astro.props;
const dir = lang === 'ar' ? 'rtl' : 'ltr';
const fontClass = lang === 'ar' ? 'font-arabic' : 'font-latin';
---
<html lang={lang} dir={dir} class={fontClass}>
<head>
<!-- ... -->
</head>
<body>
<slot />
</body>
</html>
الـfontClass مهم. للخطوط العربية واللاتينية خصائص مختلفة في ارتفاع السطر والتباعد الحرفي وعرض الوزن. نستخدم class CSS منفصلة لكل نص لضبط الإعدادات الطباعية الافتراضية بدلاً من محاولة معالجتها بمجموعة قيم واحدة.
إعداد الطباعة
في CSS العام لدينا، نحدد إعدادات طباعية افتراضية خاصة بكل خط:
/* الإعدادات اللاتينية */
.font-latin {
font-family: 'Inter', system-ui, sans-serif;
line-height: 1.6;
letter-spacing: -0.01em;
}
/* الإعدادات العربية — خط Cairo، ارتفاع سطر أكبر، لا تباعد حرفي */
.font-arabic {
font-family: 'Cairo', 'Noto Sans Arabic', sans-serif;
line-height: 1.8;
letter-spacing: 0; /* لا تُطبّق أبداً letter-spacing على النص العربي */
}
قاعدة عدم التباعد الحرفي للعربية مطلقة. يُكوّن النص العربي أحرفاً مُدغمة — أحرف تتصل وتتشكل بناءً على جيرانها. يكسر التباعد الحرفي تلك الاتصالات ويُنتج نصاً يبدو كأنه أحرف منفصلة غير متصلة، وهو أمر بصري خاطئ ومضر بالقراءة. يتعامل خط Cairo مع عرض الأحرف المُدغمة تلقائياً؛ مهمتك ألا تكسره.
تأليف المكونات
المكونات التي تحتاج إلى الاستجابة لاتجاه النص يجب أن تستخدم الخصائص المنطقية في CSS بدلاً من الشروط في JavaScript. تجنب هذا النمط:
<!-- هش — يتطلب تمرير الاتجاه إلى كل مكون -->
<Card direction={dir} />
بدلاً من ذلك، اكتب CSS المكون بالخصائص المنطقية ودع سمة dir الموروثة على <html> تقوم بالعمل:
/* card.css — يعمل في كلا الاتجاهين */
.card {
padding-inline: 1.5rem;
padding-block: 1rem;
border-inline-start: 3px solid var(--accent);
}
ستظهر border-inline-start تلقائياً على اليسار في LTR وعلى اليمين في RTL. لا JavaScript. لا تمرير للخصائص. توارث CSS يقوم بذلك.
مجموعات المحتوى مع توجيه اللغة
هيكل مجلد المحتوى لدينا للمدونات ثنائية اللغة:
src/content/blog/
├── en/
│ └── post-slug.md
└── ar/
└── post-slug.md
يتضمن frontmatter كل ملف lang: en أو lang: ar، وهو ما يقرأه التخطيط مباشرة. يُنشئ التوجيه في src/pages/ مسارات ثابتة منفصلة en/blog/[slug].astro وar/blog/[slug].astro. يربط محوّل اللغة بين الاثنين باستخدام الـslug كمعرف مشترك.
هذا نهج يُقدّم المحتوى أولاً: يجب أن تتوفر كل منشورة بكلتا اللغتين قبل النشر، والـslug هو المعرف الأساسي عبر كليهما. عدم وجود ترجمة يعني ضمنياً عدم النشر.
دروس من منتجات محددة
البروبتر العربي
التحدي الجوهري في البروبتر: تمرير النص العربي بسرعة مُعدَّة بكلمات في الدقيقة، مع معالجة نظيفة لثنائية الاتجاه عند خلط النصوص. النص العربي يسير من اليمين إلى اليسار، لكن اتجاه التمرير هو نفسه (للأسفل) بغض النظر عن اللغة.
الجزء الصعب كان واجهة التحرير. يلصق المستخدمون محتوى عربياً، أحياناً بأسماء علامات تجارية إنجليزية مضمّنة، وأحياناً بعلامات ترقيم مثل ( أو : أو —. تلقينا تقارير أخطاء متعددة عن موضع المؤشر الخاطئ بعد اللصق ثنائي الاتجاه، أو أن تمييز التحديد لم يمتد للأحرف المتوقعة.
الحل كان استخدام عنصر contenteditable مع unicode-bidi: isolate صريح على الـspan المضمّن الذي يلفّ محتوى LTR:
.teleprompter-content [dir="ltr"] {
unicode-bidi: isolate;
}
unicode-bidi: isolate أقوى من dir="ltr" وحده — يُخبر خوارزمية bidi بمعاملة العنصر كسياق bidi معزول تماماً، مانعاً السياق RTL الخارجي من التأثير على عرض المحتوى LTR الداخلي.
edar.ae
edar هي منصة لإدارة العقارات. العقارات في الإمارات ثنائية اللغة بطبيعتها — العقود بالعربية، القوائم تظهر بكلتا اللغتين، المستخدمون يتنقلون بين السياقين خلال الجلسة الواحدة.
الدرس من edar: حقول الإدخال هي حيث يبدو كسر RTL الأوضح. يرث <input type="text"> الـdir من أبيه، لكن إدخال النص بالعربية — باستخدام لوحة مفاتيح تتبدّل الاتجاه — يمكن أن يُنتج سلوكاً غير متوقع للمؤشر إذا لم يتطابق اتجاه عرض الحقل مع اتجاه الإدخال.
حلّنا: ضبط dir على حقول الإدخال النصي ديناميكياً بناءً على لغة النص المُدخَل.
input.addEventListener('input', (e) => {
const value = e.target.value;
// إذا كان الحرف الأول في نطاق Unicode العربي، اضبط RTL
const isArabic = /[\u0600-\u06FF]/.test(value[0]);
e.target.dir = isArabic ? 'rtl' : 'ltr';
});
هذا المقطع الصغير يحل أكثر شكوى شائعة يواجهها المستخدمون العرب مع النماذج: بدء المؤشر من الجانب الخاطئ.
helpyard.ae
helpyard هو سوق للخدمات. يتصفح المستخدمون خدمات المنازل ويحجزونها، ويجب أن تبدو الواجهة طبيعية بكلتا اللغتين لأن نفس المستخدمين يستخدمون كليهما يومياً.
التحدي الرئيسي كان اتجاهية الأيقونات والصور في شبكة البطاقات. عندما قلبنا التخطيط إلى RTL، بدت صور الأشخاص (التي لها تدفق بصري LTR بطبيعتها في مخزون الصور) مقلوبة. صورة منظّف يحمل ممسحة في يده اليمنى بدت خاطئة في تخطيط RTL لأنها أوحت بأنه يتحرك يساراً، بعيداً عن اتجاه قراءة المستخدم.
الحل العملي ليس عكس الصور (لا تفعل ذلك أبداً مع صور الأشخاص)، بل مصدر صور محايدة بالنسبة لـRTL حيثما أمكن — لقطات علوية، صور مقرّبة، تراكيب متماثلة. هذا الآن متطلب في موجز التصميم، وليس فكرة لاحقة.
قائمة التحقق للاختبار
قبل أي إصدار عربي، نُراجع هذه القائمة:
- كل أيقونة ذات معنى اتجاهي اختُبرت في RTL وتُقلب بشكل صحيح
- لا
letter-spacingمُطبَّق على أي نص عربي - جميع حقول الإدخال النصي تملك اكتشافاً تلقائياً للـ
dirأو مضبوطة صراحةً - الـURLs وأسماء المنتجات ومقاطع الكود في النثر العربي ملفوفة في spans بـ
dir="ltr" - الأرقام تستخدم
Intl.NumberFormatمع لغة صريحة - التخطيط معكوس بصرياً عند تطبيق
dir="rtl"على<html>— العناصر غير المنعكسة هي أخطاء ما لم تكن مقصودة - سمة
langعلى<html>تتطابق مع اللغة المعروضة — هذا يؤثر على التدقيق الإملائي وضبط المقاطع وسلوك قارئ الشاشة - بدائل
hreflangموجودة وصحيحة لتحسين محركات البحث
ما الذي تحققه بـRTL-أولاً فعلياً
عندما تبني بنهج RTL-أولاً، تصبح بعض الأمور حقيقة:
مكوناتك أكثر قابلية للتأليف. الخصائص المنطقية في CSS والتخطيطات المحايدة للاتجاه تُنتج مكونات تعمل حقاً في أي سياق. تصبح أسهل في إعادة الاستخدام لأنها تحمل افتراضات أقل.
قاعدة الكود تصبح أصغر. الدعم ثنائي الاتجاه المضمّن من البداية لا يحتاج إلى جداول أنماط للتجاوز، ولا JavaScript شرطي للاتجاه، ولا كتل محدد [dir="rtl"]. الأنماط الأساسية تعمل فقط.
مستخدموك العرب يلاحظون الفرق. واجهة مبنية بـRTL-أولاً تشعر مختلفة للمتحدث العربي عن واجهة مُكيَّفة بعد الحقيقة. التباعد صحيح، والإيقاع صحيح، والطباعة تتنفس بشكل صحيح. هذه ليست أموراً يُعبّر عنها المستخدمون — بل هي أمور يشعرون بها كراحة أو كاحتكاك.
بعد عامين، كل منتج نشحنه يدعم كلا الاتجاهين من أول عملية نشر. تكلفة الحفاظ على ذلك منخفضة. أما تكلفة عدم امتلاكه فتُدفَع في كل مرة تفتح فيها النسخة العربية من منتج منافس.
للاطلاع على الجانب الاستراتيجي للمحتوى في البناء للأسواق الناطقة بالعربية، راجع الفجوة في المحتوى العربي: لماذا تخسر الشركات السوق الشرق أوسطية وكيف يعمل تحسين محركات البحث العربي فعلياً في 2026.