-
-
Notifications
You must be signed in to change notification settings - Fork 562
Expand file tree
/
Copy pathproxy.ts
More file actions
107 lines (85 loc) · 3.17 KB
/
proxy.ts
File metadata and controls
107 lines (85 loc) · 3.17 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
// middleware.ts
import { createI18nMiddleware } from "next-international/middleware";
import { NextRequest, NextResponse } from "next/server";
import { getSessionCookie } from "better-auth/cookies";
function detectUserLocale(request: NextRequest): string {
const acceptLanguage = request.headers.get("accept-language");
if (!acceptLanguage) return "en";
// Parse Accept-Language header
const languages = acceptLanguage
.split(",")
.map((lang) => {
const [locale, quality = "1"] = lang.trim().split(";q=");
return { locale: locale.toLowerCase(), quality: parseFloat(quality) };
})
.sort((a, b) => b.quality - a.quality);
// Map browser locales to supported locales
const supportedLocales = ["en", "fr", "es", "zh-cn", "ru", "pt"];
for (const { locale } of languages) {
// Exact match
if (supportedLocales.includes(locale)) {
return locale === "zh-cn" ? "zh-CN" : locale;
}
// Language match (fr-FR -> fr)
const lang = locale.split("-")[0];
if (supportedLocales.includes(lang)) {
return lang;
}
// Chinese variants
if (locale.startsWith("zh")) {
return "zh-CN";
}
}
return "en"; // fallback
}
const I18nMiddleware = createI18nMiddleware({
locales: ["en", "fr", "es", "zh-CN", "ru", "pt"],
defaultLocale: "en",
urlMappingStrategy: "rewrite",
});
export async function proxy(request: NextRequest) {
const pathname = request.nextUrl.pathname;
const detectedLocale = detectUserLocale(request);
// If on root path and no locale detected yet, redirect to detected locale
if (pathname === "/" && !request.cookies.get("detected-locale")) {
const url = new URL(`/${detectedLocale}`, request.url);
const response = NextResponse.redirect(url);
response.cookies.set("detected-locale", detectedLocale, {
maxAge: 60 * 60 * 24 * 365, // 1 year
httpOnly: false,
secure: process.env.NODE_ENV === "production",
sameSite: "lax",
});
return response;
}
// Normal i18n middleware processing
const response = I18nMiddleware(request);
// Extract current locale from pathname
const localeMatch = pathname.match(/^\/([a-z]{2}(?:-[A-Z]{2})?)/);
const currentLocale = localeMatch ? localeMatch[1] : detectedLocale;
// Set Content-Language header for SEO
response.headers.set("Content-Language", currentLocale);
// Store detected locale in cookie for future visits
if (!request.cookies.get("detected-locale")) {
response.cookies.set("detected-locale", detectedLocale, {
maxAge: 60 * 60 * 24 * 365, // 1 year
httpOnly: false,
secure: process.env.NODE_ENV === "production",
sameSite: "lax",
});
}
const searchParams = request.nextUrl.searchParams.toString();
response.headers.set("searchParams", searchParams);
if (request.nextUrl.pathname.includes("/dashboard")) {
const session = getSessionCookie(request);
if (!session) {
return NextResponse.redirect(new URL("/", request.url));
}
}
return response;
}
export const config = {
matcher: [
"/((?!api|static|_next|manifest.json|favicon.ico|robots.txt|sw.js|apple-touch-icon.png|android-chrome-.*\\.png|images|logo|icons|sitemap.xml|ads.txt).*)",
],
};