Primoz Rome
Primoz Rome

Reputation: 11061

How to setup i18n translated URL routes in Next.js?

I am using Next.js i18n-routing to setup multi-language website. This works perfectly. If I create a file in /pages/about.js this will create URLs based on my locale settings, for example:

That is all fine.

What if I want to have a translated URL routes for each language? I am stuck on how to set this up...

?

Upvotes: 27

Views: 18665

Answers (3)

Jack Tsin
Jack Tsin

Reputation: 71

For anyone looking for a solution like the one @juliomalves gave, and one that doesn't involve the use of middleware on every request, you can:

  1. generateStaticParams as dynamic routes (statically generated) as explained here: use generateStaticParams() in layout.tsx NextJS 14 app directory to get dynamic rotes prerendered (PPR)
  2. rewrite the paths dynamically if you want to get the default locale at "/" (instead of "en/" for example if your default locale is English):
    const nextConfig = {
      ...
      async rewrites() {
        return [
          // Handle all paths that don't start with a locale 
          // and point them to the default locale static param: (en)
          {
            source: '/:path((?!(?:de|fr|es|it|el|pl|nl|en)(?:/|$)).*)',
            destination: '/en/:path*',
          },
        ];
      },
    };

Upvotes: 0

Cauan Goes
Cauan Goes

Reputation: 76

For a more scalable solution check this package: https://www.npmjs.com/package/next-translate-routes

With this you can keep one json file for your main urls and translations and also has a component for making i18n links easier

Upvotes: 2

juliomalves
juliomalves

Reputation: 50438

You can achieve translated URL routes by leveraging rewrites in your next.config.js file.

module.exports = {
    i18n: {
        locales: ['en', 'de', 'es'],
        defaultLocale: 'en'
    },
    async rewrites() {
        return [
            {
                source: '/de/uber-uns',
                destination: '/de/about',
                locale: false // Use `locale: false` so that the prefix matches the desired locale correctly
            },
            {
                source: '/es/nosotros',
                destination: '/es/about',
                locale: false
            }
        ]
    }
}

Furthermore, if you want a consistent routing behaviour during client-side navigations, you can create a wrapper around the next/link component to ensure the translated URLs are displayed.

import { useRouter } from 'next/router'
import Link from 'next/link'

const pathTranslations = {
    de: {
        '/about': '/uber-uns'
    },
    es: {
        '/about': '/sobrenos'
    }
}

const TranslatedLink = ({ href, children }) => {
    const { locale } = useRouter()
    // Get translated route for non-default locales
    const translatedPath = pathTranslations[locale]?.[href] 
    // Set `as` prop to change displayed URL in browser
    const as = translatedPath ? `/${locale}${translatedPath}` : undefined

    return (
        <Link href={href} as={as}> 
            {children}
        </Link>
    )
}

export default TranslatedLink

Then use TranslatedLink instead of next/link in your code.

<TranslatedLink href='/about'>
    <a>Go to About page</a>
</TranslatedLink>

Note that you could reuse the pathTranslations object to dynamically generate the rewrites array in the next.config.js and have a single source of truth for the translated URLs.

Upvotes: 36

Related Questions