To add internationalization to a web app, you need to handle two main tasks: managing translations and maintaining separate URLs.
Questions related to your URLs often include:
- How are locales split up? Will you use a sub-path (/fr vs /en) or domain locale strategy (domain.com vs domain.fr)?
- If your user change locale, how do you redirect them to the correct URL?
- Can you detect the user's preferred locale and redirect them accordingly?
In October 2020, Next.js released a new version of its framework. Among all the new and shiny features, the one which interested me the most was Internationalized Routing. This feature added built-in support for routing in multilingual applications along with language detection. This however leaves you with the last component: managing translations.
Enter next-translate. I have chosen this particular translation library for many reasons. On top of being very easy to use and configure, I love next-translate because it works very well with Next.s automatic page optimization. Meaning, my prerendered static pages can stay this way and next-translate will handle the translation. Woo!!
Now that the introductions are done, let's move on to the nitty gritty.
Step 1: Setting up locale strategy in next.config.js
As mentioned before, there are two ways you can go about locale strategy: sub-path (/fr, /en, /en-US, ...) or domain routing (.com, .fr, .ca).
Note: If you are not sure which to choose, consult Google's documentation on using locale-specific URLs detailing the pros and cons for each.
For this tutorial, you will be going down the sub-path route (pun intended). To do so, you need to update your next.config.js and add your locales.
In this example, the resulting URLs will be / for anglophones and /fr for francophones.
module.exports = {
i18n: {
locales: ['en', 'fr'],
defaultLocale: 'en',
},
}
Step 2: Set up Internationalized Routing in your Next.js pages
Now that your locale strategy is defined, let's move on to your pages. How does Next.js handle internationalization with its static and dynamic pages?
Static pages
Luckily for us, Next.js generates separate versions for each locale. At build time, Next.js will therefore spit out two index.js pages, one in english and one in french.
Dynamic pages
However, your dynamic pages need a little bit of love. Say, for example, I have a Next.js application for my blog. I have two pages: index.js listing all the posts and [slug].js for individual post.
Because I want my pages to load quickly, I want them statically generated. This means that, at built time, separate HTML files (post-1.html, post-2.html, ...) are generated for all my blog posts.
In multilingual applications, not only would I want all these pages generated, but I would also want a version for each locale. The end result will look something like this:
.next/ <- contains all the files generated at build time
│
└───en/
| post-1.html
| post-2.html
└───fr/
post-1.html
post-2.html
Therefore, in your application, not only do you need to specify all the different paths (meaning /post-1, /post-2, ...), but also the locales.
What it would look like with my blog example:
export async function getStaticPaths({ locales }) {
const paths = []
locales.forEach((locale, i) => {
posts.forEach((post, i) => {
paths.push({ params: { slug: post.id }, locale })
});
});
return { paths, fallback: false }
}
(Optional) Retrieve the current locale in your Next.js app
You can see what the current locale is at any point thanks to the router.
import { useRouter } from 'next/router';
export default function Home() {
const router = useRouter()
const { locale } = router
return (
<div className="center-container">
<main className="main">
// ...
<section>
<div>Current locale: {locale}</div>
</section>
// ...
</main>
</div>
)
}
Step 3: Changing locale and redirecting in your Next.js app
I love that Next.js made it really simple to redirect when changing locale. All you have to do is specify the locale in your Link component. It's pretty straightforward which I love! <3
import Link from 'next/link';
export default function Home() {
return (
<div className="center-container">
// ...
<div>
<Link href="/" locale="en">
<a>Change to english</a>
</Link>
</div>
<div>
<Link href="/" locale="fr">
<a>Change to french</a>
</Link>
</div>
// ..
</div>
)
}
Step 4: Install next-translate
Now that internationalized routing is implemented, we can move on to the last part of this tutorial: translations.
To start with, let's add the library.
npm install next-translate
# or
yarn add next-translate
Step 5: Update next.config.js
Then, update your next.config.js to use next-translate.
const nextTranslate = require('next-translate')
module.exports = nextTranslate()
Step 6: Set up your locales and namespaces
The last part of your configuration is to create an i18n.json and add your locales. One feature I really is being able to split your translations into separate files. This allows you to have page-specific translations.
For the sake of this tutorial however, I will only have one namespace called common
which will be applied to my entire app ("*").
{
"locales": ["en", "fr"],
"defaultLocale": "en",
"pages": {
"*": ["common"]
}
}
Step 7: Creating translations files
For your next step, you then create a locales folder where you will add separate folders for all your locales. In each folder, you need to create a json file for all your namespaces.
Since I only have one namespace (common), I will go ahead and create one json file called common.json
for each locale folder.
This is what I have in the end:
locales/
│
└───en/
│ common.json
└───fr/
common.json
Inside your json files, add all your translations.
{
"homepage_title": "Blog in Next.js",
"homepage_description": "This example shows a multilingual blog built in Next.js with next-translate"
}
Step 8: Displaying translated content
Finally, you can display your translated text by getting the t function from useTranslation. By passing the translation key, you can then retrieve the translated value and display it.
import useTranslation from 'next-translate/useTranslation'
export default function Home() {
const { t } = useTranslation('common')
return (
<div className="center-container">
<main className="main">
<h1 className="title">
{t('homepage_title')}
</h1>
<p className="description">
{t('homepage_description')}
</p>
</main>
</div>
)
}
Et voilà!
Your application is now officially multilingual. Along with displaying translated content, your app also handles internationalized routing thanks to Next.js built-in support.
If you liked the article, you can follow me on Twitter.
Top comments (0)