كيفية بناء مكون مبدل اللغة في Next.js (موجه الصفحات) الإصدار 16

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

المشكلة

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

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

الحل

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

الخطوات

1. إنشاء مكون مبدل اللغة الذي يقرأ المسار الحالي

يوفر كائن الموجه خصائص pathname وasPath وquery وlocale وlocales التي تحتوي على جميع المعلومات اللازمة لبناء روابط تراعي اللغة المحلية.

import { useRouter } from "next/router";
import Link from "next/link";

export default function LanguageSwitcher() {
  const router = useRouter();
  const { locale, locales, pathname, asPath, query } = router;

  return (
    <nav>
      {locales?.map((loc) => (
        <Link key={loc} href={{ pathname, query }} as={asPath} locale={loc}>
          {loc.toUpperCase()}
        </Link>
      ))}
    </nav>
  );
}

يقبل مكون Link خاصية locale للانتقال إلى لغة محلية مختلفة عن اللغة النشطة حاليًا. إن تمرير pathname وquery ككائن إلى href يحافظ على جميع معلومات التوجيه بما في ذلك قيم استعلام المسار الديناميكي.

2. تنسيق اللغة النشطة لتوفير تغذية راجعة بصرية

قم بتمييز اللغة الحالية حتى يعرف المستخدمون أي لغة يشاهدونها.

import { useRouter } from "next/router";
import Link from "next/link";

export default function LanguageSwitcher() {
  const router = useRouter();
  const { locale, locales, pathname, asPath, query } = router;

  return (
    <nav>
      {locales?.map((loc) => {
        const isActive = loc === locale;
        return (
          <Link
            key={loc}
            href={{ pathname, query }}
            as={asPath}
            locale={loc}
            style={{
              fontWeight: isActive ? "bold" : "normal",
              textDecoration: isActive ? "none" : "underline",
              marginRight: "1rem",
            }}
          >
            {loc.toUpperCase()}
          </Link>
        );
      })}
    </nav>
  );
}

تتم مقارنة كل لغة بقيمة locale الحالية لتحديد اللغة النشطة وتطبيق تنسيق مميز لتمييزها عن البدائل المتاحة.

3. إضافة تسميات يمكن الوصول إليها باستخدام react-intl

استبدل رموز اللغات بأسماء لغات مقروءة للبشر لتحسين قابلية الاستخدام.

import { useRouter } from "next/router";
import { useIntl } from "react-intl";
import Link from "next/link";

const localeNames: Record<string, string> = {
  en: "English",
  es: "Español",
  fr: "Français",
  de: "Deutsch",
};

export default function LanguageSwitcher() {
  const router = useRouter();
  const intl = useIntl();
  const { locale, locales, pathname, asPath, query } = router;

  return (
    <nav
      aria-label={intl.formatMessage({
        id: "languageSwitcher.label",
        defaultMessage: "Select language",
      })}
    >
      {locales?.map((loc) => {
        const isActive = loc === locale;
        return (
          <Link
            key={loc}
            href={{ pathname, query }}
            as={asPath}
            locale={loc}
            aria-current={isActive ? "true" : undefined}
            style={{
              fontWeight: isActive ? "bold" : "normal",
              textDecoration: isActive ? "none" : "underline",
              marginRight: "1rem",
            }}
          >
            {localeNames[loc] || loc}
          </Link>
        );
      })}
    </nav>
  );
}

يوفر مُعلق useIntl إمكانية الوصول إلى وظائف التنسيق لترجمة تسميات واجهة المستخدم. تعمل سمات aria-label وaria-current على تحسين إمكانية الوصول لمستخدمي قارئات الشاشة.