CloudProxy/middleware.ts

82 lines
2.9 KiB
TypeScript
Raw Normal View History

2025-09-15 18:30:09 +08:00
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).*)',
],
};