55 lines
1.7 KiB
TypeScript
55 lines
1.7 KiB
TypeScript
import { NextRequest, NextResponse } from 'next/server';
|
|
import { locales, defaultLocale } from './lib/i18n';
|
|
|
|
export function middleware(request: NextRequest) {
|
|
// Check if there is any supported locale in the pathname
|
|
const pathname = request.nextUrl.pathname;
|
|
|
|
// Check if the pathname already includes a locale
|
|
const pathnameIsMissingLocale = locales.every(
|
|
(locale) => !pathname.startsWith(`/${locale}/`) && pathname !== `/${locale}`,
|
|
);
|
|
|
|
// Redirect if there is no locale
|
|
if (pathnameIsMissingLocale) {
|
|
// Try to get locale from Accept-Language header
|
|
const locale = getLocale(request) || defaultLocale;
|
|
|
|
return NextResponse.redirect(new URL(`/${locale}${pathname}`, request.url));
|
|
}
|
|
}
|
|
|
|
function getLocale(request: NextRequest): string | undefined {
|
|
// Get locale from Accept-Language header
|
|
const acceptLanguage = request.headers.get('accept-language');
|
|
|
|
if (!acceptLanguage) return undefined;
|
|
|
|
// Parse Accept-Language header
|
|
const languages = acceptLanguage.split(',').map((lang) => lang.split(';')[0].trim());
|
|
|
|
// Find matching locale
|
|
for (const lang of languages) {
|
|
if (locales.includes(lang as any)) {
|
|
return lang;
|
|
}
|
|
|
|
// Check for language without region (e.g., 'zh' matches 'zh-CN')
|
|
const langWithoutRegion = lang.split('-')[0];
|
|
const matchingLocale = locales.find((locale) => locale.startsWith(langWithoutRegion));
|
|
|
|
if (matchingLocale) {
|
|
return matchingLocale;
|
|
}
|
|
}
|
|
|
|
return undefined;
|
|
}
|
|
|
|
export const config = {
|
|
matcher: [
|
|
// Skip all internal paths (_next)
|
|
'/((?!_next|api|favicon.ico|.*\\..*).*)',
|
|
],
|
|
};
|