اكتشاف اللغة المفضلة للمستخدم

إعادة توجيه الزوار الجدد إلى اللغة الأكثر احتمالاً

المشكلة

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

الحل

استخدم middleware لاعتراض الطلبات الموجهة إلى المسار الجذر (/). تحقق من رأس HTTP الخاص بـ Accept-Language للمستخدم للعثور على لغته المفضلة. إذا كانت تلك اللغة مدعومة من قبل التطبيق، أعد توجيه المستخدم إلى جذر تلك اللغة (مثل /fr). إذا لم تكن مدعومة، أعد توجيههم إلى لغة افتراضية (مثل /en).

الخطوات

1. تثبيت محلل اللغة

يمكن أن يكون رأس Accept-Language معقداً (مثل fr-CH, fr;q=0.9, en;q=0.8). تساعد مكتبة صغيرة في تحليل هذا الرأس والعثور على أفضل تطابق من قائمة اللغات المدعومة لدينا.

قم بتشغيل هذا الأمر في الطرفية الخاصة بك:

npm install accept-language-parser

2. تحديد اللغات والافتراضية

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

// i18n.config.ts

export const locales = ['en', 'es', 'fr'];
export const defaultLocale = 'en';

3. إنشاء middleware

أنشئ ملف middleware.ts في جذر مشروعك. سيعمل هذا الملف على الطلبات الواردة، مما يسمح لك بفحص المسار والرؤوس.

// middleware.ts
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
import parser from 'accept-language-parser';
import { locales, defaultLocale } from './i18n.config';

// Helper function to find the best language match
function getBestLocale(acceptLangHeader: string | null) {
  if (!acceptLangHeader) {
    return defaultLocale;
  }

  // Use the parser to find the best supported language
  const bestMatch = parser.pick(locales, acceptLangHeader, {
    loose: true,
  });

  return bestMatch || defaultLocale;
}

export function middleware(request: NextRequest) {
  const { pathname } = request.nextUrl;

  // 1. Check if the request is for the root path
  if (pathname === '/') {
    // Get the user's preferred language
    const acceptLang = request.headers.get('Accept-Language');
    const bestLocale = getBestLocale(acceptLang);

    // Redirect to the best-matched language path
    request.nextUrl.pathname = `/${bestLocale}`;
    return NextResponse.redirect(request.nextUrl);
  }

  // 2. For all other paths, continue as normal
  return NextResponse.next();
}

export const config = {
  matcher: [
    // Skip all paths that start with:
    // - api (API routes)
    // - _next/static (static files)
    // - _next/image (image optimization files)
    // - favicon.ico (favicon file)
    '/((?!api|_next/static|_next/image|favicon.ico).*)',
  ],
};

يعمل هذا الكود فقط على المسار الجذر (/). إذا زار المستخدم /، فإنه يتحقق من رأس Accept-Language الخاص به، ويجد أفضل تطابق (مثل es)، ويعيد توجيههم إلى /es. جميع الطلبات الأخرى، مثل /en/about، يتم تجاهلها بواسطة هذا المنطق وتمر من خلاله.