Skip to content

Internasionalisasi (I18n)

Workflow I18n

Lokalkan reply bot dengan deteksi locale, dictionary, dan helper di handler.

Deteksi locale

Baca metadata bahasa Telegram dan fallback ke locale default.

Helper terjemahan

Gunakan `ctx.i18n` dari handler setelah middleware dipasang.

Variabel template

Sisipkan nilai ke string terjemahan.

Helper bawaan I18n menyimpan dictionary di memori dan menyuntikkan ctx.i18n.t() ke handler.

Memulai Cepat

ts
import { Bot, I18n } from 'vibegram';

const bot = new Bot(process.env.BOT_TOKEN!);
const i18n = new I18n('id');

i18n.loadLocale('en', {
    welcome: 'Welcome {name}!',
    help: 'Available commands: /start, /help',
});

i18n.loadLocale('id', {
    welcome: 'Selamat datang {name}!',
    help: 'Perintah tersedia: /start, /help',
});

bot.use(i18n.middleware());

Menggunakan Terjemahan

ts
bot.command('start', async ctx => {
    const text = ctx.i18n!.t('welcome', {
        name: ctx.from?.first_name ?? 'Teman',
    });

    await ctx.reply(text);
});

bot.command('help', ctx => ctx.reply(ctx.i18n!.t('help')));

Jika key tidak ditemukan, t() mengembalikan key itu sendiri.

Variabel Template

Gunakan placeholder {variable}:

ts
i18n.loadLocale('id', {
    order_confirmed: 'Pesanan #{id} dikonfirmasi. Total: Rp{amount}.',
});

ctx.i18n!.t('order_confirmed', { id: '1234', amount: '99.000' });
// "Pesanan #1234 dikonfirmasi. Total: Rp99.000."

Placeholder adalah substitusi string sederhana. Escape nilainya sendiri sebelum menaruhnya di pesan HTML atau Markdown berformat.

Cara Kerja Deteksi Bahasa

Middleware membaca ctx.from?.language_code, mengambil dua karakter pertama, dan fallback ke locale default dari new I18n(defaultLang).

text
Bahasa Telegram en-US -> locale "en"
Bahasa Telegram id    -> locale "id"
Locale tidak ada      -> locale default

Muat dari File JSON

ts
import { readFileSync } from 'node:fs';

function loadLocaleFile(lang: string) {
    return JSON.parse(readFileSync(`./locales/${lang}.json`, 'utf8'));
}

i18n.loadLocale('en', loadLocaleFile('en'));
i18n.loadLocale('id', loadLocaleFile('id'));

Contoh locales/id.json:

json
{
    "welcome": "Selamat datang {name}!",
    "choose_menu": "Silakan pilih menu:",
    "generic_error": "Terjadi kesalahan. Coba lagi nanti."
}

Override Bahasa Manual

Simpan pilihan bahasa user di session dan override ctx.i18n setelah middleware i18n bawaan berjalan.

ts
bot.use(session({ initial: () => ({ lang: undefined as string | undefined }) }));
bot.use(i18n.middleware());

bot.use(async (ctx, next) => {
    const lang = ctx.session?.lang;
    if (lang) {
        ctx.i18n = {
            locale: lang,
            t: (key, placeholders) => i18n.t(lang, key, placeholders),
        };
    }

    await next();
});

bot.action(/^lang_(\w+)$/, async ctx => {
    const lang = ctx.match?.[1];
    if (!lang) return;

    ctx.session.lang = lang;
    await ctx.answerCbQuery('Bahasa diperbarui');
    await ctx.reply(i18n.t(lang, 'welcome', { name: ctx.from?.first_name ?? 'Teman' }));
});

Released under the ISC License.