كيفية بناء مكون تبديل اللغة في React Router v7

تبديل اللغات مع البقاء على نفس الصفحة

المشكلة

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

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

الحل

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

يتعامل هذا النهج مع اللغة كمعامل قابل للاستبدال في بنية عنوان URL بدلاً من وجهة تنقل، مما يضمن أن التبديل من /en/products/shoes إلى /es/products/shoes يحافظ على سياق المستخدم.

الخطوات

1. إنشاء دالة مساعدة لبناء عناوين URL مدركة للغة

حدد دالة تأخذ المسار الحالي واللغة المستهدفة، ثم تنشئ مساراً جديداً عن طريق استبدال جزء اللغة.

export function buildLocalePath(
  currentPath: string,
  newLocale: string,
): string {
  const segments = currentPath.split("/").filter(Boolean);

  if (segments.length === 0) {
    return `/${newLocale}`;
  }

  segments[0] = newLocale;
  return `/${segments.join("/")}`;
}

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

2. حدد اللغات المدعومة

أنشئ كائن تكوين يسرد جميع اللغات التي يدعمها تطبيقك.

export const locales = [
  { code: "en", label: "English" },
  { code: "es", label: "Español" },
  { code: "fr", label: "Français" },
  { code: "de", label: "Deutsch" },
];

يعمل هذا التكوين كمصدر موثوق لتحديد اللغات التي سيتم عرضها في المبدل ويوفر تسميات سهلة الاستخدام لكل لغة.

3. أنشئ مكون مبدل اللغة

أنشئ مكوناً يقرأ الموقع الحالي، ويحدد اللغة النشطة، ويعرض روابط لجميع اللغات المدعومة الأخرى.

import { Link, useLocation, useParams } from "react-router";
import { locales, buildLocalePath } from "./i18n-config";

export function LanguageSwitcher() {
  const location = useLocation();
  const params = useParams();
  const currentLocale = params.locale || "en";

  return (
    <nav aria-label="Language switcher">
      <ul>
        {locales.map((locale) => {
          const isActive = locale.code === currentLocale;
          const newPath = buildLocalePath(location.pathname, locale.code);

          return (
            <li key={locale.code}>
              {isActive ? (
                <span aria-current="true">{locale.label}</span>
              ) : (
                <Link to={newPath}>{locale.label}</Link>
              )}
            </li>
          );
        })}
      </ul>
    </nav>
  );
}

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

4. احتفظ بمعاملات الاستعلام وأجزاء التجزئة

قم بتوسيع الدالة المساعدة للحفاظ على سلاسل الاستعلام وأجزاء عنوان URL عند تبديل اللغات.

export function buildLocalePath(
  currentPath: string,
  search: string,
  hash: string,
  newLocale: string,
): string {
  const segments = currentPath.split("/").filter(Boolean);

  if (segments.length === 0) {
    return `/${newLocale}${search}${hash}`;
  }

  segments[0] = newLocale;
  return `/${segments.join("/")}${search}${hash}`;
}

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

5. حدّث المكون لاستخدام الدالة المساعدة المحسّنة

عدّل المبدل لتمرير معلومات الموقع الكاملة إلى الدالة المساعدة.

import { Link, useLocation, useParams } from "react-router";
import { locales, buildLocalePath } from "./i18n-config";

export function LanguageSwitcher() {
  const location = useLocation();
  const params = useParams();
  const currentLocale = params.locale || "en";

  return (
    <nav aria-label="Language switcher">
      <ul>
        {locales.map((locale) => {
          const isActive = locale.code === currentLocale;
          const newPath = buildLocalePath(
            location.pathname,
            location.search,
            location.hash,
            locale.code,
          );

          return (
            <li key={locale.code}>
              {isActive ? (
                <span aria-current="true">{locale.label}</span>
              ) : (
                <Link to={newPath}>{locale.label}</Link>
              )}
            </li>
          );
        })}
      </ul>
    </nav>
  );
}

يقوم المكون الآن بتمرير location.search و location.hash إلى المساعد، مما يضمن أن عناوين URL مثل /en/products?category=shoes#reviews تصبح /es/products?category=shoes#reviews عند التبديل إلى الإسبانية.