يستطيع React Native إنتاج تطبيق عربي ممتاز. لكنه لا يفعل ذلك افتراضياً، والمسافة بين «ضبطنا I18nManager.forceRTL(true)» و«هذا يبدو تطبيقاً عربياً» هي حيث تخسر معظم المشاريع أسابيع.
الإجابة المختصرة: دعم RTL في React Native يعمل، لكنه مُضاف لا مبنيّ في الصميم. التخطيط ينعكس تلقائياً، واشتراط إعادة التشغيل يفاجئ الجميع، والمكتبات الخارجية هي حيث يُكسَر التعريب فعلاً.
هذا الدليل يغطي خصوصيات React Native. أما للنطاق الكامل لما يتضمنه التعريب خلف الاتجاه، فراجع الدليل الكامل لتعريب التطبيقات والمواقع.
I18nManager ومشكلة إعادة التشغيل
يمرّ RTL في React Native عبر I18nManager:
import { I18nManager } from "react-native";
I18nManager.allowRTL(true);
I18nManager.forceRTL(true);
والمفاجأة التي تصدم كل فريق: هذه لا تسري إلا بعد إعادة تشغيل التطبيق. الطبقة الأصلية تقرأ الاتجاه عند الإقلاع، فاستدعاء forceRTL أثناء التشغيل يغيّر القيمة المخزّنة لا تخطيط الجلسة الحالية.
وهذا ينتج تجربة محرجة فعلاً: مبدّل لغة يبدو أنه لا يفعل شيئاً حتى يُعاد تشغيل التطبيق. وخياراتك بصراحة:
الخيار 1 — أعد تشغيل التطبيق. استخدم مكتبة مثل react-native-restart وأخبر المستخدم بما يحدث. فجّ لكنه متوقع ويعمل دائماً.
الخيار 2 — حدّد الاتجاه عند أول إقلاع ولا تتح التبديل. مناسب للمنتجات ذات السوق الواحد. وأبسط بكثير.
الخيار 3 — لا تستخدم I18nManager إطلاقاً. أدر الاتجاه بنفسك في حالة React ونسّق المكوّنات صراحةً. جهد أكبر في البداية وتحكم كامل، بلا إعادة تشغيل. وهو عملي للتطبيقات ذات عدد شاشات معتدل.
اختر هذا مبكراً. ليس قراراً يمكن تأجيله، لأنه يحدد كيف يُنسَّق كل مكوّن. وإضافة الخيار 3 لاحقاً على تطبيق مبنيّ حول
I18nManagerتعني لمس كل شاشة.
الأنماط: ما ينعكس وما لا ينعكس
مع تفعيل RTL، يعكس React Native معظم التخطيط تلقائياً. والخصائص التي يجب معرفتها:
| فيزيائية (تجنّبها) | منطقية (استخدمها) |
|---|---|
marginLeft | marginStart |
marginRight | marginEnd |
paddingLeft | paddingStart |
paddingRight | paddingEnd |
left / right | start / end |
borderLeftWidth | borderStartWidth |
اكتب الخصائص المنطقية في كل مكان ينعكس التخطيط صحيحاً بلا جهد. واكتب الفيزيائية فتجد نفسك تصون مجموعة موازية من تجاوزات RTL تنحرف عن الأصل خلال أسابيع.
وflexDirection: "row" ينعكس تلقائياً تحت RTL. وهذا ما تريده عادةً — وأحياناً لا. فحين تحتاج صفاً يبقى بترتيب ثابت مهما كان الاتجاه، استخدم row-reverse بوعي أو اضبط الاتجاه على تلك الحاوية صراحةً.
وtextAlign يتصرف أفضل مما يتوقع الناس. فضّل textAlign: "left" مع تفعيل RTL على كتابة "right" مباشرة — فتحت RTL يُترجَم left إلى اليمين بصرياً. أما كتابة "right" فتنكسر لحظة عرض المكوّن نفسه بالإنجليزية.
ما يجب ألا ينعكس أبداً
الانعكاس التلقائي أداة غليظة. وهذه يجب أن تبقى كما هي:
- أزرار تشغيل الوسائط — زر التشغيل يتجه يميناً في كل اللغات
- الساعات والمؤقتات
- الرسوم البيانية ذات المحور الزمني — الزمن يجري من اليسار لليمين دائماً
- أرقام الهواتف والآيبان والبطاقات وأرقام الإصدارات
- معظم الشعارات والعلامات التجارية
- كتل الكود ومخرجات الطرفية
وبالنسبة للأيقونات، React Native لا يعكس الصور تلقائياً — تعكسها بنفسك:
const flipForRTL = I18nManager.isRTL ? { transform: [{ scaleX: -1 }] } : {};
طبّق هذا على الأيقونات الاتجاهية فقط — أسهم الرجوع، والتالي/السابق، والإرسال. أما تطبيقه على زر تشغيل أو ساعة فينتج تحديداً الخطأ الذي وُجد هذا القسم لمنعه.
الخطوط والطباعة
خط النظام العربي يختلف بين iOS وAndroid، والفرق واضح بما يكفي ليلاحظه المصممون فوراً. وتضمين خط يمنحك الاتساق:
// بعد إضافة ملفات الخط وربط الأصول
const styles = StyleSheet.create({
arabic: {
fontFamily: "Cairo",
lineHeight: 28, // نحو 1.7× حجم الخط
letterSpacing: 0, // لا شيء غير الصفر للعربية أبداً
},
});
ثلاث قواعد أهم من اختيار الخط نفسه:
letterSpacing يجب أن يكون صفراً. أي قيمة أخرى تكسر اتصال الحروف العربية. وهذه ليست مسألة ذوق — بل تجعل النص مكسوراً بصرياً، وهي أشيع خطأ في الطباعة العربية على الإطلاق.
وlineHeight يحتاج نحو 1.7–1.8× حجم الخط. الحروف العربية تمتد صعوداً ونزولاً أكثر من اللاتينية. وقيمة 1.4–1.5 التي تبدو صحيحة بالإنجليزية تبدو خانقة.
واختبر على المنصتين بنص حقيقي. Android وiOS يعرضان العربية باختلاف كافٍ لجعل تخطيط تحقّقت منه على إحداهما ينكسر على الأخرى، خصوصاً في كسر الأسطر والخط البديل.
الخطوط العربية على الويب يغطي التجزئة وحجم الملف، وينطبق على خطوط التطبيقات المضمّنة أيضاً.
المكتبات الخارجية — حيث يُكسَر RTL فعلاً
هذا مركز التكلفة الحقيقي، ونادراً ما يكون في التقدير.
المكتبات التي تحتاج انتباهاً عادةً: انتقالات التنقل والقوائم الجانبية، والشرائح الدوّارة والمنزلقات، وقوائم السحب للإجراء، ومنتقيات التواريخ، والرسوم البيانية، وكل ما يحوي زر رجوع مدمجاً.
كيف تنكسر: الإيماءات تتحرك في الاتجاه الخاطئ، أو القائمة الجانبية تفتح من الجهة الخاطئة، أو فهرس الشريحة الدوّارة يعمل بالعكس، أو المكتبة تكتب marginLeft داخلياً حيث لا تستطيع الوصول إليه.
كيف تتعامل معها:
- اختبر RTL مبكراً. فعّله في الأسبوع الأول بنص وهمي، لا في الشهر الرابع. الشريحة التي تتحرك بالعكس إصلاح صغير في اليوم الخامس ونقاش معماري في اليوم التسعين.
- افحص دعم RTL قبل تبنّي أي مكتبة. ابحث في مشكلاتها عن «RTL» — وجود مشكلات RTL مفتوحة وعمرها يخبرك بما تحتاج معرفته.
- غلّف المكوّنات الخارجية بمكوّناتك، ليكون الإصلاح في مكان واحد لا متناثراً بين الشاشات.
- خصّص ميزانية لها. افترض أن نسبة من مكتباتك ستحتاج حلولاً التفافية. والفرق التي تخصّص صفراً هنا هي التي تتأخر.
النص ثنائي الاتجاه
الجمل العربية التي تحتوي أسماء منتجات إنجليزية أو أرقاماً أو روابط تحتاج عناية. وبدونها تقع علامات الترقيم في مواضع خاطئة بصرياً — نقطة تظهر في بداية السطر بدل نهايته.
خوارزمية Unicode ثنائية الاتجاه تعالج معظم الحالات، لكن الملتبسة منها تحتاج علامات صريحة: (علامة RTL) و (علامة LTR) حول المقطع المُضمَّن.
متى تظهر هذه المشكلة: الأسعار مع رموز العملات، وأرقام الإصدارات داخل جمل عربية، والمحتوى المختلط الذي ينشئه المستخدمون، والعناوين. وإن كان منتجك يعرض محتوى المستخدمين، فاختبر بمدخلات عربية وإنجليزية مختلطة عمداً — هناك تسكن الأخطاء.
كيف يقارَن React Native بـ Flutter هنا
كلاهما ينتج تطبيقات عربية جيدة. والفرق في مقدار العمل اليدوي الفاصل بينك وبين تلك النتيجة.
Flutter يبني الاتجاهية في الإطار نفسه. فـDirectionality ويدجت من الدرجة الأولى، وEdgeInsetsDirectional هي الطريقة الطبيعية لكتابة الحشوات، ومعظم مكتبة الويدجت تعالج RTL صحيحاً بلا تدخل.
React Native يعامل RTL كقدرة منصة مكشوفة عبر I18nManager. يعمل، لكن اشتراط إعادة التشغيل محرج، ودعم RTL في منظومته الخارجية أقل اتساقاً.
وما يعنيه هذا عملياً: للمنتج العربي أولاً بلا قيد فريق قائم، يحتاج Flutter عمل RTL أقل بشكل ملموس. أما الفريق الذي يكتب React أصلاً، فهذه الميزة لا ترجّح التخلي عن مهاراته القائمة — React Native يبقى الخيار الصحيح، وعليك فقط تخصيص أيام أكثر للتعريب.
Flutter مقابل React Native يغطي القرار الأوسع، ودعم العربية وRTL في Flutter هو الدليل المقابل على الجانب الآخر.
قائمة تحقق قبل الإطلاق
- اختيار استراتيجية الاتجاه:
I18nManagerبإعادة تشغيل، أم ثابت عند الإقلاع، أم يدوي - كل نمط يستخدم
start/endبدلleft/right - الأيقونات الاتجاهية معكوسة، وأزرار التشغيل والساعات والرسوم متروكة كما هي
- خط عربي مضمّن بـ
letterSpacing: 0وlineHeight≈ 1.7× - كل مكوّن خارجي متحقق منه تحت RTL
- انتقالات التنقل والقوائم الجانبية تفتح من الجهة الصحيحة
- الأرقام وأرقام الهواتف والآيبان تُعرض غير معكوسة
- النص المختلط عربي/إنجليزي مختبَر لمواضع الترقيم
- الاختبار على iOS وAndroid بمحتوى عربي حقيقي
- مراجعة بمتحدث عربي أصلي على جهاز حقيقي
اقرأ أيضاً
- الدليل الكامل لتعريب التطبيقات والمواقع — الطبقات الست خلف الاتجاه.
- دعم العربية وRTL في Flutter — المشكلة نفسها في Flutter.
- Flutter مقابل React Native — الاختيار بينهما.
- دليل React Native — البنية والحدود.
- الخطوط العربية على الويب — وزن الخط والتجزئة.
الأسئلة الشائعة
هل يدعم React Native العربية وRTL؟
نعم، عبر I18nManager الذي يعكس التخطيط تلقائياً عند تفعيل RTL. الدعم حقيقي لكنه مُضاف لا مبنيّ في الصميم: التغييرات تتطلب إعادة تشغيل التطبيق، والمكتبات الخارجية تتفاوت كثيراً في جودة تعاملها مع RTL.
لماذا لا يعمل I18nManager.forceRTL فوراً؟
الطبقة الأصلية تقرأ اتجاه التخطيط عند إقلاع التطبيق، فاستدعاء forceRTL أثناء التشغيل يحدّث القيمة المخزّنة دون تغيير الجلسة الحالية. تحتاج إعادة تشغيل. إما أن تستخدم مكتبة إعادة تشغيل وتخبر المستخدم، أو تثبّت الاتجاه عند أول إقلاع، أو تدير الاتجاه يدوياً في حالة React.
أستخدم marginLeft أم marginStart في React Native؟
دائماً marginStart وmarginEnd. الخصائص المنطقية تُترجَم صحيحاً في الاتجاهين تلقائياً، فينعكس التخطيط بلا جهد. أما الفيزيائية فتجبرك على صيانة مجموعة موازية من تجاوزات RTL ستنحرف عن الأصل.
لماذا يبدو النص العربي مكسوراً في React Native؟
letterSpacing دائماً تقريباً. أي قيمة غير صفرية تكسر اتصال الحروف العربية، لأن الخط متصل والحروف ترتبط. اضبط letterSpacing: 0 لكل نص عربي. والسبب الثاني الأشيع هو lineHeight غير كافٍ — العربية تحتاج نحو 1.7 إلى 1.8 ضعف حجم الخط.
هل Flutter أفضل من React Native للتطبيقات العربية؟
Flutter يحتاج عمل RTL يدوياً أقل لأن الاتجاهية مبنية في الإطار لا مكشوفة كعلَم منصة، ومكتبة الويدجت لديه تعالج RTL باتساق أعلى. ومع ذلك، إن كان فريقك يكتب React أصلاً، فهذه الميزة نادراً ما ترجّح التخلي عن مهارات قائمة — استخدم React Native وخصّص أياماً أكثر للتعريب.
كيف أعكس الأيقونات لـRTL في React Native؟
طبّق transform: [{ scaleX: -1 }] بشرط I18nManager.isRTL. وطبّقه على الأيقونات الاتجاهية فقط كأسهم الرجوع وأزرار الإرسال. ولا تطبّقه أبداً على أزرار التشغيل أو الساعات أو الرسوم ذات المحور الزمني — فهذه تحتفظ باتجاهها في كل اللغات.
كم يضيف دعم العربية وRTL من وقت لمشروع React Native؟
للتطبيق المخطط له بـRTL من البداية، نحو 5 إلى 15 يوماً بحسب عدد الشاشات وعدد المكوّنات الخارجية التي تحتاج حلولاً التفافية. أما إضافته لتطبيق مبنيّ بالإنجليزية وحدها فتكلف أكثر بكثير، لأن كل خاصية نمط فيزيائية يجب البحث عنها وإعادة كتابتها.
الخلاصة
حدّد استراتيجية الاتجاه في الأسبوع الأول. سلوك إعادة التشغيل في I18nManager يحدد كيف يُنسَّق كل مكوّن، وتغيير المقاربة لاحقاً يعني مراجعة كل شاشة.
واكتب خصائص الأنماط المنطقية من أول مكوّن. لا تكلفك شيئاً وقتها وتزيل صنفاً كاملاً من أخطاء التخطيط.
وخصّص ميزانية للمكتبات الخارجية. هي حيث يُكسَر RTL فعلاً، ونادراً ما تكون في التقدير، واختبار RTL في الأسبوع الأول بدل الشهر الرابع هو الفرق بين إصلاحات صغيرة ونقاشات معمارية.
تبني تطبيق React Native عربياً؟ تواصل معنا — نحن نبني بالعربية أولاً ونستطيع أن نخبرك بصراحة إن كان React Native أم Flutter أنسب لحالتك. اطّلع على خدمات تطوير تطبيقات الموبايل.