Website logo

31 Jan 2024

Implementasi
I18n
pada
React

Internationalization (i18n) adalah proses dimana membuat sebuah website atau aplikasi agar bisa diadaptasi ke berbagai macam bahasa yang berbeda.

Di setiap belahan dunia, orang-orang memahami dan menggunakan bahasa yang berbeda dalam keseharian mereka. Orang Amerika belum tentu paham dengan Bahasa Indonesia, dan juga sebaliknya, orang Indonesia belum tentu paham dengan English.

Maka dari itu dengan adanya internationalization, kita dapat membuat sebuah website atau aplikasi yang mendukung bahasa yang mereka pahami, sehingga mereka dapat menggunakannya dengan baik sesuai kebutuhan mereka.

Cara Implementasi

Untuk mengimplementasi internationalization di project React, kita dapat menggunakan sebuah library yang bernama LinguiJS.

Library ini memiliki beberapa kelebihan diantaranya:

  • Bisa digunakan di project JavaScript secara umum.
  • Bisa digunakan di project framework selain React.
  • Memiliki tools pendukung yang cukup bagus untuk menunjang penerapan i18n.
  • Mudah untuk digunakan.

Ok, kita langsung saja untuk implementasi pada framework NextJS 14 (kita pakai App Router). Pertama kita perlu install library tersebut menggunakan npm melalui terminal.

npm install --save-dev @lingui/cli
npm install --save-dev @lingui/macro @lingui/swc-plugin
npm install --save @lingui/react

Tambahkan npm scripts baru pada file package.json. Selain itu, disini kita juga mengupdate script “build” untuk menjalankan perintah untuk compile message catalog sebelum proses build NextJS dijalankan. Hal ini dilakukan untuk menghindari error ketika melakukan deployment ke Vercel.

{
	"scripts": {
		"build": "npm run lingui:compile && next build",
		"lingui:extract": "lingui extract",
	  "lingui:compile": "lingui compile"
	}
}

Tambahkan @lingui/swc-plugin ke dalam file next.config.js sebagai berikut.

/** @type {import('next').NextConfig} */
const nextConfig = {
  // ...Config lain yang kamu punya

  experimental: {
    swcPlugins: [["@lingui/swc-plugin", {}]],
  },
};

module.exports = nextConfig;

Kemudian buat file lingui.config.js di root project. File ini merupakan file berisi konfigurasi LinguiJS untuk project mu.

/** @type {import('@lingui/conf').LinguiConfig} */
module.exports = {
  locales: ["en", "id"],
  sourceLocale: "en",
  catalogs: [
    {
      path: "<rootDir>/app/locales/{locale}/messages",
      include: ["app"],
    },
  ],
  format: "po",
};

Penjelasan terkait setiap property pada konfigurasi:

  • locales merupakan bahasa-bahasa yang akan kita terapkan pada projectmu. Disini kita menggunakan “en” untuk English dan “id” untuk Bahasa Indonesia.
  • sourceLocale merupakan bahasa yang akan kita gunakan sebagai message ID, sehingga kita tidak perlu mendefinisikan message ID secara manual. Disini kita menggunakan kalimat English sebagai message ID.
  • catalogs merupakan tempat dimana kita akan menaruh file-file message catalog.
  • format merupakan jenis format yang akan digunakan untuk message catalog. Disini kita menggunakan format “po” dan format ini sangat direkomendasikan.

Opsional, jika kalian menggunakan ESLint, kalian dapat install plugin LinguiJS untuk ESLint dan menambahkan konfigurasi berikut pada file konfigurasi eslint yang ada di project kalian, misalnya .eslintrc.json.

npm install --save-dev eslint-plugin-lingui
{
  "plugins": ["lingui"]
}

Kemudian tambahkan path berikut pada file .gitignore untuk tidak mengikutkan hasil translasi ke dalam git commit.

app/locales/**/messages.js

Lalu kita perlu membuat sebuah Provider component pada app/components/Provider.tsx.

"use client";

import { FC } from "react";
import { I18nProvider } from "@lingui/react";
import { i18n } from "@lingui/core";

// Import message catalog yang telah di-compile
import { messages as enMessages } from "../locales/en/messages";
import { messages as idMessages } from "../locales/id/messages";

// Muat semua message catalog
i18n.load({
  en: enMessages,
  id: idMessages,
});

// Aktifkan English sebagai bahasa secara default
i18n.activate("en");

type Props = {
  children: JSX.Element;
};

const Provider: FC<Props> = ({ children }) => {
  return (
    <I18nProvider i18n={i18n}>
	    {children}
    </I18nProvider>
  );
};

export default Provider;

Gunakan Provider component pada app/layout.tsx.


import { FC } from "react";

import Provider from "./components/Provider";

type Props = {
  children: JSX.Element;
};

const RootLayout: FC<Props> = ({ children }) => {
  return (
    <html>
      <body>
	      <Provider>{children}</Provider>
      </body>
    </html>
  );
};

export default RootLayout;

Setelah melakukan beberapa konfigurasi diatas, selanjutnya kita dapat menerapkan nya pada komponen yang membutuhkan. Misalnya kita memiliki komponen sebagai berikut.

"use client"

import { FC } from "react";

import ContentBody from "./ContentBody";

const Content: FC = () => {
  return (
    <div>
			<h1>Learning LinguiJS</h1>

			<ContentBody value="LinguiJS is really good" />
    </div>
  );
};

export default Content;

Kita dapat mengubahnya menjadi seperti ini untuk menggunakan LinguiJS.

"use client"

import { FC } from "react";
import { Trans, msg } from "@lingui/macro";
import { useLingui } from "@lingui/react";

import ContentBody from "./ContentBody";

const Content: FC = () => {
	const { _ } = useLingui();

  return (
    <div>
			<h1>
				<Trans>Learning LinguiJS</Trans>
			</h1>

			<ContentBody value={_(msg`LinguiJS is really good`)} />
    </div>
  );
};

export default Content;

Setelah itu perlu kita jalankan perintah berikut untuk mengekstrak kalimat-kalimat yang akan ditranslasikan.

npm run lingui:extract

Perintah tersebut juga menghasilkan output berupa table yang memiliki kolom “Language”, “Total Count”, dan “Missing”. Language merupakan bahasa yang kita dukung untuk project ini, yaitu English dan Bahasa Indonesia. Total Count merupakan jumlah kalimat yang ingin kita translasikan. Missing merupakan jumlah kalimat yang belum kita translasikan.

Output dari perintah lingui extract

Perintah tersebut akan menghasilkan beberapa file message catalog dengan format “po” pada directory yang kita atur pada konfigurasi lingui.config.js, yaitu pada directory app/locales/en dan app/locales/id.

Berikut contoh pada file app/locales/en/messages.po

#: app/components/Content.tsx:15
msgid "Learning LinguiJS"
msgstr "Learning LinguiJS"

#: app/components/Content.tsx:18
msgid "LinguiJS is really good"
msgstr "LinguiJS is really good"

Berikut contoh pada file app/locales/id/messages.po

#: app/components/Content.tsx:15
msgid "Learning LinguiJS"
msgstr ""

#: app/components/Content.tsx:18
msgid "LinguiJS is really good"
msgstr ""

Bagian yang kosong pada file app/locales/id/messages.po bisa kita isi translasinya.

#: app/components/Content.tsx:15
msgid "Learning LinguiJS"
msgstr "Belajar LinguiJS"

#: app/components/Content.tsx:18
msgid "LinguiJS is really good"
msgstr "LinguiJS sangat bagus"

Setelah itu kita perlu compile file-file message catalog tersebut dengan perintah berikut.

npm run lingui:compile

Perintah tersebut akan menghasilkan file messages.js pada directory app/locales/en dan app/locales/id. File-file ini yang nantinya akan kita muat pada Provider yang telah kita buat sebelumnya.

Output dari perintah lingui:compile

Dengan ini kita sudah dapat membuat website dengan dukungan beberapa bahasa.

Untuk mengganti bahasa, kita dapat menggunakan contoh sebagai berikut. Kalau perlu, kombinasikan dengan zustand + persist middleware untuk menyimpan bahasa yang dipilih ke localStorage agar ketika halaman web di-refresh, maka bahasa yang digunakan tetap bahasa yang terpilih sebelumnya.

"use client"

import { FC } from "react";
import { useLingui } from "@lingui/react";

const LanguageSwitcher: FC = () => {
	const { i18n } = useLingui();

  return (
    <div>
			<button 
				type="button"
				onClick={() => i18n.activate("en")}
			>
				EN
			</button>
			<button
				type="button"
				onClick={() => i18n.activate("id")}
			>
				ID
			</button>
    </div>
  );
};

export default LanguageSwitcher;

Disini dapat kita lihat jika workflownya secara garis besar adalah sebagai berikut.

  • Tentukan kalimat-kalimat yang akan ditranslasikan dengan menggunakan Trans macro atau macro lainnya.
  • Jalankan perintah untuk mengekstrak kalimat-kalimat tersebut.
  • Buka file messages.po pada directory app/locales/id.
  • Isi translasi pada bagian tanda kutip yang kosong.
  • Jalankan perintah untuk meng-compile message catalog.

Banyak sekali fitur yang LinguiJS berikan, untuk itu kalian bisa langsung saja baca dari dokumentasi resmi nya di https://lingui.dev/introduction.

Kesimpulan

Internationalization sangat bermanfaat agar website atau aplikasi dapat digunakan dengan baik oleh pengguna dari berbagai negara di dunia. Dengan LinguiJS, implementasi terkait internationalization menjadi lebih mudah.