i18next

Framework Next.js 13 Internationalization (i18n) i18next

Start to using i18next

Install Packages

yarn add i18next
yarn add i18next-fs-backend

Create your locale json file

// public/locales/en/translation.json
{
  "hello": "Hello",
  "world": "World"
}
// public/locales/zh_TW/translation.json
{
  "hello": "你好",
  "world": "世界"
}

Init yout i18next setting

// app/layout.js
import i18next from 'i18next';
import Backend from 'i18next-fs-backend';

// init i18next locale language setting
i18next
  .use(Backend)
  .init({
    // Let i18n can read later
    initImmediate: false,
    nonExplicitSupportedLngs: false,
    // debug: true,
    lng: 'en',
    // fallbackLng: 'en',
    fallbackLng: {
      // Find language code => mapping exist language code
      'zh': ['zh_TW'],
      'zh-TW': ['zh_TW'],
      'zh-Hant': ['zh_TW'],
      'default': ['en']
    },
    preload: [
      'en',
      'zh_TW'
    ],
    ns: ['translation'],
    defaultNS: 'translation',
    backend: {
      loadPath: '../../public/locales/{{lng}}/{{ns}}.json'
    },
  }, (err, t) => {
    // Debug
    if (err) return console.error(err)
    console.log('i18next is ready...')
    console.log(t('hello'))
    console.log(t('hello', { lng: 'zh_TW' }))
  });

Show your locale messages

// app/layout.js
import i18next from 'i18next';
import Backend from 'i18next-fs-backend';

export default function RootLayout({ children }) {
  <html lang="en">
    <body>
      {i18next.t('hello')}
      {i18next.t('hello', { lng: 'zh_TW' })}
      {children}
    </body>
  </html>
}

Detect and Change Browser Preference language

Install packages

yarn add accept-language-parser

Create i18next locale manager file

// app/i18NextLocaleManager.js
// https://beta.nextjs.org/docs/api-reference/headers
import { cookies, headers } from 'next/headers';
// https://www.i18next.com/
import i18next from 'i18next';
// https://www.npmjs.com/package/accept-language-parser?activeTab=readme
import acceptLanguageParser from 'accept-language-parser';

const DEFAULT_ALLOW_LANGUAGES_CODE_LIST = [
  'en', 
  'zh-TW'
];
const DEFAULT_LOCALE_COOKIE_NAME = 'locale';

const getHeaderAcceptLanguagePreferenceLanguage = async function(
  allow_language_code_list = DEFAULT_ALLOW_LANGUAGES_CODE_LIST
) {
  // Get accept language from header
  const accept_languages_header = headers().get('accept-language');

  // Parse accept language header
  const accept_language = acceptLanguageParser.pick(allow_language_code_list, accept_languages_header);

  if (!accept_language) {
    // Accept language not exist
    return false;
  }


  return accept_language;
};

const getCookiePreferenceLanguage = async function(
  locale_cookie_name = DEFAULT_LOCALE_COOKIE_NAME
) {
  // Locale cookie
  const locale_cookie = await cookies().get(locale_cookie_name);

  if (!locale_cookie) {
    // No locale cookie value
    return null;
  }

  return locale_cookie.value;
}

const getCookiePreferenceLanguage = async function(
  locale_cookie_name = DEFAULT_LOCALE_COOKIE_NAME
) {
  // Locale cookie
  const locale_cookie = await cookies().get(locale_cookie_name);

  if (!locale_cookie) {
    // No locale cookie value
    return null;
  }

  return locale_cookie.value;
}

const getI18nextPreferenceLanguage = async function({
  locale_cookie_name, 
  allow_language_code_list
}) {
  // Get preference language from cookie
  const cookie_locale = await getCookiePreferenceLanguage(locale_cookie_name);
  
  if (cookie_locale) {
    console.log('Set cookie locale', cookie_locale);
    i18next.changeLanguage(cookie_locale);
    // console.log(i18next.language);
    return i18next.resolvedLanguage;
  }
  
  
  // Get preference language from header accept language
  const header_accept_language_locale = await getHeaderAcceptLanguagePreferenceLanguage(allow_language_code_list);

  if (header_accept_language_locale) {
    console.log('Set header locale', header_accept_language_locale);
    i18next.changeLanguage(header_accept_language_locale);
    return i18next.resolvedLanguage;
  }

  return i18next.resolvedLanguage;
}



export {
  getHeaderAcceptLanguagePreferenceLanguage,
  getCookiePreferenceLanguage,
  getI18nextPreferenceLanguage
}

Setting preference language

// app/layout.js
// https://www.i18next.com/
import i18next from 'i18next';
import { getI18nextPreferenceLanguage } from './i18NextLocaleManager';

export default async function RootLayout({ children }) {
  await getI18nextPreferenceLanguage({
    locale_cookie_name: 'locale', 
    allow_language_code_list: ['en', 'zh-TW']
  });

  return (
    <html lang={i18next.language}>
      <body>
        {children}
      </body>
    </html>
  );
}

Reference