DEV Community

Cover image for How to Combine English Folders with Polish Paths in Next.js (Rewrites, Redirects, and Middleware)
Marek Gacek
Marek Gacek

Posted on • Originally published at blog.marekgacekdev.pl

How to Combine English Folders with Polish Paths in Next.js (Rewrites, Redirects, and Middleware)

Any other language in programming than English looks very weird

A function named powiekszPierwszaLitere or a folder called o-nas will hurt my eyes. But very often, I make websites for my Poland brotherhood, and of course, content is better in the local language.

In Next.js, folder names are also the path names. The easiest way is to name the folder exactly how the root should look, but as we said earlier, it’s terrible. In this tutorial, I’ll show you how to do this in an easy way that’s also good for SEO. Let’s go!


Rewrites

Next.js provides us with a function called Rewrites(). As the name suggests, it maps one URL address to another. In our case, it translates Polish URLs into English.

For example, the function returns an array with two objects, each containing two keys.

  • The first key is source – this is the URL the user sees in the browser.
// next.config.ts

/** @type {import('next').NextConfig} */
const nextConfig = {
    async rewrites() {
        return [
            {
                source: '/galeria',
                destination: '/gallery',
            },
            {
                source: '/kontakt',
                destination: '/contact',
            },
        ]
    },

}

export default nextConfig
Enter fullscreen mode Exit fullscreen mode

It sounds good, but we have a little problem. We now have two routes, two paths for the same page. We want to use only /kontakt, but we end up with both /kontakt and /contact. That’s not a good idea. But maybe we could redirect the English path to the Polish one, and everything will be great?


Redirects

Next.js gives us another function called Redirects(). This function, as expected, redirects from one path to another. These two functions are very similar, but there’s a key difference:

  • Rewrites() changes the URL that the user sees in the browser, while
  • Redirects() simply... redirects.

For example, Redirects() returns an array of objects, but this time with three keys:

  • The first key, source, is the URL the user sees in the browser.
  • The second key, destination, is the URL where Next.js will redirect the request.
  • The third key, permanent, is a boolean. If we want a 301 (permanent redirect), we set it to true. For a 307 (temporary redirect), we set it to false.

Looks good – maybe, in combination, these two functions will give us the desired outcome.

// next.config.ts

/** @type {import('next').NextConfig} */
const nextConfig = {
    async rewrites() {
        return [
            {
                source: '/galeria',
                destination: '/gallery',
            },
            {
                source: '/kontakt',
                destination: '/contact',
            },
        ]
    },

    async redirects() {
        return [
            {
                source: '/gallery',
                destination: '/galeria',
                permanent: true,
            },
            {
                source: '/kontakt',
                destination: '/contact',
                permanent: true,
            },
        ]
    },
}

export default nextConfig
Enter fullscreen mode Exit fullscreen mode

It’s working! It looks like everything is good. But there’s a small problem. When we pass /contact, we get redirected. That’s what we want, but we don’t actually have this page in our app. Instead, we want to return a notFound page. Alright, let’s do this!


Middleware

This time we will use a function called Middleware(). It’s a special function that operates between the client’s request and the server’s response.

  • It allows you to execute logic, modify requests, or redirect users before they reach a specific page.
  • It works globally or on selected routes, meaning it can intercept any request and decide what to do with it.

We create this script in the main folder of the Next.js structure.

// middleware.ts

import { NextResponse, type NextRequest } from 'next/server'

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

    if (pathname === '/contact') {
        return NextResponse.rewrite(new URL('/404', request.url))
    }

    return NextResponse.next()
Enter fullscreen mode Exit fullscreen mode

We import NextResponse; this object is responsible for handling Next.js requests, while NextRequest represents the incoming HTTP request. They contain information such as the URL, headers, etc.

We export the middleware function, where the argument is a request of type NextRequest. Next, we destructure pathname from request.nextUrl to get the path after the domain.

We check the statement to see if the pathname equals, in our case, /contact. If that's true, we rewrite this request to redirect to the 404 page.

And that’s it!

// next.config.ts

/** @type {import('next').NextConfig} */
const nextConfig = {
    async rewrites() {
        return [
            {
                source: '/galeria',
                destination: '/gallery',
            },
            {
                source: '/kontakt',
                destination: '/contact',
            },
        ]
    },

    // async redirects() {
    //  return [
    //      {
    //          source: '/gallery',
    //          destination: '/galeria',
    //          permanent: true,
    //      },
    //      {
    //          source: '/contact',
    //          destination: '/kontakt',
    //          permanent: true,
    //      },
    //  ]
    // },
}

export default nextConfig

Enter fullscreen mode Exit fullscreen mode
// middleware.ts

import { NextResponse, type NextRequest } from 'next/server'

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


    if (pathname === '/contact') {
        return NextResponse.rewrite(new URL('/404', request.url))
    }

    return NextResponse.next()
}
Enter fullscreen mode Exit fullscreen mode

Bonus

And for the end, a little bonus. What if we want to change the pathname, but after that, we have something like /blog/[slug]? It’s very easy, and I’ll show you how!

//next.config.ts

/** @type {import('next').NextConfig} */
const nextConfig = {
    images: {
        remotePatterns: [
            {
                protocol: 'https',
                hostname: 'cdn.sanity.io',
            },
        ],
    },
    async rewrites() {
        return [
            {
                source: '/galeria',
                destination: '/gallery',
            },
            {
                source: '/kontakt',
                destination: '/contact',
            },
            {
                source: '/aktualnosci',
                destination: '/blog',
            },
            {
                source: '/aktualnosci/:slug*',
                destination: '/blog/:slug*',
            },
        ]
    },
}

export default nextConfig
Enter fullscreen mode Exit fullscreen mode
//middleware.ts

import { NextResponse, type NextRequest } from 'next/server'

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

    if (pathname === '/gallery' || pathname === '/contact' || pathname === '/blog') {
        return NextResponse.rewrite(new URL('/404', request.url))
    }
    if (pathname.startsWith('/blog/')) {
        return NextResponse.rewrite(new URL('/404', request.url))
    }

    return NextResponse.next()
}
Enter fullscreen mode Exit fullscreen mode

Check YouTube: https://youtu.be/SFAyBM02k9A?si=NivqJGq6cgMfHn_9

Top comments (0)