Как определить языковые предпочтения пользователя в React Router v7
Автоматическое перенаправление на основе предпочтений браузера
Проблема
Каждый браузер отправляет заголовок Accept-Language с каждым HTTP-запросом, указывая предпочтительные языки пользователя в порядке их приоритета. Этот заголовок содержит ценную информацию о том, на каком языке пользователь ожидает увидеть контент, однако большинство приложений полностью игнорируют его. Вместо этого они показывают язык по умолчанию — обычно английский — каждому посетителю, заставляя пользователей вручную искать переключатель языка, даже если их браузер уже передал их предпочтения. Это создает ненужные трудности и оставляет плохое первое впечатление, особенно для международных пользователей.
Решение
Создайте загрузчик для корневого пути, который считывает заголовок Accept-Language из входящего запроса. Разберите заголовок, чтобы извлечь предпочтительные языки пользователя и их качественные значения. Сравните предпочтительные языки с поддерживаемыми локалями вашего приложения. Если совпадение найдено, перенаправьте пользователя на путь этой локали. Если ни один из поддерживаемых языков не совпадает, перенаправьте на локаль по умолчанию. Это гарантирует, что пользователи автоматически попадут на локализованную версию вашего сайта, основываясь на предпочтениях, которые они уже настроили в своем браузере.
Шаги
1. Установите библиотеку для разбора заголовка Accept-Language
Заголовок Accept-Language имеет специфический формат с качественными значениями, который требует тщательного разбора. Используйте специализированную библиотеку для корректной обработки.
npm install accept-language-parser
Эта библиотека разбирает строку заголовка в упорядоченный список языковых предпочтений, обрабатывая качественные значения и крайние случаи в соответствии со спецификацией HTTP.
2. Определите поддерживаемые локали
Создайте вспомогательный файл, который перечисляет локали, поддерживаемые вашим приложением, и указывает локаль по умолчанию.
export const supportedLocales = ["en", "fr", "de", "es", "ja"] as const;
export const defaultLocale = "en";
export type Locale = (typeof supportedLocales)[number];
Это обеспечивает единый источник правды о том, какие языки может обслуживать ваше приложение, и гарантирует типобезопасность во всем коде.
3. Создайте помощник для определения локали
Создайте функцию, которая принимает значение заголовка Accept-Language и возвращает наиболее подходящую поддерживаемую локаль.
import parser from "accept-language-parser";
import { supportedLocales, defaultLocale, type Locale } from "./locales";
export function detectLocale(acceptLanguageHeader: string | null): Locale {
if (!acceptLanguageHeader) {
return defaultLocale;
}
const languages = parser.parse(acceptLanguageHeader);
for (const lang of languages) {
const code = lang.code.toLowerCase();
if (supportedLocales.includes(code as Locale)) {
return code as Locale;
}
}
return defaultLocale;
}
Эта функция анализирует заголовок, проходит по языковым предпочтениям пользователя в порядке их приоритета и возвращает первое совпадение с вашими поддерживаемыми локалями или возвращает локаль по умолчанию.
4. Настройте корневой маршрут индекса
Добавьте маршрут индекса в конфигурацию маршрутов, который будет обрабатывать запросы к корневому пути.
import { type RouteConfig, index, route } from "@react-router/dev/routes";
export default [
index("routes/index.tsx"),
route(":locale", "routes/locale-root.tsx", []),
] satisfies RouteConfig;
Маршрут индекса будет перехватывать запросы к корневому пути до того, как совпадет любой другой маршрут, что позволит вам выполнить определение языка и перенаправление.
5. Реализуйте загрузчик маршрута индекса с определением языка
Создайте модуль маршрута индекса, который считывает заголовок Accept-Language и перенаправляет на соответствующий путь локали.
import { redirect } from "react-router";
import type { Route } from "./+types/index";
import { detectLocale } from "~/utils/detect-locale";
export async function loader({ request }: Route.LoaderArgs) {
const acceptLanguage = request.headers.get("Accept-Language");
const locale = detectLocale(acceptLanguage);
return redirect(`/${locale}`);
}
Когда пользователь посещает корневой путь, этот загрузчик извлекает заголовок Accept-Language из запроса, определяет наилучшую локаль и перенаправляет его на корневой путь этой локали, гарантируя, что пользователь увидит контент на предпочитаемом языке с первой загрузки страницы.