Next.js: Multilanguage support with internationalized routing
Tags: nextjs, i18n, indianlanguages, multilingual
Published: 2021-04-08 13:57:03

Let's create a simple Next.js starter project with multiple languages - English *(en-US)*, Tamil *(ta-IN)*, Hindi *(hi-IN)*, Kannada *(kn-IN)* support using Next.js native [i18n](https://nextjs.org/docs/advanced-features/i18n-routing).

> :point_right: Source code of this article available at [GitHub](https://github.com/singara-velan/Nextjs-Multilanguage)

### What are we going to do
* Creating a Next js app (v10.x.x) with boostrap.css
* Configuring i18n in next.config.js
* Create locale JSON
* Read locale from the route and display in the HTML

### Set up
Create a Next js app and add bootstrap, swr as dependency
`npx create-next-app`
`npm i -s bootstrap`
`npm i -s swr`

Run the app
`npm run dev`

Create a new page called home under pages
```
const Home = () => {
    return (
        <h1>Hey! I am home - English</h1>
    )
}
    
export default Home;
```

Navigate to `http://localhost:3000/home`
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/342pb2yn0i9yk0tbepbw.png)
 
### Configuring i18n route
*There are two ways to handle locale: Sub-path and domain routing. Here we explore Sub-path routing*

Sub-path routing is basically prefixing locale code in front of existing routes without any impact on actual routing. 

`eg: /home,
     /en-US/home,
     /ta-IN/home,
     /hi-IN/home`

Now if you try to access one of the routes eg: `/en-us/home`, you will see 404 message. Because locale-based routing not enabled yet.
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yqhzgvgeabm74twl4xdj.png)
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7bc1465poepp1jllqdjv.png)

To enable locale-based routing, Create a next.config.js file in the project root as below.
```
module.exports = {
    i18n: {
        locales: ['en-us', 'ta-in', 'hi-in', 'kn-in'],
        defaultLocale: 'en-us'
    }
}
```
> :bulb: checkout i18n locale code reference for different languages [here](https://gist.github.com/singara-velan/aedb97495f4e430fc34e88daef6716e5)

> :bulb: Do remember to stop and start the app, whenever modifying next.config.js

Now try again to access locale-based route `/en-us/home`
Boom, it works!! :heart_eyes:
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fov47yv1scapniddnuwe.png)

Let's try with another locale code `/ta-in/home`. 
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ld7q4g2jf5o6vaykvk58.png)
The page didn't break, but the language doesn't change :frowning: Because we didn't create any language-specific content. 

### Create language-specific files
*Create a new folder called `locales` under the public folder and create JSON files with exact names as locale codes*
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/y6nq8m9s08xy5zl82l5h.png)
Inside of each JSON create one key-value language as a data property

eg: [en-US](https://raw.githubusercontent.com/singara-velan/Nextjs-Multilanguage/main/public/locales/en-US.json)
```
{
    "language": "English"
}
```
[ta-IN](https://raw.githubusercontent.com/singara-velan/Nextjs-Multilanguage/main/public/locales/ta-IN.json)
```
{
    "language": "தமிழ்"
}
```
[hi-IN](https://raw.githubusercontent.com/singara-velan/Nextjs-Multilanguage/main/public/locales/hi-IN.json)
```
{
    "language": "हिन्दी"
}
```
### Loading the language file based on route locale code

*When navigating to a specific locale route, the page should show content from the respective locale JSON file.*

We will be achieving that by
1 Get the locale code from the route
2 Fetch the locale JSON
3 Bind in HTML

1: Get the locale code from the route
`next/router` will provide us the locale code. Update the home.js file with `useRouter` hook.
```
const router = useRouter();
const locale = router.locale;
```
2: Fetch locale JSON file
Make Rest call using [useSWR](https://swr.vercel.app/) hook with the locale code from the previous step.

```
const { data, error } = useSWR(`/locales/${locale}.json`, fetcher)
```

3: Bind in HTML
Replace the `English` with the data fetched from the previous step. Final home.js will looks as below.
```
import { useRouter } from 'next/router'
import useSWR from 'swr'

const Home = () => {
    const router = useRouter();
    const locale = router.locale;

    const { data, error } = useSWR(`/locales/${locale}.json`, fetcher)

    return (
        <h1>Hey! I am home - {data?.language}</h1>
    )
}

const fetcher = (...args) => fetch(...args).then(res => res.json());

export default Home;
```
### Time for Testing! :smiley: :smiley:
Try access different route based on route code
`http://localhost:3000/ta-IN/home`
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vdkfumx0hothga3lexp5.png)
`http://localhost:3000/hi-IN/home`
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/495mynxb6dll3dr7quyg.png)

Its working !! Have a great day :blush: :innocent: