كيفية دعم اللغات من اليمين إلى اليسار (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 مع الحفاظ على النص والمسافات المتوافقة مع الاتجاه من خلال خصائص منطقية. ليست كل الأيقونات تحتاج إلى عكس - فقط تلك التي تشير إلى الاتجاه أو الحركة.