82 lines
2.9 KiB
TypeScript
82 lines
2.9 KiB
TypeScript
import { NextResponse } from 'next/server';
|
|
import type { NextRequest } from 'next/server';
|
|
|
|
const locales = ['zh-CN', 'zh-TW', 'en', 'ko', 'ja'];
|
|
const defaultLocale = 'zh-CN';
|
|
|
|
function getLocale(request: NextRequest): string {
|
|
// Check if there is any supported locale in the pathname
|
|
const pathname = request.nextUrl.pathname;
|
|
const pathnameIsMissingLocale = locales.every(
|
|
(locale) => !pathname.startsWith(`/${locale}/`) && pathname !== `/${locale}`,
|
|
);
|
|
|
|
// If there's no locale in the pathname, detect from headers
|
|
if (pathnameIsMissingLocale) {
|
|
const acceptLanguage = request.headers.get('accept-language');
|
|
|
|
if (acceptLanguage) {
|
|
// Parse accept-language header
|
|
const languages = acceptLanguage.split(',').map((lang) => lang.split(';')[0].trim());
|
|
|
|
// Find the first matching locale
|
|
for (const lang of languages) {
|
|
if (lang.startsWith('zh-TW') || lang.startsWith('zh-HK')) {
|
|
return 'zh-TW';
|
|
} else if (lang.startsWith('zh')) {
|
|
return 'zh-CN';
|
|
} else if (lang.startsWith('ko')) {
|
|
return 'ko';
|
|
} else if (lang.startsWith('ja')) {
|
|
return 'ja';
|
|
} else if (lang.startsWith('en')) {
|
|
return 'en';
|
|
}
|
|
}
|
|
}
|
|
|
|
return defaultLocale;
|
|
}
|
|
|
|
// Extract locale from pathname
|
|
const locale = pathname.split('/')[1];
|
|
return locales.includes(locale) ? locale : defaultLocale;
|
|
}
|
|
|
|
export function middleware(request: NextRequest) {
|
|
const pathname = request.nextUrl.pathname;
|
|
|
|
// Skip middleware for sitemap.xml, robots.txt and other static files
|
|
const staticFiles = ['/sitemap.xml', '/robots.txt', '/favicon.ico', '/manifest.json'];
|
|
if (staticFiles.includes(pathname)) {
|
|
return NextResponse.next();
|
|
}
|
|
|
|
// Check if there is any supported locale in the pathname
|
|
const pathnameIsMissingLocale = locales.every(
|
|
(locale) => !pathname.startsWith(`/${locale}/`) && pathname !== `/${locale}`,
|
|
);
|
|
|
|
// Redirect if there is no locale
|
|
if (pathnameIsMissingLocale) {
|
|
const locale = getLocale(request);
|
|
return NextResponse.redirect(
|
|
new URL(`/${locale}${pathname.startsWith('/') ? '' : '/'}${pathname}`, request.url),
|
|
);
|
|
}
|
|
}
|
|
|
|
export const config = {
|
|
// Matcher ignoring static files, API routes, and special files
|
|
matcher: [
|
|
/*
|
|
* Match all request paths except for the ones starting with:
|
|
* - api (API routes)
|
|
* - _next/static (static files)
|
|
* - _next/image (image optimization files)
|
|
* - favicon.ico, sitemap.xml, robots.txt (static files)
|
|
*/
|
|
'/((?!api|_next/static|_next/image|favicon.ico|sitemap.xml|robots.txt|manifest.json).*)',
|
|
],
|
|
};
|