Как проверить параметры локали в URL в Next.js (Pages Router) v16

Элегантная обработка неподдерживаемых кодов локалей

Проблема

Когда коды локалей становятся частью структуры URL, они превращаются в пользовательский ввод, который необходимо проверять. Посетитель может ввести /xx/about или /gibberish/contact так же легко, как и допустимую локаль, например /en/about. Без проверки приложение может выйти из строя, отображать некорректный контент или показывать запутанные сообщения об ошибках. Пользователям, которые сталкиваются с недопустимыми URL локалей, нужен понятный путь решения проблемы — либо через перенаправление на допустимую локаль, либо через корректный ответ "Не найдено", который поможет им понять, что пошло не так.

Решение

Проверяйте входящие параметры локалей на соответствие списку поддерживаемых локалей до того, как запрос достигнет компонентов страницы. Используйте middleware в Next.js для перехвата запросов, проверки, соответствует ли локаль в URL поддерживаемому значению, и соответствующего ответа. Для недопустимых локалей перенаправляйте пользователя на локаль по умолчанию или переписывайте запрос для отображения страницы 404. Это гарантирует, что только допустимые коды локалей будут использоваться для отображения контента, а недопустимые коды будут обработаны корректно, не нарушая пользовательский опыт.

Шаги

1. Определите поддерживаемые локали в конфигурации Next.js

Настройте параметры i18n в next.config.js, чтобы указать, какие локали поддерживает ваше приложение, и какая локаль используется по умолчанию.

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

Установка localeDetection в значение false предотвращает автоматические перенаправления на основе предпочтений браузера, предоставляя вам полный контроль над обработкой локалей.

2. Создайте middleware для проверки параметров локалей

Создайте файл middleware.ts в корне вашего проекта или в папке src, если вы её используете.

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|.*\\..*).*)"],
};

Middleware извлекает локаль из пути URL, проверяет её на соответствие массиву поддерживаемых локалей и перенаправляет недопустимые локали на локаль по умолчанию, сохраняя остальную часть пути.

3. Обработка недопустимых локалей с помощью ответа 404

Если вы предпочитаете показывать страницу 404 вместо перенаправления, перепишите запрос на пользовательскую страницу 404.

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|.*\\..*).*)"],
};

Создайте пользовательскую страницу 404 в pages/404.js, которая будет статически сгенерирована во время сборки.

4. Создание пользовательской страницы 404

export default function Custom404() {
  return (
    <div>
      <h1>404 - Страница не найдена</h1>
      <p>Страница, которую вы ищете, не существует.</p>
    </div>
  );
}

Эта страница отображается, когда middleware переписывает запросы с недопустимыми локалями, предоставляя пользователям четкое сообщение о том, что запрашиваемый URL недоступен.