Detectar el idioma preferido de un usuario
Redirigir a los nuevos visitantes a su idioma más probable
Problema
Cuando un usuario visita por primera vez la raíz de una aplicación (por ejemplo, /), se muestra un idioma predeterminado, como el inglés. Esto crea fricción inmediata para los usuarios que hablan otros idiomas, obligándolos a buscar manualmente un selector de idioma, aunque su navegador ya comunica su preferencia.
Solución
Utiliza middleware para interceptar las solicitudes a la ruta raíz (/). Verifica el encabezado HTTP Accept-Language del usuario para encontrar su idioma preferido. Si ese idioma es compatible con la aplicación, redirige al usuario a la raíz de ese idioma (por ejemplo, /fr). Si no, redirige a un idioma predeterminado (por ejemplo, /en).
Pasos
1. Instalar un analizador de idiomas
El encabezado Accept-Language puede ser complejo (por ejemplo, fr-CH, fr;q=0.9, en;q=0.8). Una pequeña biblioteca ayuda a analizar este encabezado y encontrar la mejor coincidencia de nuestra lista de idiomas compatibles.
Ejecuta este comando en tu terminal:
npm install accept-language-parser
2. Definir tus idiomas y el predeterminado
Crea un archivo de configuración central para almacenar tu lista de idiomas compatibles y definir uno predeterminado. Este predeterminado se utilizará si las preferencias del navegador de un usuario no coinciden con ningún idioma que admitas.
// i18n.config.ts
export const locales = ['en', 'es', 'fr'];
export const defaultLocale = 'en';
3. Crear el middleware
Crea un archivo middleware.ts en la raíz de tu proyecto. Este archivo se ejecutará en las solicitudes entrantes, permitiéndote verificar la ruta y los encabezados.
// 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).*)',
],
};
Este código solo ejecuta lógica para la ruta raíz (/). Si un usuario visita /, verifica su encabezado Accept-Language, encuentra la mejor coincidencia (por ejemplo, es) y lo redirige a /es. Todas las demás solicitudes, como /en/about, son ignoradas por esta lógica y pasan sin modificaciones.