#Middleware for Internationalization

1 messages · Page 1 of 1 (latest)

willow notch
#

This is my folder structure and i have middleware
// Purpose: Adding locale and Redirect user to the correct locale based on the accept-language header

import { NextResponse } from "next/server";
import { match } from "@formatjs/intl-localematcher";
import Negotiator from "negotiator";

// Supported locales and default locale
let locales = ["en-US", "en-GB", "en-NZ", "en-AU", "en-CA", "fr-CA"];
let defaultLocale = "en-US";

function getLocale(request) {
let headers = { "accept-language": request.headers.get("accept-language") };
const negotiator = new Negotiator({ headers });
const languages = negotiator.languages();

// if header is not present, return default locale (en-US) and if headers give no match, return default locale
return languages.length > 0
? match(languages, locales, defaultLocale)
: defaultLocale;
}

// Middleware function to add locale to the pathname
// If the pathname already has locale, and it is supported, do nothing and return
// Else, add the default locale to the pathname and redirect the user to the correct locale
export function middleware(request) {
const { pathname } = request.nextUrl;

const pathnameHasLocale = locales.some(
(locale) => pathname.startsWith(/${locale}/) || pathname === /${locale},
);
if (pathnameHasLocale) return;

const locale = getLocale(request);
request.nextUrl.pathname = /${locale}${pathname};

return NextResponse.redirect(request.nextUrl);
}

export const config = {
matcher: ["/((?!_next|sitemap|favicon).*)"],
};

like this but problem is when i direclty hit localhost:3000
its showing me 404

shy oracleBOT
#

Hi @willow notch. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave:

#

I can see you're having an issue with your internationalization middleware in Next.js where directly accessing localhost:3000 results in a 404 error.

The problem appears to be related to how your middleware is handling the redirect. Based on the knowledge sources, there are a few potential issues:

  1. The Negotiator library might not be correctly processing the NextRequest object. As mentioned in Docs: Internationalization middleware.js example does not work, the Negotiator library may not properly recognize the NextRequest object that middleware passes.

  2. Your matcher pattern might be causing issues with how routes are processed.

Here's a solution you can try:

import { NextResponse } from "next/server";
import { match } from "@formatjs/intl-localematcher";
import Negotiator from "negotiator";

let locales = ["en-US", "en-GB", "en-NZ", "en-AU", "en-CA", "fr-CA"];
let defaultLocale = "en-US";

function getLocale(request) {
  // Negotiator expects plain object so we need to transform headers
  const negotiatorHeaders = {};
  request.headers.forEach((value, key) => (negotiatorHeaders[key] = value));

  const languages = new Negotiator({ headers: negotiatorHeaders }).languages(
    locales,
  );

  return languages.length > 0
    ? match(languages, locales, defaultLocale)
    : defaultLocale;
}

export function middleware(request) {
  const { pathname } = request.nextUrl;

  const pathnameHasLocale = locales.some(
    (locale) => pathname.startsWith(`/${locale}/`) || pathname === `/${locale}`
  );
  
  if (pathnameHasLocale) return;

  const locale = getLocale(request);
  request.nextUrl.pathname = `/${locale}${pathname}`;

  return NextResponse.redirect(request.nextUrl);
}

export const config = {
  matcher: ['/((?!api|_next/static|_next/image|favicon.ico).*)'],
};
#

The key changes are:

  1. Transform the headers into a plain object that Negotiator can understand
  2. Updated the matcher pattern to better exclude Next.js system paths

This approach is based on the solution mentioned in the GitHub issue where a user suggested transforming the headers for Negotiator to work properly with Next.js middleware.

If you're still experiencing issues, you might want to try an alternative approach as suggested in this GitHub comment, where using a more specific matcher pattern helped resolve similar issues:

export const config = { 
  matcher: ['/((?!api|_next/static|_next/image|favicon.ico).*)'], 
};

Make sure your app directory structure follows the recommended pattern with your pages nested under app/[lang] to enable the Next.js router to handle different locales properly.

Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: