if the ip address of the user entering the site is blocked, I want to redirect to a different page such as /blocked and not access the site. I wanted to create a fetch request on my middleware and run other codes according to the result, but next-intl gave the error “Unable to find next-intl locale because the middleware didn't run on this request.”
what do I need to do to control banned users via api? waiting for your advice
import createMiddleware from 'next-intl/middleware';
import { defaultLocale, locales, pathnames } from "./config/lang-config";
import withAuth from 'next-auth/middleware';
import { NextRequest, NextResponse } from 'next/server';
import { getProfile } from './services/authQueries';
const privatePages = [
'/profile',
'/settings',
'/settings/*',
'/wallet',
'/wallet/*',
'/auth/logout',
];
const intlMiddleware = createMiddleware({
defaultLocale,
locales,
localePrefix: "as-needed",
pathnames,
localeDetection: true,
});
const authMiddleware = withAuth(
// Note that this callback is only invoked if
// the `authorized` callback has returned `true`
// and not for pages listed in `pages`.
function onSuccess(req) {
return intlMiddleware(req);
},
{
callbacks: {
authorized: async ({ token }: { token: any }) => {
const accessToken = token?.tokenData?.token || token?.token as string;
if (token) {
try {
const res = await getProfile(accessToken as string, 'en');
if (res.isSucceed) {
token.user = res.data;
return true;
} else {
throw new Error(res.message);
}
} catch (error) {
if (error instanceof Error) {
console.error(error.message);
} else {
console.error('An unknown error occurred');
}
return false;
}
} else {
return false;
}
},
},
pages: {
signIn: '/',
}
}
);
const env = process.env.NODE_ENV;
const blockedCountries = ['US', 'UK'];
export default function middleware(req: NextRequest) {
const res = NextResponse.next()
const pathname = req.nextUrl.pathname
// Skip this middleware in development or if the path is international
if (env !== 'development' && pathname !== '/blocked') {
const country = req.geo?.country || req.headers.get('cloudfront-viewer-country') || req.headers.get('x-vercel-ip-country');
if (blockedCountries.includes(country ?? '')) {
return NextResponse.redirect(new URL('/blocked', req.url))
}
}
const privatePathnameRegex = RegExp(
`^(/(${locales.join('|')}))?(${privatePages
.flatMap((p) => {
// for '*'
return p.replace(/\*/g, '.*');
})
.map((p) => (p === '/' ? ['', '/'] : p))
.join('|')})/?$`,
'i'
);
const isPrivatePage = privatePathnameRegex.test(req.nextUrl.pathname);
if (!isPrivatePage) {
const country = req.geo?.country || req.headers.get('cloudfront-viewer-country') || req.headers.get('x-vercel-ip-country');
const response = intlMiddleware(req);
response.cookies.set("client-counry", country || '');
return response;
} else {
return (authMiddleware as any)(req);
}
}
export const config = {
matcher: [
// Enable a redirect to a matching locale at the root
'/',
// Set a cookie to remember the previous locale for
// all requests that have a locale prefix
'/(en-US)/:path*',
// Enable redirects that add missing locales
// (e.g. `/pathnames` -> `/en/pathnames`)
'/((?!api|_next|_vercel|.*\\..*).*)'
]
};
I sent an API request on Middleware and redirected the user with NextResponse according to the incoming data, but I got the following error "Unable to find next-intl locale because the middleware didn't run on this request."
The error "Unable to find next-intl locale because the middleware didn't run on this request" occurs because Next.js middleware runs on the edge, and next-intl expects the middleware to be applied consistently to determine the locale for each request. This can be tricky when combining redirection, locale detection, and user authorization within a middleware file.
To handle blocked users with next-intl and authentication while avoiding this error, you can refactor the middleware to manage country-based redirects separately from locale-based processing. Here’s how to do this:
Step 1: Separate Blocked User Logic from next-intl Middleware
First, we’ll move the blocked user check to the top of the middleware. This way, it executes before next-intl tries to detect the locale or apply its configurations.
Step 2: Ensure intlMiddleware Runs Consistently
The intlMiddleware should be the only function responsible for handling localization. This approach makes sure it’s applied consistently to every request, resolving the locale-related error.
import createMiddleware from 'next-intl/middleware';
import { defaultLocale, locales, pathnames } from "./config/lang-config";
import withAuth from 'next-auth/middleware';
import { NextRequest, NextResponse } from 'next/server';
import { getProfile } from './services/authQueries';
const privatePages = [
'/profile',
'/settings',
'/settings/*',
'/wallet',
'/wallet/*',
'/auth/logout',
];
const intlMiddleware = createMiddleware({
defaultLocale,
locales,
localePrefix: "as-needed",
pathnames,
localeDetection: true,
});
const authMiddleware = withAuth(
function onSuccess(req) {
return intlMiddleware(req);
},
{
callbacks: {
authorized: async ({ token }: { token: any }) => {
const accessToken = token?.tokenData?.token || token?.token as string;
if (token) {
try {
const res = await getProfile(accessToken, 'en');
if (res.isSucceed) {
token.user = res.data;
return true;
} else {
throw new Error(res.message);
}
} catch (error) {
console.error(error instanceof Error ? error.message : 'An unknown error occurred');
return false;
}
}
return false;
},
},
pages: {
signIn: '/',
}
}
);
const env = process.env.NODE_ENV;
const blockedCountries = ['US', 'UK'];
export default async function middleware(req: NextRequest) {
// Blocked user check
const country = req.geo?.country || req.headers.get('cloudfront-viewer-country') || req.headers.get('x-vercel-ip-country');
if (env !== 'development' && blockedCountries.includes(country ?? '')) {
return NextResponse.redirect(new URL('/blocked', req.url));
}
const pathname = req.nextUrl.pathname;
const privatePathnameRegex = new RegExp(
`^(/(${locales.join('|')}))?(${privatePages
.map((p) => p.replace(/\*/g, '.*'))
.join('|')})/?$`,
'i'
);
// Apply auth middleware on private pages
if (privatePathnameRegex.test(pathname)) {
return authMiddleware(req);
}
// Apply intlMiddleware on public pages and set country cookie
const response = intlMiddleware(req);
response.cookies.set("client-country", country || '');
return response;
}
export const config = {
matcher: [
'/',
'/(en-US)/:path*',
'/((?!api|_next|_vercel|.*\\..*).*)'
]
};
Blocked User Check: Placed at the very beginning to ensure redirection for blocked countries before intlMiddleware runs.
Private Page Auth Check: We match private pages with authMiddleware while leaving other routes to intlMiddleware to handle localization. Consistent Locale Handling: By structuring the middleware like this, intlMiddleware always runs on non-private pages, avoiding the locale detection error.
This setup should redirect blocked users to /blocked, handle authentication on private pages, and apply consistent locale detection and response processing on public pages.