Skip to content

Internasionalisasi (I18n)

Workflow I18n

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

Deteksi locale

Ambil bahasa dari user, chat, atau konfigurasi middleware.

Helper terjemahan

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

Fallback

Sediakan default locale agar translation yang hilang tidak merusak reply.

Middleware I18n bawaan untuk respons bot multibahasa dengan deteksi lokal otomatis.

Memulai Cepat

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

const bot = new Bot(process.env.BOT_TOKEN!);

const i18n = new I18n('id'); // lokal default

// Muat kamus/dictionary lokal
i18n.loadLocale('en', {
    selamat_datang: 'Welcome {name}!',
    bantuan: 'Available commands: /start, /help',
    selamat_tinggal: 'Goodbye!',
});

i18n.loadLocale('id', {
    selamat_datang: 'Selamat datang {name}!',
    bantuan: 'Perintah tersedia: /start, /bantuan',
    selamat_tinggal: 'Sampai jumpa!',
});

i18n.loadLocale('ar', {
    selamat_datang: 'مرحباً {name}!',
    bantuan: 'الأوامر المتاحة: /start, /help',
    selamat_tinggal: 'وداعاً!',
});

bot.use(i18n.middleware());

Menggunakan Terjemahan

typescript
bot.command('start', async ctx => {
    const teks = ctx.i18n!.t('selamat_datang', {
        name: ctx.from?.first_name || 'Teman',
    });
    await ctx.reply(teks);
});

bot.command('bantuan', async ctx => {
    await ctx.reply(ctx.i18n!.t('bantuan'));
});

Variabel Template

Gunakan placeholder {variable}:

typescript
i18n.loadLocale('id', {
    pesanan_dikonfirmasi: 'Pesanan #{id} dikonfirmasi. Total: Rp{jumlah}.',
    sambutan_vip: 'Halo {nama}! Kamu adalah anggota {level}.',
});

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

Deteksi Bahasa Otomatis

Middleware secara otomatis membaca ctx.from?.language_code dari pengaturan klien Telegram. Jika lokal belum dimuat, akan fallback ke default:

Pengguna dengan Telegram en-US → menggunakan lokal 'en'
Pengguna dengan Telegram id    → menggunakan lokal 'id'
Lokal tidak ada                → menggunakan lokal default

Muat dari File JSON

typescript
import { readFileSync } from 'fs';

const loadLocaleFile = (lang: string) =>
    JSON.parse(readFileSync(`./locales/${lang}.json`, 'utf-8'));

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

Contoh locales/id.json:

json
{
    "selamat_datang": "Selamat datang {name}!",
    "pilih_menu": "Silakan pilih menu:",
    "error_umum": "Terjadi kesalahan. Coba lagi nanti."
}

Override Bahasa Manual

Izinkan pengguna memilih bahasa secara manual:

typescript
// Simpan pilihan bahasa di session
bot.use(session({ initial: () => ({ lang: 'id' }) }));

bot.use(async (ctx, next) => {
    // Override lokal berdasarkan session pengguna
    if (ctx.session?.lang) {
        ctx.i18n?.setLocale(ctx.session.lang);
    }
    await next();
});

bot.command('bahasa', async ctx => {
    await ctx.reply('Pilih bahasa:', {
        reply_markup: Markup.inlineKeyboard([
            [
                Markup.button.callback('🇮🇩 Indonesia', 'lang_id'),
                Markup.button.callback('🇬🇧 English', 'lang_en'),
            ],
        ]),
    });
});

bot.action(/^lang_(\w+)$/, async ctx => {
    const lang = ctx.match![1];
    ctx.session.lang = lang;
    ctx.i18n?.setLocale(lang);
    await ctx.answerCbQuery('✅ Bahasa diperbarui');
    await ctx.reply(ctx.i18n!.t('selamat_datang', { name: ctx.from?.first_name }));
});

Released under the ISC License.