كيفية دعم اللغات من اليمين إلى اليسار (RTL) في React Router v7
عكس التخطيطات للعربية والعبرية
المشكلة
تفترض معظم أنظمة التصميم أن النص يتدفق من اليسار إلى اليمين. يبدأ التنقل من اليسار، وترتكز الأشرطة الجانبية على اليسار، ويُقرأ المحتوى من اليسار إلى اليمين. لكن العربية والعبرية تُقرأ من اليمين إلى اليسار، ويجب أن تنعكس تخطيطاتها وفقاً لذلك - ما يظهر على اليسار للإنجليزية يجب أن يظهر على اليمين للعربية. بدون هذا الانعكاس، تبدو الواجهة بأكملها معكوسة. يتعارض التدفق البصري مع اتجاه القراءة، مما يخلق تجربة مربكة حيث يجب على المستخدمين محاربة التخطيط للقراءة بشكل طبيعي.
يمتد التحدي إلى ما هو أبعد من مجرد محاذاة النص. تحتاج الهوامش والحشو والحدود والموضع جميعها إلى التكيف. يجب أن يحتوي الزر الذي له هامش أيسر في الإنجليزية على هامش أيمن في العربية. يجب أن تشير الأيقونات التي تشير إلى اليمين إلى اليسار. يجب أن ينقلب المنطق المكاني بأكمله للواجهة ليتطابق مع اتجاه القراءة.
الحل
قم بتعيين سمة dir على عنصر <html> في المستند لتحديد اتجاه النص للغة الحالية. استخدم ltr للغات من اليسار إلى اليمين مثل الإنجليزية وrtl للغات من اليمين إلى اليسار مثل العربية والعبرية. تتسبب هذه السمة الواحدة في قيام المتصفحات تلقائياً بعكس العديد من سلوكيات التخطيط.
صمم التخطيطات باستخدام خصائص CSS المنطقية مثل margin-inline-start بدلاً من الخصائص الفيزيائية مثل margin-left، بحيث تتكيف المسافات تلقائياً عندما يتغير اتجاه النص. الخصائص المنطقية محايدة للاتجاه - فهي تحدد المسافات بالنسبة لتدفق النص بدلاً من المواضع الثابتة على الشاشة. عندما يكون اتجاه المستند RTL، يصبح margin-inline-start margin-right، وينعكس التخطيط تلقائياً دون كود إضافي.
الخطوات
1. اكتشاف اتجاه النص للغة الحالية
يتطلب React Router 7 مسارًا جذريًا في app/root.tsx يعرض مستند HTML. أنشئ دالة مساعدة تربط رموز اللغات باتجاه النص الخاص بها.
const locales = {
en: { dir: "ltr" },
ar: { dir: "rtl" },
he: { dir: "rtl" },
es: { dir: "ltr" },
};
function getTextDirection(locale: string): "ltr" | "rtl" {
return locales[locale as keyof typeof locales]?.dir || "ltr";
}
تُرجع هذه الدالة الاتجاه المناسب لكل لغة مدعومة، مع الافتراض إلى اليسار-إلى-اليمين للغات غير المعروفة.
2. تعيين سمة dir على عنصر html
في التخطيط الجذري الخاص بك، استرجع اللغة الحالية وطبّق الاتجاه المقابل على المستند.
import { Links, Meta, Outlet, Scripts, ScrollRestoration } from "react-router";
export function Layout({ children }: { children: React.ReactNode }) {
return (
<html lang="en" dir="ltr">
<head>
<meta charSet="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<Meta />
<Links />
</head>
<body>
{children}
<ScrollRestoration />
<Scripts />
</body>
</html>
);
}
export default function Root() {
return <Outlet />;
}
استبدل dir="ltr" المكتوبة بشكل ثابت بقيمة ديناميكية بناءً على آلية اكتشاف اللغة لديك. إذا كان تطبيقك يخزن اللغة الحالية في loader أو context، اقرأها هنا ومررها إلى getTextDirection.
3. استخدام الخصائص المنطقية للمسافات
استبدل خصائص CSS الفيزيائية بمكافئاتها المنطقية في المكونات وأوراق الأنماط الخاصة بك.
export default function Card({
title,
children,
}: {
title: string;
children: React.ReactNode;
}) {
return (
<div
style={{
paddingInlineStart: "1rem",
paddingInlineEnd: "1rem",
marginInlineStart: "auto",
borderInlineStart: "4px solid blue",
}}
>
<h2>{title}</h2>
{children}
</div>
);
}
عندما يتم تعيين dir="rtl"، يُطبق paddingInlineStart على الجانب الأيمن وpaddingInlineEnd على الجانب الأيسر، مما يعكس التخطيط تلقائيًا. يعمل نفس المكون بشكل صحيح في سياقات LTR وRTL دون منطق شرطي.
4. تطبيق الخصائص المنطقية على حاويات التخطيط
استخدم الخصائص المنطقية لأنماط التخطيط الشائعة مثل أشرطة التنقل وشبكات المحتوى.
export default function Navigation() {
return (
<nav
style={{
display: "flex",
gap: "1rem",
paddingInline: "2rem",
borderBlockEnd: "1px solid #ccc",
}}
>
<a href="/" style={{ marginInlineEnd: "auto" }}>
Home
</a>
<a href="/about">About</a>
<a href="/contact">Contact</a>
</nav>
);
}
paddingInline يعيّن الحشو على كلا الجانبين الداخليين، وmarginInlineEnd: "auto" يدفع المحتوى إلى حافة البداية الداخلية، والتي تنقلب من اليسار إلى اليمين عند تغيير الاتجاه. يعكس تخطيط التنقل تلقائيًا للغات RTL.
5. التعامل مع الأيقونات والرسومات الاتجاهية
بالنسبة للأيقونات التي تمثل الاتجاه أو التدفق، اقلبها بشكل مشروط بناءً على اتجاه النص.
function BackButton() {
const dir = document.documentElement.dir;
const iconStyle = {
transform: dir === "rtl" ? "scaleX(-1)" : "none",
marginInlineEnd: "0.5rem",
};
return (
<button>
<span style={iconStyle}>←</span>
Back
</button>
);
}
يؤدي هذا إلى قلب أيقونة السهم أفقياً في وضع RTL مع الحفاظ على النص والمسافات مدركة للاتجاه من خلال الخصائص المنطقية. ليست كل الأيقونات بحاجة إلى القلب—فقط تلك التي تشير إلى الاتجاه أو الحركة.