Help needed setting up i18n router with next-intl

I have used this tutorial here in order to setup internationalization with Prismic GitHub - prismicio-community/nextjs-starter-prismic-multi-language: Multi-language project with Next.js & Prismic

Most of the things work fine, but when following the tutorial here for setting up next-intl with i18n routing it fails specifically at the createMiddleware part. My guess is that it's happening because of the fact that I am trying to mix the config.matcher part.

This is how the middleware looks now:

// ./src/middleware.ts

import { NextRequest, NextResponse } from 'next/server';
import { createClient } from '@/prismicio';
import createMiddleware from 'next-intl/middleware';

export default createMiddleware({
    // A list of all locales that are supported
    locales: ['en', 'ro'],

    // Used when no locale matches
    defaultLocale: 'ro'
});

export async function middleware(request: NextRequest) {
    const client = createClient();
    const repository = await client.getRepository();

    const locales = repository.languages.map((lang) => lang.id);
    const defaultLocale = locales[0];

    // Check if there is any supported locale in the pathname
    const { pathname } = request.nextUrl;

    const pathnameIsMissingLocale = locales.every(
        (locale) => !pathname.startsWith(`/${locale}/`) && pathname !== `/${locale}`
    );

    // Redirect to default locale if there is no supported locale prefix
    if (pathnameIsMissingLocale) {
        return NextResponse.rewrite(
            new URL(`/${defaultLocale}${pathname}`, request.url)
        );
    }
}

export const config = {
    matcher: [
        /*
        * Match all request paths except for the ones starting with:
        * - api (API routes)
        * - _next/static (static files)
        * - _next/image (image optimization files)
        * - images directory in /public (public static images)
        */
        '/((?!api|_next/static|_next/image|images).*)',
    ],
};

The error I am getting is the following:

lang ro

Unable to find `next-intl` locale because the middleware didn't run on this request. See https://next-intl-docs.vercel.app/docs/routing/middleware#unable-to-find-locale. The `notFound()` function will be called as a result.

 GET / 404 in 57ms

What I am trying to achieve is the following:
default lang "ro" should be reachable without any "path". While any other languages like "en-us" should be reachable with the language path.

In prismic my locales are set under "ro" and "en-us".

I would appreciate any help or suggestion

Hi @tudor2004 ,

Thank you for reaching out. Here are some suggestions and insights that might help you resolve the issue with your middleware setup for internationalization:

Key Points from the Knowledge Base:

  1. Locale Detection and Redirection:

    • When using Sub-path Routing, the user would be redirected to /fr if the locale is detected as fr.
    • When using Domain Routing, the user would be redirected to example.fr if the domain handles the fr locale by default.
    • The default locale does not have a prefix.
  2. Middleware Configuration:

    • The middleware should check if there is any supported locale in the pathname and redirect to the default locale if there is no supported locale prefix.
    • Ensure all special files inside the app are nested under app/[lang].

Suggestions for Your Middleware:

  1. Combining Middleware Functions:

    • It seems you are trying to combine the createMiddleware from next-intl with your custom middleware logic. Ensure that both middleware functions are compatible and do not conflict with each other.
  2. Default Locale Handling:

    • Ensure that the default locale (ro) is correctly handled without a path prefix, while other locales like en should have the language path.

Example Middleware Configuration:

Here is an example of how you might configure your middleware to achieve the desired behavior:

// ./src/middleware.ts

import { NextRequest, NextResponse } from 'next/server';
import { createClient } from '@/prismicio';
import createMiddleware from 'next-intl/middleware';

const intlMiddleware = createMiddleware({
    // A list of all locales that are supported
    locales: ['en', 'ro'],

    // Used when no locale matches
    defaultLocale: 'ro'
});

export async function middleware(request: NextRequest) {
    const client = createClient();
    const repository = await client.getRepository();

    const locales = repository.languages.map((lang) => lang.id);
    const defaultLocale = locales[0];

    // Check if there is any supported locale in the pathname
    const { pathname } = request.nextUrl;

    const pathnameIsMissingLocale = locales.every(
        (locale) => !pathname.startsWith(`/${locale}/`) && pathname !== `/${locale}`
    );

    // Redirect to default locale if there is no supported locale prefix
    if (pathnameIsMissingLocale) {
        return NextResponse.rewrite(
            new URL(`/${defaultLocale}${pathname}`, request.url)
        );
    }

    // Run the next-intl middleware
    return intlMiddleware(request);
}

export const config = {
    matcher: [
        /*
        * Match all request paths except for the ones starting with:
        * - api (API routes)
        * - _next/static (static files)
        * - _next/image (image optimization files)
        * - images directory in /public (public static images)
        */
        '/((?!api|_next/static|_next/image|images).*)',
    ],
};

Key Changes:

  • Combining Middleware: The custom middleware logic is combined with the next-intl middleware by calling intlMiddleware(request) at the end of the custom middleware function.
  • Default Locale Handling: The default locale (ro) is handled without a path prefix, while other locales like en are prefixed.

Additional Resources:

If you continue to face issues, please provide more details about the specific error messages or behavior you are encountering, and I will be happy to assist further.

Hi @Phil thanks a lot for your reply!

It's still somewhat working :) but not like I'm expecting.

Some things first:

  1. My goal is to have the default language "ro". But for the default language I don't want the lang in the URL. Example URL: mywebsite.com - This website is for sale! - mywebsite Resources and Information. and mywebsite.com - This website is for sale! - mywebsite Resources and Information. (or at least en-us/hellp)
  2. My Prismic locales are set with "ro" and "en-us"
  3. Loading mywebsite.com/ro/ works ok and also mywebsite.com/en/ but... (read below)
  4. When accessing mywebsite.com/en/hello and calling await getLocale() from next-intl/server I expect it to return en (or en-us), but it currently returns still ro
  5. Like said above, I would like mywebsite.com/ro/ to be called simply without the ro part as that is the default locale.

This is how my next.config.mjs file looks like:

import { createClient } from '@prismicio/client';
import createNextIntlPlugin from 'next-intl/plugin';
import sm from './slicemachine.config.json' assert { type: "json" };

const withNextIntl = createNextIntlPlugin();

const client = createClient(sm.repositoryName);

const repository = await client.getRepository();
const locales = repository.languages.map((lang) => lang.id);

console.log("locales", locales);

/** @type {import('next').NextConfig} */
const nextConfig = {
    trailingSlash: true,
};

export default withNextIntl(nextConfig);

Here is also a screenshot of my file config:

LATER EDIT: I have also tried with adding the localePrefix: 'as-needed' to the createMiddleware function... still doesn't work.

My teammate took a deep dive into next-intl and got everything working. They believe it behaves as the you want:

  • The default locale is not in the URL.
  • getLocale() works.
  • Prismic links work.
  • They uploaded an example repo that the user can use as a reference: prismic-next-intl-example. This is not an official example and may have bugs.

The example is set up for en-us and fr-fr locales. It maps en-us to the root URL and fr-fr to /fr.

Here are some important parts they highlighted for configuration:

  • Turn off localeDetection and alternateLinks in middleware.ts. localeDetection must be turned off if the default locale is not in the URL to avoid a redirect to another locale.
  • Update the middleware.ts matcher to include all routes.
  • Use a function to convert the URL's locale to Prismic's locale. This is necessary for URL locales that may not match a Prismic locale, such as en. Example functions are located in src/i18n/routing.ts.
  • Set up @prismicio/client routes using hard-coded URL overrides in prismicio.ts. This is needed to change locales from one form to another (e.g., en-us to en).