Обработка неподдерживаемых языковых кодов
Проблема
Приложение использует путь в URL (например, /en/, /fr/) для определения языка, но пользователи могут вручную ввести любое значение, например /xx/about. Если это значение не совпадает с поддерживаемым языком, приложение может аварийно завершиться, показать общую ошибку или отобразить непереведённый контент, не направив пользователя обратно к правильному опыту работы.
Решение
Используйте middleware, чтобы перехватывать все входящие запросы. Этот middleware будет сверять языковой код из URL с точным списком поддерживаемых языков. Если код не поддерживается, запрос будет перенаправлен на страницу "Не найдено" до того, как он попадёт в основную логику приложения.
Шаги
1. Определите поддерживаемые языки
Создайте центральный конфигурационный файл для хранения списка допустимых языковых кодов (локалей). Это позволит использовать список повторно в middleware и других частях приложения.
// i18n.config.ts
export const locales = ['en', 'es', 'fr'];
2. Создайте файл middleware
Создайте новый файл с именем middleware.ts в корне вашего проекта (или в каталоге src/). Next.js автоматически обнаружит этот файл и будет запускать его на запросах.
// middleware.ts
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
import { locales } from './i18n.config';
export function middleware(request: NextRequest) {
// Logic will go here in the next step
}
3. Добавьте логику проверки
Внутри функции middleware получите pathname из запроса. Нужно проверить первый сегмент пути (например, en в /en/about) и убедиться, что он является допустимым и поддерживаемым языком.
// middleware.ts
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
import { locales } from './i18n.config';
export function middleware(request: NextRequest) {
const { pathname } = request.nextUrl;
// 1. Handle the root path separately
// (This will be handled by the next recipe: "Detecting a user's
// preferred language"). For now, we just let it pass.
if (pathname === '/') {
return NextResponse.next();
}
// 2. Extract the language code from the path
const langCode = pathname.split('/')[1];
// 3. Check if the language code is in our list
if (locales.includes(langCode)) {
// Language is valid, continue to the requested page
return NextResponse.next();
}
// 4. If the language is not valid, rewrite to a 404 page
// This keeps the invalid URL in the browser bar
const url = request.nextUrl.clone();
url.pathname = `/404`; // Assumes you have an app/404.tsx file
return NextResponse.rewrite(url);
}
Эта логика проверяет каждый запрос. Если URL — /fr/about, langCode — это fr, он найден в locales, и запрос продолжается. Если URL — /xx/about, langCode — это xx, он не найден, и пользователь увидит страницу 404, не дождавшись, пока приложение попытается обработать некорректный запрос.
4. Настройте matcher для middleware
Чтобы сделать ваш middleware более эффективным, укажите, на каких путях он должен работать. Мы хотим, чтобы он запускался только на запросах к страницам, но пропускал статические файлы и API-маршруты.
Добавьте объект config в конце файла middleware.ts.
// middleware.ts
// ... (the middleware function from above)
export const config = {
matcher: [
// Skip all paths that start with:
// - api (API routes)
// - _next/static (static files)
// - _next/image (image optimization files)
// - favicon.ico (favicon file)
'/((?!api|_next/static|_next/image|favicon.ico).*)',
],
};
Это регулярное выражение указывает middleware работать на всех путях, кроме тех, которые обычно используются для статических файлов или API-запросов. Это предотвращает ненужную валидацию для каждого запроса к изображениям, шрифтам или данным.