Cómo detectar las preferencias de idioma del usuario en React Router v7
Redirección automática basada en las preferencias del navegador
Problema
Cada navegador envía un encabezado Accept-Language con cada solicitud HTTP, indicando los idiomas preferidos del usuario en orden de preferencia. Este encabezado contiene información valiosa sobre qué idioma espera ver el usuario, sin embargo, la mayoría de las aplicaciones lo ignoran por completo. En su lugar, muestran un idioma predeterminado (normalmente inglés) a cada visitante, obligando a los usuarios a buscar manualmente un selector de idioma aunque su navegador ya haya comunicado su preferencia. Esto crea fricción innecesaria y una mala primera impresión, especialmente para usuarios internacionales.
Solución
Crea un cargador para la ruta raíz que lea el encabezado Accept-Language de la solicitud entrante. Analiza el encabezado para extraer los idiomas preferidos del usuario y sus valores de calidad. Compara los idiomas preferidos con los idiomas soportados por tu aplicación. Si se encuentra una coincidencia, redirige al usuario a la ruta de ese idioma. Si ningún idioma soportado coincide, redirige a un idioma predeterminado. Esto asegura que los usuarios lleguen a una versión localizada de tu sitio automáticamente, basándose en las preferencias que ya han configurado en su navegador.
Pasos
1. Instala una biblioteca para analizar el encabezado Accept-Language
El encabezado Accept-Language tiene un formato específico con valores de calidad que requiere un análisis cuidadoso. Utiliza una biblioteca dedicada para manejar esto correctamente.
npm install accept-language-parser
Esta biblioteca analiza la cadena del encabezado en una lista ordenada de preferencias de idioma, manejando valores de calidad y casos especiales según la especificación HTTP.
2. Define tus idiomas soportados
Crea un archivo auxiliar que liste los idiomas que tu aplicación soporta y especifique un idioma predeterminado de respaldo.
export const supportedLocales = ["en", "fr", "de", "es", "ja"] as const;
export const defaultLocale = "en";
export type Locale = (typeof supportedLocales)[number];
Esto proporciona una única fuente de verdad para los idiomas que tu aplicación puede servir y garantiza la seguridad de tipos en toda tu base de código.
3. Crear una función auxiliar de detección de idioma
Construir una función que tome el valor del encabezado Accept-Language y devuelva el idioma compatible que mejor coincida.
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;
}
Esta función analiza el encabezado, itera a través de las preferencias de idioma del usuario en orden de calidad y devuelve la primera coincidencia con tus idiomas compatibles o recurre al idioma predeterminado.
4. Configurar la ruta índice raíz
Agregar una ruta índice a tu configuración de rutas que manejará las solicitudes a la ruta raíz.
import { type RouteConfig, index, route } from "@react-router/dev/routes";
export default [
index("routes/index.tsx"),
route(":locale", "routes/locale-root.tsx", []),
] satisfies RouteConfig;
La ruta índice interceptará las solicitudes de ruta raíz antes de que coincida cualquier otra ruta, permitiéndote realizar la detección de idioma y redirección.
5. Implementar el cargador de ruta índice con detección de idioma
Crear el módulo de ruta índice que lee el encabezado Accept-Language y redirige a la ruta de idioma apropiada.
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}`);
}
Cuando un usuario visita la ruta raíz, este cargador extrae el encabezado Accept-Language de la solicitud, determina el mejor idioma y los redirige a la ruta raíz de ese idioma, asegurando que vean contenido en su idioma preferido desde la primera carga de página.