deploy
This commit is contained in:
124
frontend/middleware.js
Normal file
124
frontend/middleware.js
Normal file
@@ -0,0 +1,124 @@
|
||||
import { NextResponse } from "next/server";
|
||||
|
||||
const LOCALE_COOKIE = "rs_locale";
|
||||
const SUPPORTED_LOCALES = new Set(["en", "pt"]);
|
||||
const PUBLIC_FILE = /\.(?:ico|png|jpg|jpeg|svg|webp|avif|gif|txt|xml|json|webmanifest|css|js|map|woff2?)$/i;
|
||||
const RESERVED_PREFIXES = [
|
||||
"/_next",
|
||||
"/_a2a",
|
||||
"/.well-known",
|
||||
"/api",
|
||||
"/auth",
|
||||
"/invoke",
|
||||
"/mcp",
|
||||
"/message:send",
|
||||
"/message:stream",
|
||||
"/tasks",
|
||||
"/answers",
|
||||
"/input-requests",
|
||||
"/scope-grants",
|
||||
"/scope-denials",
|
||||
];
|
||||
|
||||
function isReservedPath(pathname) {
|
||||
if (PUBLIC_FILE.test(pathname)) {
|
||||
return true;
|
||||
}
|
||||
return RESERVED_PREFIXES.some(
|
||||
(prefix) => pathname === prefix || pathname.startsWith(`${prefix}/`),
|
||||
);
|
||||
}
|
||||
|
||||
function normalizeLocale(value) {
|
||||
const locale = String(value || "").trim().toLowerCase();
|
||||
if (SUPPORTED_LOCALES.has(locale)) {
|
||||
return locale;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function localeFromCountry(request) {
|
||||
const country = (
|
||||
request.headers.get("x-vercel-ip-country")
|
||||
|| request.headers.get("cf-ipcountry")
|
||||
|| request.headers.get("x-country-code")
|
||||
|| ""
|
||||
).trim().toUpperCase();
|
||||
if (country === "BR" || country === "PT") {
|
||||
return "pt";
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function localeFromAcceptLanguage(request) {
|
||||
const header = request.headers.get("accept-language") || "";
|
||||
const ranked = header
|
||||
.split(",")
|
||||
.map((part) => {
|
||||
const [tag, ...params] = part.trim().split(";");
|
||||
const q = params
|
||||
.map((param) => param.trim())
|
||||
.find((param) => param.startsWith("q="));
|
||||
const weight = q ? Number.parseFloat(q.slice(2)) : 1;
|
||||
return {
|
||||
language: tag.toLowerCase().split("-")[0],
|
||||
weight: Number.isFinite(weight) ? weight : 1,
|
||||
};
|
||||
})
|
||||
.filter((item) => SUPPORTED_LOCALES.has(item.language))
|
||||
.sort((a, b) => b.weight - a.weight);
|
||||
return ranked[0]?.language || null;
|
||||
}
|
||||
|
||||
function preferredLocale(request) {
|
||||
return (
|
||||
normalizeLocale(request.cookies.get(LOCALE_COOKIE)?.value)
|
||||
|| localeFromAcceptLanguage(request)
|
||||
|| localeFromCountry(request)
|
||||
|| "en"
|
||||
);
|
||||
}
|
||||
|
||||
function withLocaleCookie(response, locale) {
|
||||
response.cookies.set(LOCALE_COOKIE, locale, {
|
||||
path: "/",
|
||||
maxAge: 60 * 60 * 24 * 365,
|
||||
sameSite: "lax",
|
||||
});
|
||||
return response;
|
||||
}
|
||||
|
||||
export function middleware(request) {
|
||||
const url = request.nextUrl;
|
||||
const { pathname, searchParams } = url;
|
||||
|
||||
if (isReservedPath(pathname)) {
|
||||
return NextResponse.next();
|
||||
}
|
||||
|
||||
const requestedLocale = normalizeLocale(searchParams.get("lang"));
|
||||
if (requestedLocale) {
|
||||
const cleanUrl = url.clone();
|
||||
cleanUrl.searchParams.delete("lang");
|
||||
const response =
|
||||
cleanUrl.toString() === url.toString()
|
||||
? NextResponse.next()
|
||||
: NextResponse.redirect(cleanUrl);
|
||||
return withLocaleCookie(response, requestedLocale);
|
||||
}
|
||||
|
||||
if (pathname === "/") {
|
||||
const locale = preferredLocale(request);
|
||||
if (locale === "pt") {
|
||||
const redirectUrl = url.clone();
|
||||
redirectUrl.pathname = "/pt/";
|
||||
return NextResponse.redirect(redirectUrl);
|
||||
}
|
||||
}
|
||||
|
||||
return NextResponse.next();
|
||||
}
|
||||
|
||||
export const config = {
|
||||
matcher: ["/:path*"],
|
||||
};
|
||||
Reference in New Issue
Block a user