Cómo detectar las preferencias de idioma del usuario en Next.js (Pages Router) v16

Redirección automática basada en las preferencias del navegador

Problema

Cada navegador envía una cabecera Accept-Language con cada solicitud HTTP, indicando los idiomas preferidos del usuario en orden de prioridad. La mayoría de las aplicaciones ignoran esta valiosa señal y sirven un idioma predeterminado a todos los visitantes, obligando a los usuarios a buscar manualmente un selector de idioma incluso cuando la aplicación ya conoce sus preferencias. Esto crea una fricción innecesaria durante la primera visita y puede llevar a los usuarios a abandonar el sitio antes de encontrar contenido en su idioma.

Cuando los usuarios llegan a la ruta raíz de una aplicación, existe la oportunidad de examinar sus preferencias de idioma y dirigirlos inmediatamente al contenido en un idioma que entiendan. Sin esta detección, los usuarios internacionales se enfrentan a una experiencia en inglés por defecto, independientemente de la configuración de su navegador, perdiendo la oportunidad de ofrecer una primera impresión localizada y acogedora.

Solución

Crear una página raíz que ejecute lógica del lado del servidor en cada solicitud a la ruta raíz. Leer la cabecera HTTP Accept-Language de la solicitud entrante y analizarla para extraer el idioma más preferido del usuario. Comparar este idioma con la lista de idiomas que soporta tu aplicación. Si se encuentra una coincidencia, redirigir al usuario a la ruta raíz de ese idioma. Si ningún idioma soportado coincide, redirigir a una ruta de idioma predeterminada.

Este enfoque aprovecha la función getServerSideProps de Next.js, que se ejecuta en el servidor para cada solicitud y puede devolver una respuesta de redirección. Al manejar la detección en la ruta raíz, la aplicación proporciona un valor predeterminado inteligente mientras permite a los usuarios cambiar manualmente de idioma más tarde si es necesario.

Pasos

1. Instalar una biblioteca para analizar la cabecera Accept-Language

El encabezado Accept-Language contiene una lista de códigos de idioma separados por comas con valores de calidad opcionales que deben ser analizados. Instala una biblioteca de análisis para manejar este formato.

npm install accept-language-parser

Esta biblioteca extrae los códigos de idioma y las puntuaciones de calidad del encabezado y los devuelve en orden de prioridad.

2. Crear una página raíz con lógica de redirección del lado del servidor

Crea un archivo pages/index.tsx que se enrutará automáticamente al directorio raíz. Utiliza getServerSideProps para devolver un objeto de redirección con un destino y una bandera permanente.

import { GetServerSideProps } from "next";
import parser from "accept-language-parser";

const SUPPORTED_LOCALES = ["en", "fr", "es", "de"];
const DEFAULT_LOCALE = "en";

export default function RootPage() {
  return null;
}

export const getServerSideProps: GetServerSideProps = async (context) => {
  const acceptLanguageHeader = context.req.headers["accept-language"];

  let targetLocale = DEFAULT_LOCALE;

  if (acceptLanguageHeader) {
    const languages = parser.parse(acceptLanguageHeader);

    const matchedLanguage = languages.find((lang) =>
      SUPPORTED_LOCALES.includes(lang.code),
    );

    if (matchedLanguage) {
      targetLocale = matchedLanguage.code;
    }
  }

  return {
    redirect: {
      destination: `/${targetLocale}`,
      permanent: false,
    },
  };
};

La función getServerSideProps se ejecuta en cada solicitud, leyendo el encabezado Accept-Language y redirigiendo a la ruta de localización apropiada antes de que se renderice cualquier contenido de la página.

3. Definir tus localizaciones soportadas

Actualiza el array SUPPORTED_LOCALES para que coincida con los idiomas que tu aplicación soporta. El analizador devolverá los idiomas en orden de calidad, y el código selecciona la primera coincidencia.

const SUPPORTED_LOCALES = ["en", "fr", "es", "de", "ja", "zh"];
const DEFAULT_LOCALE = "en";

El analizador devuelve los idiomas ordenados por calidad de mayor a menor, por lo que el primer idioma soportado encontrado representa la preferencia más fuerte del usuario que tu aplicación puede satisfacer.

4. Manejar casos sin encabezado Accept-Language

Algunas solicitudes pueden no incluir un encabezado Accept-Language. El código verifica la presencia del encabezado y recurre al idioma predeterminado cuando falta.

if (acceptLanguageHeader) {
  const languages = parser.parse(acceptLanguageHeader);

  const matchedLanguage = languages.find((lang) =>
    SUPPORTED_LOCALES.includes(lang.code),
  );

  if (matchedLanguage) {
    targetLocale = matchedLanguage.code;
  }
}

Esto asegura que la aplicación siempre redirija a una ruta de idioma válida, incluso cuando la información del idioma del navegador no está disponible.