Persistencia de la elección de idioma del usuario

Uso de una cookie para recordar una selección

Problema

Un usuario selecciona manualmente 'Francés' en un sitio. Cuando cierra su navegador y posteriormente escribe la dirección principal del sitio (por ejemplo, example.com), la aplicación vuelve a su configuración predeterminada (por ejemplo, inglés) o al idioma detectado automáticamente. Este fallo al recordar su elección obliga al usuario a encontrar el selector de idioma y volver a seleccionar su idioma cada vez que inicia una nueva sesión.

Solución

Cuando un usuario selecciona un idioma, almacena esa elección en una cookie. En el middleware, cuando un usuario visita la ruta raíz (/), verifica esta cookie antes de comprobar el encabezado Accept-Language. Si se encuentra una cookie válida, redirige al usuario a la raíz de su idioma elegido (por ejemplo, /fr), anulando cualquier configuración predeterminada del navegador.

Pasos

1. Definir la configuración de idioma

Crea un archivo de configuración central para almacenar tus idiomas compatibles, un idioma predeterminado y el nombre de la cookie que utilizarás para almacenar la preferencia del usuario.

// i18n.config.ts

export const locales = ['en', 'es', 'fr'];
export const defaultLocale = 'en';
export const localeCookieName = 'NEXT_LOCALE';

2. Instalar un analizador de idioma

Todavía necesitas un analizador para el encabezado Accept-Language, que se utilizará como respaldo si no se establece ninguna cookie.

npm install accept-language-parser

3. Crear el middleware

Crea un archivo middleware.ts en la raíz de tu proyecto. Este middleware verificará primero la cookie NEXT_LOCALE. Si no se encuentra, recurrirá a verificar el encabezado Accept-Language. Esta lógica solo se aplicará a las solicitudes para la ruta raíz (/).

// middleware.ts
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
import parser from 'accept-language-parser';
import {
  locales,
  defaultLocale,
  localeCookieName,
} from './i18n.config';

function getPreferredLocale(request: NextRequest) {
  // 1. Verificar la cookie
  const cookie = request.cookies.get(localeCookieName);
  if (cookie) {
    const locale = cookie.value;
    if (locales.includes(locale)) {
      return locale;
    }
  }

  // 2. Verificar el encabezado Accept-Language
  const acceptLang = request.headers.get('Accept-Language');
  if (acceptLang) {
    const bestMatch = parser.pick(locales, acceptLang, {
      loose: true,
    });
    if (bestMatch) {
      return bestMatch;
    }
  }

  // 3. Devolver el valor predeterminado
  return defaultLocale;
}

export function middleware(request: NextRequest) {
  const { pathname } = request.nextUrl;

  // 1. Verificar si la solicitud es para la ruta raíz
  if (pathname === '/') {
    // Obtener el idioma preferido del usuario (de la cookie o encabezado)
    const bestLocale = getPreferredLocale(request);

    // Redirigir a la ruta del idioma mejor coincidente
    request.nextUrl.pathname = `/${bestLocale}`;
    return NextResponse.redirect(request.nextUrl);
  }

  // 2. Para todas las demás rutas, continuar normalmente
  return NextResponse.next();
}

export const config = {
  matcher: [
    // Solo queremos ejecutar esto en la ruta raíz por ahora
    '/',
    // También necesitamos coincidir con rutas no raíz para dejarlas pasar
    '/((?!api|_next/static|_next/image|favicon.ico).*)',
  ],
};

La lógica de este middleware ahora prioriza correctamente la elección explícita del usuario (la cookie) sobre su preferencia implícita (el encabezado del navegador) cuando visitan la raíz del sitio.