Skip to content

Yrobot/i18next-ssg

Repository files navigation

logo


The i18n tool for next.js ssg project.

npm package


Demos

How To Start

1. Install i18next-ssg

yarn add i18next-ssg next-i18next react-i18next i18next

2. Project Setup

First, create a next-i18next.config.js file in the root of your project.

next-i18next.config.js

module.exports = {
  i18n: {
    defaultLocale: "en", // the default language
    locales: ["en", "zh"], // language list
  },
};

And You have to expose the i18n config as the next.js Environment Variable NEXT_PUBLIC_I18N.

next.config.js

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

module.exports = {
  env: {
    NEXT_PUBLIC_I18N: i18n,
  },
};

3. Add locales json files to your Next.js project

- public
  - locales
    - zh
      - common.json
    - en
      - common.json
    - ... other languages

public/locales/en/common.json

{
  "title": "English Title"
}

If you want to structure your translations/namespaces in a custom way, you will need to pass modified localePath and localeStructure values into next-i18next.config.js. Check detail here https://github.com/i18next/next-i18next#options

4. Wrap the app

pages/_app.tsx

add appWithTranslation logic

import { appWithTranslation } from "i18next-ssg";

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

export default appWithTranslation(App);

5. Create pages/[locale] directory and Add pages under it

pages
  - [locale]
    - index.tsx
    - second.tsx
    - third.tsx

/second/index.tsx and /second.tsx both work fine for /second

Add locale inject logic in every page, for example:
pages/[locale]/index.tsx

import { makeStaticProps, getStaticPaths } from "i18next-ssg/server";

export default Page(){
  return <div>Page</div>
}

const getStaticProps = makeStaticProps(["common"]);
export { getStaticPaths, getStaticProps };

6. use i18n inside the page

for example:

import { useTranslation } from "i18next-ssg";

export default function Title() {
  const { t } = useTranslation("common");
  return <div>{t("title")}</div>;
}

7. Add root redirect logic [optional]

First, create [[...paths]].tsx under the pages folder (i18next-ssg will auto generate the root pages based on the pages you created under [locale])

pages/[[...paths]].tsx

copy pause the code directly without any changes, it will works fine for your project.

export { getStaticProps, getStaticPaths } from "i18next-ssg/Redirect";
import { useRootPathRedirect } from "i18next-ssg";

export default function Page() {
  useRootPathRedirect();
  return <div>Redirecting...</div>;
}

Then, the auto redirect logic works like this:

  • / => /[locale]
  • /second => /[locale]/second
  • /third => /[locale]/third

The [locale] value based on getLocale, which strategy works follow this:

[url locale] > [user set locale in localStorage] > [locale detect from browser navigator]


After all these steps and run yarn build (next build && next export -o build), you will get output files below:

- build
  - locales
    - ... your locale json files
  - index.html
  - second.html
  - third.html
  - zh.html
  - en.html
  - en
    - second.html
    - third.html
  - zh
    - second.html
    - third.html

Other Tricks

get your i18n config quickly

this work fine on both server and browser.

import { config } from "i18next-ssg";

console.log(config.locales);
console.log(config.defaultLocale);

All functions exported from next-i18next or react-i18next

import {
  appWithTranslation,
  serverSideTranslations,
  i18n,
  withTranslation,
  I18nContext,
  Trans,
  Translation,
  useTranslation,
} from "i18next-ssg";

locale route logic

I18NLink

import { I18NLink } from "i18next-ssg";
export default function Pages() {
  return <I18NLink href="/sansa">Sansa</I18NLink>; // /sansa => /[locale]/sansa
}

localize

import { useRouter } from "next/router";
import { localize } from "i18next-ssg";
export default function Pages() {
  const router = useRouter();
  return (
    <span
      onClick={() => {
        router.push(localize("/sansa")); // /sansa => /[locale]/sansa
      }}
    >
      Sansa
    </span>
  );
}

locale switch logic

import Link from "next/link";
import { useLocaleSwitcher, setUserLocale } from "i18next-ssg";

const localeMap: Record<Locale, string> = {
  en: "English",
  zh: "中文",
};

function LocaleSwitcher() {
  const {
    label, // current locale label
    options, // the option list of other locales
  } = useLocaleSwitcher({ localeMap });
  return (
    <div>
      <label>{label}</label>
      <ul>
        {options.map(({ label, path, locale }) => (
          <li key={path}>
            <Link href={path}>
              <span
                onClick={() => {
                  setUserLocale(locale);
                }}
              >
                {label}
              </span>
            </Link>
          </li>
        ))}
      </ul>
    </div>
  );
}

export default LocaleSwitcher;