Next.js: Adding Localization with next-intl
Adding locales to a project in NextJs is as easy as creating a few files, and installing the handy npm package next-intl
. Using next-intl
works right away with minimal setup and configuration, and makes adding different locales to a new or existing project a breeze.
We'll step trough the basic setup of the project and necessary dependendies, the project structure, and a few cool things we can do with next-intl
that make langauge integrations seemless.
Install
To start thigns off, we'll create a nextjs app using the following:
$ npx create-next-app nextjs-locaels --use-npm --example "https://github.com/vercel/next-learn-starter/tree/master/learn-starter"
Once you've created the app:
$ cd nextjs-locales
$ npm run dev
You should see a generic starter page from cloning the NextJs learn-starter
project.
Next we need to add the translations dependency:
$ npm i -S next-intl
Setup
At this point, we would have already considered which langauges we want to support, and which language is our default. For this example, we're going to use English as the default, and Japanese as the next supported langauge.
Configure NextJs
Create the file next.config.js
and add the following line:
module.exports = {
i18n: {
locales: ['en', 'ja'],
defaultLocale: 'en',
},
};
We add this to next.config.js
because we want the framework to be aware of context changes within the app when we provide static props to our app.
Register Locales
In our project, we want to consider the best place for loading different translation files. Typically these extra files don't need to compiled with our source code so we can create a locales
folder outside the main source files:
next-locales
| ...
| locales/
| pages/
| README.md
| ...
In the locales folder, we can create en.json
and ja.json
respectively, making sure to match the name of the file to what we used in the config.
Using next-intl
The next few steps are a basic usage of next-intl
.
Add Languages
First we need to add to our language files, so we know where to pull information from. Using the existing text generated from our initial script, we can add to out en.json
file:
// en.json
{
"Home": {
"hello": "Welcome to Next.js!"
}
}
And to the ja.json
file:
// ja.json
{
"Home": {
"hello": "Next.jsγΈγγγγοΌ"
}
}
NOTE: be sure to research what the correct translation are for he languages you use and test accordingly!
Provide Locales
Our pages need context to pull locale information from. We provide that to a page via NextJs built-in function getStaticProps
. This gives default prop values to a react component. Place it at the bottom of index.js
.
...
export function getStaticProps({ locale }) {
return {
props: {
messages: require(`../locales/${locale}.json`),
},
};
}
NOTE: the previous step is crucial to making this work correctly since the name provided in the config need to match the file name.
Then in the pages/
folder again, create a file _app.js
which we'll use to register providers for our app. Then add the following:
import {NextIntlProvider} from 'next-intl';
export default function App({Component, pageProps}) {
return (
<NextIntlProvider messages={pageProps.messages}>
<Component {...pageProps} />
</NextIntlProvider>
);
}
What this did was take the default pageProps
object and give it another default property messages
.
Component Use
Now that our setup is complete, we can use our translation package like:
import { useTranslations } from 'next-intl';
...
export default function Home() {
const t = useTranslations('Home');
...
}
Think of the sctructure of the JSON as the copy text you'd include directly in HTML. We need to access the section of copy for the page we're on, and we identify the piece with the Home
key. Then, we access the inner copy like:
<h1>{t('hello')}</h1>
Start up the app, and if it was setup correctly, you should see the "Welcome to Next.js!"
Advanced Use
Now that we've covered the basic use. Let's take a look at a cool pattern we can use.
next-intl
gives us the option of specifying how we want to style and break apart pieces of copy. The way they accomplish this is with custom tags, declared within the copy itself.
To accomplish this, first we adjust the language files by wrapping the word "NextJs" in link
tags.
// en.json
{
"Home": {
"hello": "Welcome to <link>Next.js!</link>"
}
}
// ja.json
{
"Home": {
"hello": "<link>Next.js</link>γΈγγγγοΌ"
}
}
Then in the component, we express how we want the link
tag to function when rendering. We access the specific tag by the custom name given in the JSON, and give it a function where children
, like in React, takes the contents between the custom tags, and interpolates that, whoever we choose. In our case, we want to maintain the original link that was generated from the project starter.
<h1>{t('hello', {
link: (children) => <a href="https://nextjs.org">{children}</a>,
})}</h1>
Locale Strategies
NextJs' routing feature is powerful in the way it works with the basic setup we have thus far. Because we defined our locales in the config, we can run the app and navigate to the locale code to see it render in view.
For example: navigating to localhost:3000/ja
will dynamically render the right context via the provider we set up in _app.js
.
Read more about NextJs Locale Strategies to learn more about routing and locales for your app's needs.
Conclusion
Adding i18n to a project is simple. As we've seen, with just a few steps, we were able to add some basic copy translations to our app with minimal effort.
Try the complete code example.