Обработка неподдерживаемых языковых кодов
Проблема
Приложение использует путь 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) {
// Логика будет добавлена на следующем шаге
}
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. Обработайте корневой путь отдельно
// (Это будет рассмотрено в следующем рецепте: "Определение предпочтительного языка пользователя"). Пока что просто пропустим его.
if (pathname === '/') {
return NextResponse.next();
}
// 2. Извлеките код языка из пути
const langCode = pathname.split('/')[1];
// 3. Проверьте, есть ли код языка в нашем списке
if (locales.includes(langCode)) {
// Язык допустим, продолжаем к запрашиваемой странице
return NextResponse.next();
}
// 4. Если язык недопустим, перенаправляем на страницу 404
// Это сохраняет некорректный URL в адресной строке браузера
const url = request.nextUrl.clone();
url.pathname = `/404`; // Предполагается, что у вас есть файл app/404.tsx
return NextResponse.rewrite(url);
}
Эта логика проверяет каждый запрос. Если URL — /fr/about, langCode равен fr, он найден в locales, и запрос продолжается. Если URL — /xx/about, langCode равен xx, он не найден, и пользователю показывается страница 404, без попытки приложения обработать некорректный запрос.
4. Настройте сопоставитель middleware
Чтобы сделать ваш middleware более эффективным, вы должны указать, на каких путях он должен выполняться. Мы хотим, чтобы он работал на запросах страниц, но пропускал статические файлы и маршруты API.
Добавьте объект config в конец вашего файла middleware.ts.
// middleware.ts
// ... (функция middleware из примера выше)
export const config = {
matcher: [
// Пропустить все пути, которые начинаются с:
// - api (маршруты API)
// - _next/static (статические файлы)
// - _next/image (файлы оптимизации изображений)
// - favicon.ico (файл favicon)
'/((?!api|_next/static|_next/image|favicon.ico).*)',
],
};
Это регулярное выражение указывает middleware выполняться на всех путях, кроме тех, которые обычно используются для статических ресурсов или вызовов API. Это предотвращает ненужную проверку для каждого изображения, шрифта или запроса данных.