❯ npx create-next-app@latest ✔ What is your project named? … `next-i18n-demo` ✔ Would you like to use TypeScript? … No / `Yes` ✔ Would you like to use ESLint? … No / `Yes` ✔ Would you like to use Tailwind CSS? … No / `Yes ✔ Would you like to use `src/` directory? … No / `Yes` ✔ Would you like to use App Router? (recommended) … No / `Yes` ✔ Would you like to customize the default import alias (@/*)? … `No` / Yes
{ "page":{ "title":"Next.js i18n Demo", "desc":"How to implement i18n with Next.js (based on App Router)" }, "home":{ "title":"Hello, Next.js i18n", "desc":"This is a demo of Next.js i18n" } }
let locales = ["en", "zh"]; let defaultLocale = "en";
// Get the preferred locale, similar to the above or using a library functiongetLocale(request: NextRequest) { return defaultLocale; }
exportfunctionmiddleware(request: NextRequest) { // Check if there is any supported locale in the pathname const { pathname } = request.nextUrl; const pathnameHasLocale = locales.some( (locale) => pathname.startsWith(`/${locale}/`) || pathname === `/${locale}` );
if (pathnameHasLocale) return;
// Redirect if there is no locale const locale = getLocale(request); request.nextUrl.pathname = `/${locale}${pathname}`; // e.g. incoming request is /products // The new URL is now /en-US/products returnNextResponse.redirect(request.nextUrl); }
exportconst config = { matcher: [ // Skip all internal paths (_next) "/((?!_next).*)", // Optional: only run on root (/) URL // '/' ], };
// Get the preferred locale, similar to the above or using a library functiongetLocale(request: NextRequest): string { // Get locale from cookie if (request.cookies.has(cookieName)) return request.cookies.get(cookieName)!.value; // Get accept language from HTTP headers const acceptLang = request.headers.get("Accept-Language"); if (!acceptLang) return defaultLocale; // Get match locale const headers = { "accept-language": acceptLang }; const languages = newNegotiator({ headers }).languages(); returnmatch(languages, locales, defaultLocale); }
exportfunctionmiddleware(request: NextRequest) { if (request.nextUrl.pathname.startsWith("/_next")) returnNextResponse.next();
// Check if there is any supported locale in the pathname const { pathname } = request.nextUrl; const pathnameHasLocale = locales.some( (locale) => pathname.startsWith(`/${locale}/`) || pathname === `/${locale}` );
if (pathnameHasLocale) return;
// Redirect if there is no locale const locale = getLocale(request); request.nextUrl.pathname = `/${locale}${pathname}`; // e.g. incoming request is /products // The new URL is now /en-US/products const response = NextResponse.redirect(request.nextUrl); // Set locale to cookie response.cookies.set(cookieName, locale); return response; }
exportconst config = { matcher: [ // Skip all internal paths (_next) "/((?!_next).*)", // Optional: only run on root (/) URL // '/' ], };