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 —típicamente 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 una fricción innecesaria y una mala primera impresión, especialmente para usuarios internacionales.
Solución
Crear un cargador para la ruta raíz que lea el encabezado Accept-Language de la solicitud entrante. Analizar el encabezado para extraer los idiomas preferidos del usuario y sus valores de calidad. Comparar los idiomas preferidos con los idiomas compatibles de tu aplicación. Si se encuentra una coincidencia, redirigir al usuario a la ruta de ese idioma. Si ningún idioma compatible coincide, redirigir a un idioma predeterminado. Esto asegura que los usuarios lleguen automáticamente a una versión localizada de tu sitio, basada en las preferencias que ya han configurado en su navegador.
Pasos
1. Instalar 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 extremos según la especificación HTTP.
2. Definir tus idiomas compatibles
Crea un archivo auxiliar que enumere los idiomas que tu aplicación admite y especifica un valor predeterminado alternativo.
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 sobre qué idiomas puede servir tu aplicación y garantiza la seguridad de tipos en todo tu código.
3. Crear un ayudante de detección de idioma
Construye 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 predeterminado.
4. Configurar la ruta índice raíz
Añade 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
Crea 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 el contenido en su idioma preferido desde la primera carga de página.