2 Ways to Setup i18Next in Next.js

Last Updated Date: 18-06-2023

This note outlines both client-side and server-side rendering way to setup i18Next in Next.js.

Please notice that:

  • Page Router will be used instead of the new App Router introduced in Next.js 13.

  • TypeScript will be used instead of JavaScript for better type declaration.

Introduction of i18Next

i18Next is a user-friendly internationalization (i18n) framework that helps developers easily translate and adapt their applications to different languages and regions. With features like translation management, pluralization support, and flexible formatting options.

Initialize the Project

First of all, initialize a Next.js application and install the dependencies first.

# npm
npx create-next-app

# pnpm
pnpm create next-app

After creating the project, install i18next dependency into it.

# npm
npm install i18next

# pnpm
pnpm add i18next

Method 1: Client-Side Rendering

In Client-Side Rendering (CSR), i18Next setup is done on the client-side, the translactions are loaded and managed by the client's browser. Which may not be a good idea for Next.js initial page load performance and Search Engine Optimization (SEO).

If planning to use CSR, follow the provided configuration below.

CSR: Installation

install the react-i18next dependency first.

# npm
npm install react-i18next

# pnpm
pnpm add react-i18next

CSR: Configuration

Then follow the provided configuration below.

// src/locales/index.tsx

import i18n from "i18next";
import { initReactI18next } from "react-i18next";

import translation_en from "./langs/en";
import translation_zh_hant from "./langs/zh-Hant";

const resources = {
    en: {
        translation: translation_en,
    },
    zh_hant: {
        translation: translation_zh_hant,
    },
};

i18n.use(initReactI18next).init({
    resources,
    // fallback language if any issues
    fallbackLng: "en",
    interpolation: {
        // React already did the value escape
        escapeValue: false,
    },
});

export default i18n;

Write all the English translations in en.tsx (or Traditional Chinese translations in zh-Hant.tsx).

// src/locales/langs/en.tsx

const lang = {
    title: "Hello World!",
    content: {
        a: "This is A content",
        b: "This is B content",
    },
};

export default lang;

Then import it into _app.tsx to apply all the configuration.

// src/pages/_app.tsx

import "@/locales";

CSR: Usage

To use it in the component, you may use the useTranslation hook which provided by react-i18next library;

// src/pages/index.tsx

import { useTranslation } from "react-i18next";

export default function () {
	// declarations
	const { t, i18n } = useTranslation();

	// change language
	const changeLang = (val: string) => {
		i18n.changeLanguage(val);
	};

	// contents
	return (
		<>
			<div>{t("title")}</div>
			<div>{t("content.a")}</div>
		</>
	);
}

Method 2: Server-Side Rendering

In Server-Side Rendering (SSR), i18Next setup is done on the server-side, and the translations are pre-rendered before being sent to the client. Better performance and SEO result will be benifits from Next.js.

If planning to use SSR, follow the provided configuration below. However, please note that if the internet connection is slow, page loading may take more time due to the need for getServerSideProps to connect to the server each time a page changes.

SSR: Installation

Install both react-i18next and next-i18next dependencies before start.

# npm
npm install react-i18next next-i18next

# pnpm
pnpm add react-i18next next-i18next

SSR: Configuration

After adding dependencies, please do the configuration as well.

// next-i18next.config.js

const path = require("path");

/** @type {import('next-i18next').UserConfig} */
module.exports = {
    i18n: {
        defaultLocale: "default",
        locales: ["default", "en", "zh-Hant"],
        localeDetection: false,
    },
    lowerCaseLng: true,
    nonExplicitSupportedLngs: true,
    localePath: path.resolve("src", "locales"),
};

After the configuration in next-i18next.config.js, import it into next.config.js to apply part of the language configuration.

// next.config.js

const { i18n } = require("./next-i18next.config.js");

const nextConfig = {
    // other settings ...
    i18n,
};

module.exports = nextConfig;

Then do the configuration in _app.tsx as well:

// src/pages/_app.tsx

import { appWithTranslation } from "next-i18next";

const App = ({ Component, pageProps }) => {
    // ...
};

export default appWithTranslation(App);

When you add different translation, common.json will be considered as an index file by default, if you tend to add other languages, you may add it into {lang}/common.json first:

// src/locales/en/common.json

{
    "title": "Hello World!",
    "content": {
        "a": "This is A content",
        "b": "This is B content"
    }
}

SSR: Usage

To use the function of i18Next, you may use the useTranslation hook which provided by next-i18next library. Additionally, getServerSideProps function is only required in page-level component. you don't need to add it everywhere.

// src/pages/index.tsx

import { useTranslation } from "next-i18next";
import { serverSideTranslations } from "next-i18next/serverSideTranslations";

export default function () {
	// declarations
	const { t } = useTranslation();
	// or
	const { t } = useTranslation("common");

	// change language
	const changeLang = (val: string) => {
		router.replace(router.route, router.asPath, {
			locale: val,
		});
	};

	// contents
	return (
		<>
			<div>{t("title")}</div>
			<div>{t("content.a")}</div>
			{/* or this if the translation is not in common.json but others.json */}
			<div>{t("others:content.a")}</div>
		</>
	);
}

// only required in page level components
export const getServerSideProps = async ({ query, locale }: any) => {
	return {
		props: {
			...(await serverSideTranslations(locale, ["common"])),
		},
	};
};

Switch Language on initialization

The automatic language-switching function can be added in _app.tsx. Below is an example that detects the language state from the link and switches to it during initialization. You may do it in the CSR way as well.

// src/pages/_app.tsx

import { useRouter } from "next/router";

const App = ({ Component, pageProps }) => {
    // declarations
    const router = useRouter();
    // set which languages to provide
    const langProvider = ["en", "zh-Hant"];

    // ...

    // initialize
    React.useEffect(() => {
        const getLang = () => {
            // link language
            const pathname = window.location.pathname;
            const linkLang = pathname.split("/")[1];

            // more ways can be added here

            if (langProvider.includes(lang)) {
                return lang;
            } else {
                return "zh-hk";
            }
        };
        let lang = getLang();
        router.replace(router.route, router.asPath, {
            locale: lang,
        });
    }, []);
};

Conclusion

In conclusion, both client-side and server-side rendering (CSR and SSR) methods can be used to set up i18Next in a Next.js project. However, it's important to consider the specific requirements and characteristics of your application to determine which method is more beneficial.

Feel free to contact if there are any problem in this note.