I tried to implement i18n and i10n in my project, but it didn’t quite work. I want my admin folder out of the [locale] folder, and the rest of my website inside it. I have 2 middlewares that manage the auth (not next auth package), and I want the another middleware for the i18n (i’m using next-intl v. 3.12.2). I’m using MiddlewareFactory in stackHandler that manage all middlewares.
Now, my website loads if I enter any locale after the domain (ex. localhost:300/en). And it doesn’t load if I enter localhost:300; i.e the default doesn’t work. And I don’t want the default locale to be present in the url.
Here’s my code:
middleware.ts:
import { stackMiddlewares } from "@middlewares/stackHandler";
import { adminAuth, userAuth } from "@middlewares/authMiddleware";
import intlMiddleware from "@middlewares/intlMiddleware";
export const config = {
matcher: ["/user/:path*", "/admin/:path*"]
};
const middlewares = [adminAuth, userAuth, intlMiddleware];
export default stackMiddlewares(middlewares);
stackHandler.ts:
import { NextMiddleware, NextResponse } from "next/server";
export type MiddlewareFactory = (middleware: NextMiddleware) => NextMiddleware;
export function stackMiddlewares(functions: MiddlewareFactory[] = [], index = 0): NextMiddleware {
const current = functions[index];
if (current) {
const next = stackMiddlewares(functions, index + 1);
return current(next);
}
return () => NextResponse.next();
};
authMiddlware.ts:
import { NextRequest, NextResponse, NextFetchEvent, NextMiddleware } from "next/server";
import { jwtDecode } from "jwt-decode";
import { WEBSITE_URL } from "@utils/constants";
function getSearchParam(param: string, url: any) {
return url.searchParams.get(param);
};
const adminAuth = (middleware: NextMiddleware) => {
return (request: NextRequest, next: NextFetchEvent) => {
const pathURL = request.url;
if (pathURL.startsWith(`${WEBSITE_URL}/admin`)) {
const token = request.cookies.get("token");
let role = "";
if (!token && pathURL !== `${WEBSITE_URL}/admin/login`) {
return NextResponse.redirect(new URL("/admin/login", request.url));
}
if (token) {
const decoded: any = jwtDecode(token.value);
role = decoded.role;
}
if (role != "admin" && pathURL !== `${WEBSITE_URL}/admin/login`) {
return NextResponse.redirect(`${WEBSITE_URL}/admin/login`);
}
if (pathURL == `${WEBSITE_URL}/admin`) {
return NextResponse.redirect(new URL("/admin/dashboard", request.url));
}
}
return middleware(request, next);
};
};
const userAuth = (middleware: NextMiddleware) => {
return async (request: NextRequest, next: NextFetchEvent) => {
const pathURL = request.url;
if (pathURL.startsWith(`${WEBSITE_URL}/user`)) {
const token = request.cookies.get("token");
let role = "";
if (!token && pathURL !== `${WEBSITE_URL}/user/login`) {
return NextResponse.redirect(new URL("/user/login", request.url));
}
if (token) {
const decoded: any = jwtDecode(token.value);
role = decoded.role;
}
if (role != "user" && pathURL !== `${WEBSITE_URL}/user/login`) {
return NextResponse.redirect(`${WEBSITE_URL}/user/login`);
}
if (pathURL == `${WEBSITE_URL}/user`) {
return NextResponse.redirect(new URL("/user/dashboard", request.url));
}
}
return middleware(request, next);
};
};
export { adminAuth, userAuth };
intlMiddleware.ts:
import { NextRequest, NextResponse, NextFetchEvent, NextMiddleware } from "next/server";
import createIntlMiddleware from "next-intl/middleware";
import { locales } from "../i18n.config";
const intlMiddleware = (middleware: NextMiddleware) => {
return (request: NextRequest, next: NextFetchEvent) => {
// Step 1: Use the incoming request (example)
const defaultLocale = request.headers.get("x-your-custom-locale") || "en";
// Step 2: Create and call the next-intl middleware (example)
const handleI18nRouting = createIntlMiddleware({
// locales: ["en", "ar"],
locales: locales,
// defaultLocale: defaultLocale
defaultLocale: "en"
});
const response = handleI18nRouting(request);
// Step 3: Alter the response (example)
response.headers.set("x-custom-locale", defaultLocale);
return response;
// return middleware(response, next);
};
};
export default intlMiddleware;
// Our middleware only applies to routes that
// match the following:
// export const config = {
// matcher: [
// // Match all pathnames except for
// // - … if they start with `/api`, `/_next` or `/_vercel`
// // - … the ones containing a dot (e.g. `favicon.ico`)
// "/((?!api|_next|_vercel|.*\..*).*)"
// ]
// };
Can someone tell me what’s wrong in my code?
And I had an error when I tried to pass the response to middleware(response, next); because it only accepts requests not responses. Is there a way to fix this?
Thanks in advance…