skip to Main Content

I’m currently utilizing Next.js (v13.5.4) and next-intl (v3.0.0-beta.19) for internationalization. My goal is to modify the URL structure for locales from a format like en-GB to en/UK.

I’ve set up Next with the app router and initialized next-intl following the server component guide.

Here’s my attempt to set up URL rewrites in next.config.js:


/** @type {import('next').NextConfig} */
const nextConfig = {
    async rewrites() {
        return {
            beforeFiles: [
                {
                    source: "/en/uk/:path*",
                    destination: "/en-GB/:path*",
                }
            ]
        }
    },
}

module.exports = withNextIntl(nextConfig);

With this config, navigating to http://localhost:3000/en-GB functions as expected. However, accessing http://localhost:3000/en/uk redirects to http://localhost:3000/en-GB/en/uk (where en-GB is the last locale I accessed).

For further context, this is my middleware:

import createMiddleware from 'next-intl/middleware';

export default createMiddleware({
    locales: ['de-DE', 'en-GB'],
    defaultLocale: ''
});

export const config = {
    matcher: ['/((?!api|_next|_vercel|.*\..*).*)']
};

Attempts at Resolving:

  • Removed the beforeFiles segment from the rewrite configuration.
  • Incorporated locale: false in my config.
  • Adjusted the matcher in the middleware to matcher: ['/((?!api|en/uk|_next|_vercel|.*\..*).*)'], which resulted in the error: Error: Unable to find next-intl locale, have you configured the middleware.

Any insights, alternative solutions, or suggestions would be immensely appreciated.

2

Answers


  1. Chosen as BEST ANSWER

    Seems like I was on the right track but was just missing this part from my middleware:

    export function middleware(request: NextRequest) {
        return NextResponse.next();
    }
    

    Here is the final result to get the URL rewrite to work:

    src/middleware.ts

    import createMiddleware from 'next-intl/middleware';
    import { NextResponse } from 'next/server'
    import type { NextRequest } from 'next/server'
    
    export function middleware(request: NextRequest) {
        return NextResponse.next();
    }
    
    export default createMiddleware({
        locales: ['de-DE', 'en-GB'],
        defaultLocale: ''
    });
    
    export const config = {
        // Skip all paths that should not be internationalized.
        matcher: ['/((?!api|_next|_vercel|.*\..*).*)']
    };
    

    next.config.js

    /** @type {import('next').NextConfig} */
    const nextConfig = {
        async rewrites() {
            return [
                {
                    source: '/en/uk/:path*',
                    destination: '/en-GB/:path*',
                },
                {
                    source: '/de/de/:path*',
                    destination: '/de-DE/:path*',
                }
            ]
    
        },
    }
    
    module.exports = nextConfig
    

    the beforeFiles in the rewrite config was not needed so I removed it.


  2. My previous answer only works for client components. To get it to work with server components, you need to to do the url rewrite in the middleware. This is because next.js prioritises redirects and rewrites in the middleware over the rewrites in the config. Here is my middleware in the end:

    import createIntlMiddleware from 'next-intl/middleware';
    import { NextRequest } from 'next/server';
    
    export function middleware(request: NextRequest) {
        const localeMapping = {
            'en/uk': 'en-GB',
            'de/de': 'de-DE',
        };
        let modifiedRequest = request;
    
        // URL Rewrites
        for (const [srcPath, targetPath] of Object.entries(localeMapping)) {
            if (request.nextUrl.pathname.startsWith(`/${srcPath}`)) {
                const remainingPath = request.nextUrl.pathname.replace(`/${srcPath}`, '');
                const newUrl = new URL(`/${targetPath}${remainingPath}`, request.url);
                modifiedRequest = new NextRequest(newUrl, request);
                break;
            }
        }
    
        const locales = Object.values(localeMapping);
    
        // Translations middleware logic
        const defaultLocale = modifiedRequest.headers.get('x-default-locale') || 'en-GB';
        const handleI18nRouting = createIntlMiddleware({
            locales,
            defaultLocale
        });
    
        const response = handleI18nRouting(modifiedRequest);
        response.headers.set('x-default-locale', defaultLocale);
    
        return response;
    }
    
    export const config = {
        // Skip all paths that should not be internationalized.
        matcher: ['/((?!api|_next|_vercel|.*\..*).*)']
    };
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search