Internationalization (i18n)

Plugin internationalization bisa membuat bot kamu berbicara dalam berbagai macam bahasa.

i18n vs Fluent

Jangan bingung membedakan plugin ini dengan plugin fluent.

Plugin ini merupakan versi upgrade dari plugin fluent. Ia dapat digunakan baik di Deno maupun Node.js.

Penjelasan Internationalization

Di bagian ini kita akan membahas apa itu internationalization, kenapa ia diperlukan, apa saja kendalanya, apa hubungannya dengan localization, serta kenapa kamu perlu sebuah plugin untuk melakukan semua itu. Jika kamu sudah memahami itu semua, langsung gulir ke bawah menuju bagian Memulai.

Pertama-tama, internationalization merupakan kata yang sangat panjang. Karena alasan tersebut, orang-orang lebih memilih menulis huruf pertama (i) dan huruf terakhirnya (n) saja. Mereka kemudian menghitung huruf yang tersisa (nternationalizatio, 18 huruf) lalu meletakkan digit angka tersebut diantara huruf i dan n, sehingga jadilah i18n. Tolong jangan tanya kami apa alasannya. Setidaknya sekarang kamu paham bahwa i18n adalah sebuah singkatan aneh dari kata internationalization.

Hal yang sama juga berlaku untuk localization, yang disingkat menjadi l10n.

Apa itu Localization?

Localization maksudnya adalah membuat sebuah bot yang dapat berbicara dengan berbagai macam bahasa. Bot tersebut didesain sedemikian rupa sehingga bahasa yang ditampilkan serupa dengan bahasa yang digunakan oleh user.

Selain bahasa, ada banyak hal lainnya yang bisa di-localize. Selain itu, kamu juga bisa menyesuaikan perbedaan kultural atau format-format lainnya, misalnya format waktu dan tanggal. Berikut hal-hal yang ditampilkan secara berbeda di berbagai tempat:

  1. Tanggal
  2. Waktu
  3. Angka
  4. Satuan
  5. Kata jamak
  6. Jenis Kelamin
  7. Tanda hubung
  8. Huruf Kapital
  9. Posisi Teks
  10. Simbol dan ikon
  11. Pengurutan

… dan lain sebagainyaopen in new window.

Semua hal di atas menentukan jenis locale yang digunakan oleh suatu user. Locale seringkali disimbolkan dengan kode dua huruf, misalnya en untuk Inggris, id untuk Indonesia, de untuk Jerman, dan sebagainya. Jika kamu ingin mengetahui kode locale lainnya, coba lihat daftar berikutopen in new window.

Apa itu Internationalization?

Singkatnya, internationalization artinya menulis kode yang bisa disesuaikan dengan locale yang digunakan oleh suatu user. Dengan kata lain, internationalization-lah yang menentukan apakah localization akan digunakan atau tidak (lihat di atas). Artinya, meskipun bot kamu bekerja dengan cara yang sama untuk semua orang, namun tampilan pesan yang dikirim akan berbeda dari user ke user. Dengan begitu, bot kamu mampu berbicara menggunakan bahasa yang berbeda.

Kamu telah melakukan Internationalization jika teks yang dikirim oleh bot tidak ditulis secara langsung di coding-an kamu (hard-coded). Sebaliknya, teks-teks tersebut dibaca dari sebuah file secara dinamis. Kamu telah melakukan Internationalization jika format waktu dan tanggal tidak ditulis secara langsung di coding-an kamu. Sebaliknya, gunakan sebuah library untuk menampilkan nilai-nilai tersebut sesuai dengan formatnya masing-masing. Kesimpulannya, jangan menulis sesuatu yang nilainya bisa berubah-ubah (misalnya negara asal atau bahasa yang digunakan user) langsung di coding-an kamu.

Kenapa Kamu Perlu Plugin Ini?

Plugin ini akan memudahkan kamu ketika melakukan internationalization. Ia ditenagai oleh Fluentopen in new window—sebuah sistem localization yang dibuat oleh Mozillaopen in new window. Sistem tersebut memiliki syntax yang canggih serta elegan yang dapat kamu gunakan untuk menulis terjemahan agar terlihat lebih natural dan efisien.

Kamu bisa menambahkan hal-hal yang akan mengalami perubahan berdasarkan locale user ke beberapa file teks yang diletakkan secara berdampingan dengan coding-an kamu. Kemudian, kamu dapat menggunakan plugin ini untuk memuat localization tersebut. Plugin akan secara otomatis menentukan locale yang sedang digunakan oleh user, lalu memberikan pilihan bahasa yang sesuai ke bot kamu.

Kita akan memanggil file-file teks tadi dengan sebutan file terjemahan. Semua konten yang ada di file terjemahan wajib mengikuti aturan syntax Fluent.

Memulai

Di bagian ini, kita akan membahas mengenai pengaturan struktur proyek dan tempat peletakkan file terjemahan. Jika kamu sudah memahaminya, langsung lompat ke sini untuk mengetahui cara menginstal dan menggunakan plugin ini.

Ada beberapa cara untuk menambahkan bahasa lain ke bot kamu. Cara termudah adalah dengan membuat sebuah folder yang berisi file terjemahan Fluent kamu. Biasanya, folder tersebut dinamakan locales/. File-file terjemahan harus memiliki ekstension .ftl (fluent).

Berikut contoh struktur proyek yang bisa kita gunakan:

.
├── bot.ts
└── locales/
    ├── de.ftl
    ├── en.ftl
    ├── id.ftl
    └── ru.ftl

Jika kamu belum begitu paham dengan syntax milik Fluent, kamu bisa membaca panduan yang mereka sediakan: https://projectfluent.org/fluent/guideopen in new window

Berikut contoh file terjemahan untuk bahasa Inggris dengan nama locales/en.ftl:

start = Hi, how can I /help you?
help = 
    Send me some text, and I can make it bold for you.
    You can change my language using the /language command.

Untuk bahasa Indonesia kita namakan dengan locales/id.ftl, isinya akan terlihat seperti ini:

start = Halo, ada yang bisa aku bantu? /help
help = 
    Kirimi aku sebuah teks, lalu aku akan mengubah teks tersebut menjadi tebal.
    Kamu bisa mengubah tampilan bahasa menggunakan perintah /language.

Sekarang kamu bisa menggunakan terjemahannya menggunakan plugin ini di bot kamu. Ia akan tersedia melalui ctx.t:

bot.command("start", async (ctx) => {
  await ctx.reply(ctx.t("start"));
});

bot.command("help", async (ctx) => {
  await ctx.reply(ctx.t("help"));
});

Setiap kali kamu memanggil ctx.t, locale dari context object ctx tersebut akan digunakan untuk mencari terjemahan yang sesuai. Locale negotiator bertugas mencari terjemahan yang sesuai. Untuk penggunaan normal, ia hanya mengembalikan ctx.from.language_code.

Hasilnya, user dengan locale yang berbeda-beda bisa membaca pesan tersebut menggunakan bahasa mereka masing-masing.

Penggunaan

Plugin ini memperoleh locale seorang user dari berbagai macam faktor. Salah satunya melalui ctx.from.language_code, yang disediakan oleh aplikasi milik user.

Selain itu, ada hal-hal lain yang bisa digunakan untuk menentukan locale user. Contohnya, kamu bisa menyimpan locale user di session kamu. Oleh karena itu, plugin ini bisa digunakan dengan dua cara: Dengan Session dan Tanpa Session.

Tanpa Session

Cara ini lebih mudah digunakan karena tidak perlu mengatur session untuk plugin. Kekurangannya adalah kamu tidak bisa menyimpan bahasa yang dipilih oleh user.

Seperti yang telah disebutkan di atas, locale yang digunakan oleh user akan ditentukan berdasarkan ctx.from.language_code, yang diperoleh dari aplikasi Telegram user. Tetapi, jika kamu tidak memiliki terjemahan untuk bahasa tersebut, bahasa bawaanlah yang akan digunakan. Ada kalanya bot tidak dapat mendeteksi bahasa yang digunakan oleh user, jika itu terjadi, bot akan menggunakan bahasa bawaannya juga.

ctx.from.language_code hanya akan terlihat jika user pernah memulai percakapan pribadi dengan bot kamu.

import { Bot, Context } from "grammy";
import { I18n, I18nFlavor } from "@grammyjs/i18n";

// Extend Context dengan Context Flavor I18n
// agar fitur TypeScript dan auto-complete dapat digunakan.
type MyContext = Context & I18nFlavor;

// Buat sebuah bot seperti biasanya.
// Jangan lupa untuk meng-extend context-nya.
const bot = new Bot<MyContext>(""); // <-- taruh token bot kamu di sini (https://t.me/BotFather)

// Buat sebuah instance `I18n`.
// Lanjutkan membaca untuk mengetahui bagaimana cara mengatur instance ini.
const i18n = new I18n<MyContext>({
  defaultLocale: "en", // Lihat di bawah untuk informasi lebih lanjut.
  directory: "locales", // Muat semua file terjemahan dari locales/.
});

// Terakhir, register instance i18n ke bot-nya
// agar pesan bisa langsung diterjemahkan!
bot.use(i18n);

// Semua sudah siap.
// Kamu bisa mengakses terjemahan dengan `t` atau `translate`.
bot.command("start", async (ctx) => {
  await ctx.reply(ctx.t("start-msg"));
});
const { Bot } = require("grammy");
const { I18n } = require("@grammyjs/i18n");

// Buat sebuah bot seperti biasanya.
const bot = new Bot(""); // <-- taruh token bot kamu di sini (https://t.me/BotFather)

// Buat sebuah instance `I18n`.
// Lanjutkan membaca untuk mengetahui bagaimana cara mengatur instance ini.
const i18n = new I18n({
  defaultLocale: "en", // Lihat di bawah untuk informasi lebih lanjut.
  directory: "locales", // Muat semua file terjemahan dari locales/.
});

// Terakhir, register instance i18n ke bot-nya
// agar pesan bisa langsung diterjemahkan!
bot.use(i18n);

// Semua sudah siap.
// Kamu bisa mengakses terjemahan dengan `t` atau `translate`.
bot.command("start", async (ctx) => {
  await ctx.reply(ctx.t("start-msg"));
});
import { Bot, Context } from "https://deno.land/x/grammy@v1.13.1/mod.ts";
import { I18n, I18nFlavor } from "https://deno.land/x/grammy_i18n@v1.0.1/mod.ts";

// Extend Context dengan Context Flavor I18n
// agar fitur TypeScript dan auto-complete dapat digunakan.
type MyContext = Context & I18nFlavor;

// Buat sebuah bot seperti biasanya.
// Jangan lupa untuk meng-extend context-nya.
const bot = new Bot<MyContext>(""); // <-- taruh token bot kamu di sini (https://t.me/BotFather)

// Buat sebuah instance `I18n`.
// Lanjutkan membaca untuk mengetahui bagaimana cara mengatur instance ini.
const i18n = new I18n<MyContext>({
  defaultLocale: "en", // Lihat di bawah untuk informasi lebih lanjut.
  // Muat semua file terjemahan dari locales/. (Tidak bekerja di Deno Deploy)
  directory: "locales",
});

// Untuk Deno Deploy, pakai cara berikut untuk memuat file terjemahan.
// await i18n.loadLocalesDir("locales");

// Terakhir, register instance i18n ke bot-nya
// agar pesan bisa langsung diterjemahkan!
bot.use(i18n);

// Semua sudah siap.
// Kamu bisa mengakses terjemahan dengan `t` atau `translate`.
bot.command("start", async (ctx) => {
  await ctx.reply(ctx.t("start-msg"));
});

ctx.t mengembalikan pesan terjemahan untuk key tertentu. Plugin ini secara otomatis memilih bahasa yang sesuai untuk user, sehingga kamu tidak perlu memikirkannya lagi.

Selamat! Bot kamu sekarang bisa berbicara dalam berbagai macam bahasa! 🌏🎉

Dengan Session

Mari kita asumsikan bot kamu memiliki sebuah perintah /language. Di grammY kita bisa menyimpan data user untuk setiap chat dengan menggunakan session. Agar instance internationalization tahu bahwa session sedang diaktifkan, maka kamu perlu menyetel useSession menjadi true di opsi I18n.

Berikut contoh sederhana penggunaan perintah /language:

import { Bot, Context, session, SessionFlavor } from "grammy";
import { I18n, I18nFlavor } from "@grammyjs/i18n";

interface SessionData {
  __language_code?: string;
}

type MyContext = Context & SessionFlavor<SessionData> & I18nFlavor;

const i18n = new I18n<MyContext>({
  defaultLocale: "en",
  useSession: true, // Menentukan data bahasa user disimpan di session atau tidak
  directory: "locales", // Muat locale dari direktori `locales`.
});

const bot = new Bot<MyContext>(""); // <-- taruh token bot kamu di sini.

// Jangan lupa untuk me-register middleware `session` sebelum
// me-register middleware instace i18n.
bot.use(session({
  initial: () => {
    return {};
  },
}));

// Register middleware i18n
bot.use(i18n);

bot.command("start", async (ctx) => {
  await ctx.reply(ctx.t("greeting"));
});

bot.command("language", async (ctx) => {
  if (ctx.match === "") {
    return await ctx.reply(ctx.t("language.specify-a-locale"));
  }

  // `i18n.locales` berisi semua locale yang telah di-register
  if (!i18n.locales.includes(ctx.match)) {
    return await ctx.reply(ctx.t("language.invalid-locale"));
  }

  // `ctx.i18n.getLocale` mengembalikan locale yang sedang digunakan.
  if (await ctx.i18n.getLocale() === ctx.match) {
    return await ctx.reply(ctx.t("language.already-set"));
  }

  await ctx.i18n.setLocale(ctx.match);
  await ctx.reply(ctx.t("language.language-set"));
});
const { Bot, session } = require("grammy");
const { I18n } = require("@grammyjs/i18n");

const i18n = new I18n({
  defaultLocale: "en",
  useSession: true, // Menentukan data bahasa user disimpan di session atau tidak
  directory: "locales", // Muat locale dari direktori `locales`.
});

const bot = new Bot(""); // <-- taruh token bot kamu di sini.

// Jangan lupa untuk me-register middleware `session` sebelum
// me-register middleware instace i18n
bot.use(
  session({
    initial: () => {
      return {};
    },
  }),
);

// Register middleware i18n
bot.use(i18n);

bot.command("start", async (ctx) => {
  await ctx.reply(ctx.t("greeting"));
});

bot.command("language", async (ctx) => {
  if (ctx.match === "") {
    return await ctx.reply(ctx.t("language.specify-a-locale"));
  }

  // `i18n.locales` berisi semua locale yang telah di-register
  if (!i18n.locales.includes(ctx.match)) {
    return await ctx.reply(ctx.t("language.invalid-locale"));
  }

  // `ctx.i18n.getLocale` mengembalikan locale yang sedang digunakan.
  if ((await ctx.i18n.getLocale()) === ctx.match) {
    return await ctx.reply(ctx.t("language.already-set"));
  }

  await ctx.i18n.setLocale(ctx.match);
  await ctx.reply(ctx.t("language.language-set"));
});
import {
  Bot,
  Context,
  session,
  SessionFlavor,
} from "https://deno.land/x/grammy@v1.13.1/mod.ts";
import { I18n, I18nFlavor } from "https://deno.land/x/grammy_i18n@v1.0.1/mod.ts";

interface SessionData {
  __language_code?: string;
}

type MyContext = Context & SessionFlavor<SessionData> & I18nFlavor;

const i18n = new I18n<MyContext>({
  defaultLocale: "en",
  useSession: true, // Menentukan data bahasa user disimpan di session atau tidak

  // TIDAK BEKERJA di Deno Deploy
  directory: "locales",
});

// Untuk Deno Deploy, pakai cara berikut untuk memuat file terjemahan.
// await i18n.loadLocalesDir("locales");

// Jangan lupa untuk me-register middleware `session` sebelum
// me-register middleware instace i18n
bot.use(
  session({
    initial: () => {
      return {};
    },
  }),
);

// Register middleware i18n
bot.use(i18n);

bot.command("start", async (ctx) => {
  await ctx.reply(ctx.t("greeting"));
});

bot.command("language", async (ctx) => {
  if (ctx.match === "") {
    return await ctx.reply(ctx.t("language.specify-a-locale"));
  }

  // `i18n.locales` berisi semua locale yang telah di-register
  if (!i18n.locales.includes(ctx.match)) {
    return await ctx.reply(ctx.t("language.invalid-locale"));
  }

  // `ctx.i18n.getLocale` mengembalikan locale yang sedang digunakan.
  if ((await ctx.i18n.getLocale()) === ctx.match) {
    return await ctx.reply(ctx.t("language.already-set"));
  }

  await ctx.i18n.setLocale(ctx.match);
  await ctx.reply(ctx.t("language.language-set"));
});

Ketika session diaktifkan, property __language_code di session akan digunakan alih-alih ctx.from.language_code (yang disediakan oleh aplikasi Telegram) selama proses pemilihan bahasa berlangsung. Saat bot kamu mengirim pesan, locale tersebut akan dipilih dari ctx.session.__language_code.

Ada sebuah method setLocale yang bisa kamu gunakan untuk mengatur bahasa yang diinginkan. Pengaturan tersebut akan disimpan di session kamu.

await ctx.i18n.setLocale("id");

Cara di atas serupa dengan mengatur session secara manual, lalu me-renegotiate locale tersebut:

ctx.session.__language_code = "id";
await ctx.i18n.renegotiateLocale();

Me-renegotiate Locale

Ketika kamu menggunakan session atau hal lainnya—selain dari ctx.from.language_code—untuk memilih locale khusus untuk suatu user, ada beberapa situasi dimana kamu berkeinginan untuk mengganti bahasanya ketika menangani sebuah update. Coba lihat kembali contoh yang menggunakan session di atas.

Ketika kamu cuma melakukan

ctx.session.__language_code = "id";

locale yang sedang digunakan tidak akan diperbarui di instance I18n. Alih-alih, ia memperbarui session-nya saja. Akibatnya, perubahan tersebut hanya akan diterapkan untuk update selanjutnya.

Jika kamu ingin perubahan diterapkan saat itu juga, kamu perlu memperbarui perubahan tersebut tepat setelah mengatur bahasa user. Untuk melakukannya, gunakan method renegotiateLocale.

ctx.session.__language_code = "id";
await ctx.i18n.renegotiateLocale();

Setelah itu, setiap kali kita menggunakan method t, bot akan membalas dengan terjemahan bahasa Indonesia untuk pesan tersebut (yang telah ditentukan di locales/id.ftl).

Perlu diingat juga, ketika menggunakan session built-in, kamu bisa mendapatkan hasil yang serupa dengan menggunakan method setLocale.

Mengatur Locale Tanpa Menggunakan Session

Jika suatu saat kamu perlu menentukan locale untuk suatu user, tetapi kamu tidak sedang menggunakan session, maka kamu bisa melakukannya dengan menggunakan method useLocale.

await ctx.i18n.useLocale("id");

Ia akan menggunakan locale yang telah ditentukan untuk terjemahan selanjutnya. Efeknya hanya akan berlaku untuk update yang sedang berlangsung, dan tidak permanen. Kamu bisa menggunakan method ini untuk mengubah terjemahan ketika sedang menangani update (misal, ketika user mengubah bahasa).

Locale Negotiation Khusus

Kamu bisa menggunakan opsi localeNegotiator untuk menentukan sebuah locale negotiator khusus. Opsi ini akan berguna jika kamu hendak menggunakan locale berdasarkan sumber dari luar (misalnya database) atau mengatur secara manual locale yang akan digunakan.

Berikut langkah-langkah bawaan yang dilakukan oleh plugin ketika memilih sebuah locale:

  1. Jika session diaktifkan, baca __language_code dari session tersebut. Jika locale yang dikembalikan valid, gunakan locale tersebut. Jika tidak mengembalikan apa-apa atau locale tidak terdaftar, lanjutkan ke langkah nomor 2.

  2. Baca ctx.from.language_code. Jika locale yang dikembalikan valid, gunakan locale tersebut. Jika tidak mengembalikan apa-apa atau locale tidak terdaftar, lanjutkan ke langkah nomor 3.

    Perlu diingat, ctx.from.language_code hanya akan tersedia jika user pernah menggunakan bot tersebut. Artinya, jika bot melihat user di sebuah grup atau di tempat lain, tetapi user belum pernah menggunakan bot tersebut, bot tidak dapat melihat ctx.from.language_code-nya.

  3. Gunakan konfigurasi bahasa bawaan di I18n. Jika locale yang dikembalikan valid, gunakan locale tersebut. Jika tidak mengembalikan apa-apa atau locale tidak terdaftar, lanjutkan ke langkah nomor 4.

  4. Gunakan bahasa Inggris (en). Plugin akan menggunakan bahasa Inggris sebagai fallback utamanya. Meski begitu, kami menyarankan untuk memiliki sebuah terjemahan walaupun itu bukan syarat utama. Jika locale Inggris tidak tersedia, lanjutkan ke langkah nomor 5.

  5. Jika semua langkah di atas gagal, gunakan {key} alih-alih terjemahan. Kami sangat merekomendasikan untuk menetapkan sebuah locale yang tersedia di terjemahan kamu sebagai defaultLocale di opsi I18n.

Locale Negotiation

Locale negotiation biasanya hanya terjadi sekali selama pemrosesan update Telegram berlangsung. Meski begitu, kamu bisa memanggil kembali negotiator dan menentukan locale yang baru dengan menjalankan ctx.i18n.renegotiateLocale(). Ini akan berguna jika locale mengalami perubahan selama proses update berlangsung.

Berikut sebuah contoh penerapan localeNegotiator dimana kita menggunakan locale dari sebuah session alih-alih menggunakan __language_code. Untuk penggunaan seperti ini, kamu tidak perlu mengubah opsi useSession di I18n menjadi true.

const i18n = new I18n<MyContext>({
  localeNegotiator: (ctx) =>
    ctx.session.locale ?? ctx.from?.language_code ?? "en",
});
const i18n = new I18n({
  localeNegotiator: (ctx) =>
    ctx.session.locale ?? ctx.from?.language_code ?? "en",
});

Jika locale negotiator yang kita buat mengembalikan sebuah locale yang tidak valid, ia akan melakukan fallback dan memilih sebuah locale berdasarkan urutan yang telah dijelaskan di atas.

Me-render Pesan Terjemahan

Mari kita lihat pesan yang sedang di-render berikut.

bot.command("start", async (ctx) => {
  // Panggil "translate" atau "t" helper untuk me-render
  // pesan berdasarkan ID dan parameter tambahan lainnya:
  await ctx.reply(ctx.t("welcome"));
});

Sekarang kamu bisa /start bot-nya. Pesan tersebut kurang lebih akan di-render menjadi seperti ini:

Halo!

Placeables

Terkadang, kamu ingin menaruh sebuah nilai seperti angka dan nama di dalam string-nya. Kamu bisa melakukannya dengan menggunakan placeables.

bot.command("cart", async (ctx) => {
  // Kamu bisa menambahkan placeables sebagai object kedua.
  await ctx.reply(ctx.t("cart-msg", { items: 10 }));
});

Kita bisa menyebut object { items: 10 } sebagai translation context dari sebuah string cart-msg.

Jalankan perintah /cart:

Kamu saat ini memiliki 10 item di keranjang kamu.

Coba ganti nilai variable items untuk melihat perubahan pada pesan yang telah di-render! Jangan lupa untuk membaca dokumentasi Fluent, khususnya materi placeablesopen in new window.

Global Placeables

Memiliki beberapa placeables di semua terjemahan akan sangat membantu pekerjaan kita. Contohnya, jika kamu hendak mencantumkan nama user di banyak tempat, akan sangat melelahkan untuk menulis translation context { name: ctx.from.first_name } di berbagai tempat.

Global placeables datang menyelamatkan! Coba lihat contoh berikut:

const i18n = new I18n<MyContext>({
  defaultLocale: "en",
  directory: "locales",
  // Tentukan placeables yang tersedia secara global:
  globalTranslationContext(ctx) {
    return { name: ctx.from?.first_name ?? "" };
  },
});

bot.use(i18n);

bot.command("start", async (ctx) => {
  // `name` bisa digunakan tanpa perlu menulisnya lagi!
  await ctx.reply(ctx.t("welcome"));
});

Menambahkan Terjemahan

Kita bisa memuat terjemahan dengan tiga cara.

Memuat Locale Menggunakan Opsi directory

Cara termudah untuk menambahkan terjemahan ke instance I18n adalah dengan mengumpulkan semua file terjemahan ke dalam sebuah direktori lalu masukkan nama direktori tersebut di opsi directory,

const i18n = new I18n({
  directory: "locales",
});

Memuat Locale dari Sebuah Direktori

Cara ini serupa dengan mengatur opsi directory. Cukup kumpulkan semua file terjemahan ke dalam sebuah folder lalu muat dengan cara seperti ini:

const i18n = new I18n();

await i18n.loadLocalesDir("locales"); // versi async
i18n.loadLocalesDirSync("locales-2"); // versi sync

Perlu diperhatikan bahwa beberapa lingkungan kerja tertentu mengharuskan kamu untuk menggunakan async. Contohnya, Deno Deploy tidak mendukung pengoperasian file menggunakan cara synchronous.

Memuat Satu Locale Saja

Kita juga bisa menambahkan satu terjemahan saja ke instance I18n. Kamu bisa melakukannya baik dengan menentukan path file ke terjemahan menggunakan

const i18n = new I18n();

await i18n.loadLocale("en", { filePath: "locales/en.ftl" }); // versi async
i18n.loadLocaleSync("id", { filePath: "locales/id.ftl" }); // versi sync

maupun memuat konten terjemahan secara langsung sebagai sebuah string

const i18n = new I18n();

// versi async
await i18n.loadLocale("en", {
  source: `greeting = Hello { $name }!
language-set = Language has been set to English!`,
});

// versi sync
i18n.loadLocaleSync("id", {
  source: `greeting = Halo { $name }!
language-set = Bahasa telah diganti menjadi bahasa Indonesia!`,
});

Menyimak Teks yang Telah Di-localize

Kita telah berhasil mengirim pesan yang sudah di-localize ke user. Sekarang, mari kita belajar cara menyimak pesan yang dikirim oleh user. Di grammY, kita biasanya menggunakan handler bot.hears untuk menyimak pesan yang datang. Namun, karena kita berbicara mengenai internationalization, maka di bagian ini kita akan mempelajari bagaimana menyimak pesan yang datang dalam bentuk localize.

Fitur ini akan bermanfaat jika bot kamu memiliki keyboard custom berisi teks yang sudah di-localize.

Berikut contoh sederhana untuk menyimak pesan yang dikirim menggunakan custom keyboard yang sudah di-localize. Alih-alih menggunakan handler bot.hears, kita akan menggunakan bot.filter yang dikombinasikan dengan middleware hears.

import { hears } from "@grammyjs/i18n";

bot.filter(hears("back-to-menu-btn"), async (ctx) => {
  await ctx.reply(ctx.t("main-menu-msg"));
});
const { hears } = require("@grammyjs/i18n");

bot.filter(hears("back-to-menu-btn"), async (ctx) => {
  await ctx.reply(ctx.t("main-menu-msg"));
});
import { hears } from "https://deno.land/x/grammy_i18n@v1.0.1/mod.ts";

bot.filter(hears("back-to-menu-btn"), async (ctx) => {
  await ctx.reply(ctx.t("main-menu-msg"));
});

Function helper hears dapat membuat bot kamu mampu menyimak pesan yang ditulis menggunakan locale suatu user.

Langkah Berikutnya

Ringkasan Plugin