Как валидировать параметры локали в 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|.*\\..*).*)"],
};
Промежуточное ПО извлекает локаль из пути 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 - Page Not Found</h1>
<p>The page you are looking for does not exist.</p>
</div>
);
}
Эта страница отображается, когда промежуточное ПО переписывает запросы с некорректной локалью, показывая пользователям понятное сообщение о том, что запрошенный URL недоступен.