Определение предпочтительного языка пользователя
Перенаправление новых посетителей на наиболее подходящий язык
Проблема
Когда пользователь впервые заходит на корень приложения (например, /), по умолчанию отображается определённый язык, например, английский. Это сразу создаёт неудобство для тех, кто говорит на других языках: им приходится вручную искать переключатель языка, хотя браузер уже сообщает о предпочтениях пользователя.
Решение
Используйте 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, этой логикой не обрабатываются и проходят дальше.