Cómo validar parámetros de locale en URLs en Next.js (Pages Router) v16

Maneja códigos de locale no soportados de manera elegante

Problema

Cuando los códigos de idioma forman parte de la estructura de URL, se convierten en datos de entrada del usuario que deben validarse. Un visitante puede escribir /xx/about o /gibberish/contact tan fácilmente como un idioma válido como /en/about. Sin validación, la aplicación puede fallar, mostrar contenido incorrecto o mensajes de error confusos. Los usuarios que encuentran URLs con idiomas inválidos necesitan un camino claro a seguir—ya sea mediante redirección a un idioma válido o una respuesta apropiada de "No encontrado" que les ayude a entender qué salió mal.

Solución

Valida los parámetros de idioma entrantes contra una lista de idiomas soportados antes de que la solicitud llegue a los componentes de la página. Utiliza el middleware de Next.js para interceptar solicitudes, verificar si el idioma en la URL coincide con un valor soportado y responder adecuadamente. Para idiomas inválidos, redirige al usuario al idioma predeterminado o reescribe la solicitud para mostrar una página 404. Esto asegura que solo los códigos de idioma válidos procedan a renderizar contenido, mientras que los códigos inválidos se manejan elegantemente sin romper la experiencia del usuario.

Pasos

1. Define los idiomas soportados en la configuración de Next.js

Configura los ajustes de i18n en next.config.js para declarar qué idiomas soporta tu aplicación y qué idioma sirve como predeterminado.

module.exports = {
  i18n: {
    locales: ["en", "fr", "de"],
    defaultLocale: "en",
    localeDetection: false,
  },
};

Establecer localeDetection como false evita redirecciones automáticas basadas en preferencias del navegador, dándote control total sobre el manejo de idiomas.

2. Crea middleware para validar parámetros de idioma

Crea un archivo middleware.ts en la raíz de tu proyecto o dentro de la carpeta src si estás usando una.

import { NextRequest, NextResponse } from "next/server";

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

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

  const pathnameHasLocale = SUPPORTED_LOCALES.some(
    (locale) => pathname.startsWith(`/${locale}/`) || pathname === `/${locale}`,
  );

  if (!pathnameHasLocale) {
    return;
  }

  const localeInPath = pathname.split("/")[1];

  if (!SUPPORTED_LOCALES.includes(localeInPath)) {
    const url = request.nextUrl.clone();
    url.pathname = pathname.replace(`/${localeInPath}`, `/${DEFAULT_LOCALE}`);
    return NextResponse.redirect(url);
  }
}

export const config = {
  matcher: ["/((?!_next|api|favicon.ico|.*\\..*).*)"],
};

El middleware extrae el idioma de la ruta URL, lo verifica contra el array de idiomas soportados, y redirige los idiomas inválidos al idioma predeterminado mientras preserva el resto de la ruta.

3. Manejar locales inválidos con una respuesta 404

Si prefieres mostrar una página 404 en lugar de redirigir, reescribe la solicitud a la página 404 personalizada.

import { NextRequest, NextResponse } from "next/server";

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

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

  const pathnameHasLocale = SUPPORTED_LOCALES.some(
    (locale) => pathname.startsWith(`/${locale}/`) || pathname === `/${locale}`,
  );

  if (!pathnameHasLocale) {
    return;
  }

  const localeInPath = pathname.split("/")[1];

  if (!SUPPORTED_LOCALES.includes(localeInPath)) {
    const url = request.nextUrl.clone();
    url.pathname = "/404";
    return NextResponse.rewrite(url);
  }
}

export const config = {
  matcher: ["/((?!_next|api|favicon.ico|.*\\..*).*)"],
};

Crea una página 404 personalizada en pages/404.js que se genera estáticamente durante la compilación.

4. Crear una página 404 personalizada

export default function Custom404() {
  return (
    <div>
      <h1>404 - Página no encontrada</h1>
      <p>La página que estás buscando no existe.</p>
    </div>
  );
}

Esta página se muestra cuando el middleware reescribe solicitudes con locales inválidos, proporcionando a los usuarios un mensaje claro de que la URL solicitada no está disponible.