65 lines
1.8 KiB
TypeScript
65 lines
1.8 KiB
TypeScript
import { NextResponse } from "next/server";
|
|
import type { NextRequest } from "next/server";
|
|
import { i18n } from "./i18n-config";
|
|
|
|
function getLocale(request: NextRequest): string {
|
|
const acceptLanguage = request.headers.get("accept-language");
|
|
if (!acceptLanguage) return i18n.defaultLocale;
|
|
|
|
// Simple and ultra-robust parsing for accept-language header
|
|
const preferredLocales = acceptLanguage
|
|
.split(",")
|
|
.map((lang) => {
|
|
const [locale, q] = lang.split(";q=");
|
|
return {
|
|
locale: locale.trim().split("-")[0].toLowerCase(), // e.g. "tr", "en"
|
|
priority: q ? parseFloat(q) : 1.0,
|
|
};
|
|
})
|
|
.sort((a, b) => b.priority - a.priority);
|
|
|
|
for (const pref of preferredLocales) {
|
|
if (i18n.locales.includes(pref.locale as any)) {
|
|
return pref.locale;
|
|
}
|
|
}
|
|
|
|
return i18n.defaultLocale;
|
|
}
|
|
|
|
export function proxy(request: NextRequest) {
|
|
const pathname = request.nextUrl.pathname;
|
|
|
|
// Skip static assets, internal paths, and favicon
|
|
if (
|
|
pathname.startsWith("/_next") ||
|
|
pathname.startsWith("/api") ||
|
|
pathname.startsWith("/favicon.ico") ||
|
|
pathname.match(/\.(png|jpg|jpeg|gif|svg|webp|ico|css|js|woff|woff2|ttf|otf|json|xml|txt)$/)
|
|
) {
|
|
return;
|
|
}
|
|
|
|
// Check if pathname already contains a supported locale prefix
|
|
const pathnameIsMissingLocale = i18n.locales.every(
|
|
(locale) => !pathname.startsWith(`/${locale}/`) && pathname !== `/${locale}`
|
|
);
|
|
|
|
if (pathnameIsMissingLocale) {
|
|
const locale = getLocale(request);
|
|
|
|
// Redirect /xxx to /locale/xxx
|
|
return NextResponse.redirect(
|
|
new URL(
|
|
`/${locale}${pathname.startsWith("/") ? "" : "/"}${pathname}`,
|
|
request.url
|
|
)
|
|
);
|
|
}
|
|
}
|
|
|
|
export const config = {
|
|
// Matcher ignoring static items and api routes
|
|
matcher: ["/((?!api|_next/static|_next/image|favicon.ico).*)"],
|
|
};
|