Logo
Published on
ยท8 min read

Next.js - Creating a Multilingual (i18n) Blog Part 1

I apologize in advance for any awkward expressions in English. ๐Ÿ™

English is not my native language, and I have relied on ChatGPT's assistance to proceed with the translation.

Overview

For this blog, I'd like to have the default language as Korean and add additional content in English for specific posts.

Please note that this blog is based on the Tailwind CSS Blog Starter template code.
(I received it as a Pages Route-based code initially, but it seems to have been changed to App Route-based now.)

Since the content has become extensive, I'll be dividing it into Parts 1 through 4.

In Part 1, we'll implement multilingual support for the site using the next-i18next library. (Handling multilingual content for individual posts will be covered in Part 2.)


I created this project with reference to gitHub, i18n-tailwind-nextjs-starter-blog.

If you've decided to use the Tailwind CSS Blog Starter template and are starting your project from scratch, it might be a good idea to start with the above project.

In my case, since the project was already in progress, I proceeded with it by referring to the mentioned project.

next-i18next

First, aside from translating the blog posts (md/mdx) into multiple languages, we use the next-i18next library for displaying language-specific content, such as error messages, according to the configured language.

If you don't require translation, you can skip this part and simply configure Next.js' default i18n (next.config.js) for your use.

Installation

You can find detailed installation and configuration instructions for next-i18next on their GitHub page.

First, install it by running the following command:

npm install next-i18next react-i18next i18next

Adding Translation Files

  • Create a locales folder under the public directory.

  • Within the locales folder, create en and ko folders.

  • Create a public/locales/en/common.json file and write it as follows:

{
  "all": "All Posts"
}
  • Create a public/locales/ko/common.json file and write it as follows:
{
  "all": "์ „์ฒด ๊ธ€"
}
  • Please note that when adding key/value pairs during local development, you may need to restart the application to read the newly added values. Keep this in mind.

Project Configuration

  • Create a next-i18next.config.js file in the top-level folder and add your desired language configurations.
    (I've configured the default language as Korean and provided languages as Korean and English like this:)
/** @type {import('next-i18next').UserConfig} */
module.exports = {
    i18n: {
        defaultLocale: 'ko',
        locales: ['ko', 'en']
    }
}
  • Open the next.config.js file and add the i18n configuration. (A restart is required.)
const { i18n } = require('./next-i18next.config') // Add

// ...

module.exports = withBundleAnalyzer({
  i18n, // Add
  reactStrictMode: true,
  // ...
})
  • Open the pages/_app.js file and add appWithTranslation.
import { appWithTranslation } from 'next-i18next'  // Add

function App({ Component, pageProps }) { // Remove export default
  // ...
}

export default appWithTranslation(App) // Add appWithTranslation

It's all set up. Now it's time to check if it's working correctly.

Confirming Locale Functionality

Confirming that it's accessible at http://localhost:3000/en. (There won't be any page changes yet since translation hasn't been applied.)

Display According to Language

Let's make changes to display the translated value for All Posts on the Blog page.

  • Modify pages/blog.js
// ...
import { serverSideTranslations } from 'next-i18next/serverSideTranslations' // Add
import { useTranslation } from 'next-i18next' // Add

// ...

export async function getStaticProps({ locale }) { // Add { locale }
  // ...

  return {
    props: {
      ...(await serverSideTranslations(locale, ['common'])), // Add
      // ...
    },
  }
}

export default function Blog({ posts, initialDisplayPosts, pagination }) {
  const { t } = useTranslation('common') // Add

  return (
    <>
      // ...
      <ListLayout
        // ...
        title={t('all')} // Fetch Translation for the Appropriate Language
      />
    </>
  )
}
  • When you access http://localhost:3000/blog, you can see that it's displayed as ์ „์ฒด ๊ธ€.
  • When you access http://localhost:3000/en/blog, you can see that it's displayed as All Posts.

It looks like the language-specific display is working correctly!


โœ” During the installation process of next-i18next, it seems that things got tangled as I repeated the installation, uninstallation, installation of other libraries, and reinstallation of next-i18next. There was no apparent reason why it wasn't working, but it couldn't read the translation files. In the end, I had to delete the 'node_modules' folder and reinstall it, and it started working correctly.


Now, we will add links to easily switch between languages, as shown in the image below.

๋งํฌ ๋ณ€๊ฒฝ ํ™•์ธ

Adding Language Switching Component

  • Create a components/LanguageSwitch.js file and write it as follows:
import { useRouter } from 'next/router'
import Link from 'next/link'

const LanguageSwitch = () => {
  const { locales, locale, asPath } = useRouter()

  if (!locales) {
    return null
  }

  return (
    <div className="rounded bg-gray-200 py-2 dark:bg-gray-800">
      {locales.map((item) => (
        <Link key={item} locale={item} href={asPath}>
          <a
            className={`p-2 font-medium text-gray-900 dark:text-gray-100 ${
              item === locale ? 'rounded bg-gray-400 dark:bg-gray-600' : ''
            }`}
          >
            {item}
          </a>
        </Link>
      ))}
    </div>
  )
}

export default LanguageSwitch

Applying the Language Switching Component

  • In components/LayoutWrapper.js, use the LanguageSwitch component.
import LanguageSwitch from '@/components/LanguageSwitch' // Add

const LayoutWrapper = ({ children }) => {
  return (
    <SectionContainer>
      <div className="...">
        <header className="...">
          // ...
          <div className="...">
            // ...
            <LanguageSwitch /> // Add
            <ThemeSwitch />
            <MobileNav />
          </div>
        </header>
      </div>
    </SectionContainer>
  )
}

Now, for the text you want to display in different languages, you can pass serverSideTranslations as a prop in the getStaticProps of the respective page and handle it in the component using {t('key')}.

Please refer to the modified section in pages/blog.js for guidance.


Summary

To summarize the essential tasks from the work:

  1. Install and configure next-i18next.
  2. Add translation files.
  3. Apply translation to pages (using getStaticProps, serverSideTranslations, and t('key')).

For blog posts that are read from .md(x) files, managing them as {t('key')} isn't feasible.

You need to display registered posts differently based on the selected language, including post lists, tag lists, etc.

We'll continue with related content in Next.js - Creating a Multilingual (i18n) Blog Part 2.

Code

The updated code can be found in the commit history.