Internationalization, disingkat i18n, adalah menyiapkan kode supaya aplikasinya bisa dipakai dalam bahasa dan kebiasaan daerah mana pun tanpa kodenya diubah. Localization, disingkat l10n, adalah mengisi satu bahasa dan daerah itu: terjemahan, format harga, format tanggal. Bayangin Bu Sri menyiapkan Homestay Kabut di Dieng untuk tamu dari luar negeri. Memasang colokan universal di tiap kamar adalah i18n: dikerjakan sekali, waktu membangun. Menaruh adaptor, buku panduan berbahasa Jepang, dan jam dinding yang benar untuk tamu dari Jepang adalah l10n: dikerjakan per tamu, tanpa membongkar dinding.
🧪 Tebakan cepat: Kartu pesan Kamar Teras di halaman Bu Sri berisi judul, harga, tanggal check-in, tiga tombol lama menginap, total, tombol pesan, dan satu catatan. Dari semua teks di kartu itu, berapa yang cukup diterjemahkan kata per kata untuk tamu dari Jepang: hampir semua, sekitar separuh, atau kurang dari separuh? Jawabannya ada di bagian "Menghitung teks hard-coded di halaman Bu Sri".
i18n, l10n, g11n, dan translation
Empat istilah ini sering tertukar. Angka di tengah singkatannya cuma jumlah huruf: i, 18 huruf, n adalah internationalization; l, 10 huruf, n adalah localization; g, 11 huruf, n adalah globalization.
| Istilah | Artinya | Di halaman Bu Sri |
|---|---|---|
| Translation | Mengganti kata ke bahasa lain | "Pesan kamar" jadi "予約する" |
| l10n (localization) | Menyesuaikan halaman untuk satu locale: terjemahan, plus format uang, tanggal, jumlah, dan arah tulisan | Untuk tamu Jepang: harga IDR 700,000, tanggal 12月12日, "2泊" |
| i18n (internationalization) | Menyiapkan arsitektur kode supaya l10n bisa dikerjakan tanpa mengubah kode | Teks pindah ke kamus per bahasa, angka dan tanggal lewat Intl, file disimpan UTF-8, CSS memakai logical properties |
| g11n (globalization) | Keputusan dan kerja untuk melayani pasar lain, termasuk i18n dan l10n | Bu Sri memutuskan menerima tamu dari Jepang dan Mesir, termasuk cara bayar dan jam balas chat |
- i18n dikerjakan developer, sekali, di arsitektur kode. l10n dikerjakan per bahasa, sering oleh penerjemah, dan bisa diulang untuk bahasa baru tanpa developer menyentuh kode.
- Translation cuma sebagian dari l10n. Halaman yang kata-katanya sudah bahasa Jepang tapi masih menulis "Rp 700.000" dan "2 malam" belum selesai di-lokalisasi.
- Pelajaran UI/UX "Internationalization (i18n)" sudah membawa kartu ini ke bahasa Inggris dengan
Intl.NumberFormat,Intl.DateTimeFormat, danIntl.PluralRules. Track ini melanjutkan dari situ.
Locale: kode bahasa, aksara, dan wilayah
Locale adalah kode yang menyebut bahasa dan kebiasaan daerah yang dipakai. Web memakai format BCP 47, disebut juga language tag: bagian-bagian yang disambung tanda minus.
| Tag | Bahasa | Aksara | Wilayah | Contoh pemakaian |
|---|---|---|---|---|
id-ID |
id Indonesia |
ID Indonesia |
Halaman asli Bu Sri | |
ja-JP |
ja Jepang |
JP Jepang |
Tamu dari Jepang | |
zh-Hant-TW |
zh Tionghoa |
Hant Han tradisional |
TW Taiwan |
Tag dengan tiga bagian |
sr-Latn |
sr Serbia |
Latn Latin |
Bahasa Serbia yang ditulis huruf Latin | |
es-419 |
es Spanyol |
419 Amerika Latin |
Wilayah boleh berupa kode angka |
- Bahasa: 2 atau 3 huruf kecil (ISO 639). Aksara: 4 huruf, huruf pertamanya kapital (ISO 15924). Wilayah: 2 huruf kapital (ISO 3166) atau 3 angka.
- Aksara dan wilayah boleh dilewati.
Intl.Localemengisinya dengan pilihan yang paling umum:
new Intl.Locale('ja').maximize().toString(); // "ja-Jpan-JP"
new Intl.Locale('ar').maximize().toString(); // "ar-Arab-EG"
new Intl.Locale('sr').maximize().toString(); // "sr-Cyrl-RS": tanpa Latn, bahasa Serbia ditulis huruf Kiril
new Intl.Locale('zh-TW').maximize().toString(); // "zh-Hant-TW"
Intl.getCanonicalLocales('ID-id'); // ["id-ID"]: huruf besar dan kecilnya dirapikan
Hasilnya sama di Chromium 147, Firefox 146, WebKit 26.4 (mesin Safari), dan Node 22.22.1.
maximize()menambah aksara dan wilayah yang paling mungkin,minimize()membuang yang bisa ditebak:new Intl.Locale('id-ID').minimize().toString()memberi"id".- Pemisahnya tanda minus.
id_ID(gaya Java,setlocaledi PHP, dan Linux) bukan BCP 47:new Intl.NumberFormat('id_ID')melemparRangeError. Pesannya "Invalid language tag: id_ID" di Chrome,invalid language tag: "id_ID"di Firefox, dan "invalid language tag: id_ID" di Safari.
Empat locale untuk Homestay Kabut
Track ini membawa halaman Bu Sri ke empat locale. Tiap locale dipilih karena menguji hal yang berbeda:
id-ID, bahasa sumber. Bu Sri menulis semuanya dalam bahasa Indonesia dulu.en-US, untuk backpacker dari mana saja, termasuk Pak Hadi dari pelajaran UI/UX yang browser-nya berbahasa Inggris. Jamaknya dua bentuk: 1 night, 2 nights.ja-JP, untuk tamu dari Jepang yang datang melihat matahari terbit di Sikunir. Aksaranya CJK (Tionghoa, Jepang, Korea), tanpa spasi antar kata, tanpa bentuk jamak (2泊), dan tiap hurufnya 3 byte di UTF-8.ar-EG, untuk tamu dari Mesir. Ditulis kanan ke kiri (RTL), angkanya angka Arab timur (٧٠٠٬٠٠٠), dan jamaknya punya enam kategori: zero, one, two, few, many, other.
Kenapa ar-EG, bukan ar-SA? Wilayah mengubah hasil. Untuk ar-SA, Safari 26.4 memakai kalender Hijriah dan menulis 12 Desember 2026 sebagai ٣ رجب ١٤٤٨ هـ, sementara Chrome dan Firefox memakai kalender Masehi. Untuk ar-EG, ketiganya memakai kalender Masehi.
Kartu yang sama di empat locale, diformat Intl di Chromium 147 (harga dengan maximumFractionDigits: 0, tanggal dengan dateStyle: 'medium', timeStyle: 'short', dan timeZone: 'Asia/Jakarta'):
id-ID |
en-US |
ja-JP |
ar-EG |
|
|---|---|---|---|---|
| Total 2 malam | Rp 700.000 | IDR 700,000 | IDR 700,000 | ٧٠٠٬٠٠٠ IDR |
| Check-in | 12 Des 2026, 14.00 | Dec 12, 2026, 2:00 PM | 2026/12/12 14:00 | ١٢/١٢/٢٠٢٦، ٢:٠٠ م |
| Kategori jamak untuk 2 | other | other | other | two |
| Tombol 2 malam | 2 malam | 2 nights | 2泊 | ليلتان |
| Arah tulisan | kiri ke kanan | kiri ke kanan | kiri ke kanan | kanan ke kiri |
Kata di tombol berasal dari kamus terjemahan; Intl.PluralRules cuma memberi tahu kategori mana yang dipakai. Bahasa Arab punya bentuk khusus untuk tepat dua (dual): ليلتان artinya "dua malam".
Yang berubah selain kata
| Aspek | Contoh di halaman Bu Sri |
|---|---|
| Angka dan uang | Pemisah ribuan titik di id-ID, koma di en-US dan ja-JP, dan ٬ dengan angka ٠ sampai ٩ di ar-EG. "Rp" di depan angka untuk id-ID, "IDR" di belakang untuk ar-EG. |
| Tanggal dan jam | "Sabtu, 12 Desember 2026 pukul 14.00" di id-ID, "Saturday, December 12, 2026 at 2:00 PM" di en-US, "2026年12月12日土曜日 14:00" di ja-JP. |
| Jumlah | 2 malam, 2 nights, 2泊, ليلتان: bentuk katanya ikut jumlah. |
| Arah | Bahasa Arab ditulis kanan ke kiri, jadi garis hijau di awal kartu pindah ke kanan. |
| Urutan abjad | ['Zahra', 'Ömer', 'andi'].sort() memberi ["Zahra", "andi", "Ömer"]. Bahasa Swedia memang menaruh Ö sesudah Z, bahasa Jerman menaruhnya bersama O. |
| Nama orang | Banyak orang Indonesia bernama satu kata, dan nama Jepang ditulis marga dulu (山田 太郎). Kolom wajib "Nama depan" plus "Nama belakang" menyulitkan keduanya. |
| Alamat | Alamat Jepang ditulis dari yang besar ke yang kecil, diawali kode pos 〒; alamat Indonesia punya RT/RW dan kelurahan. |
| Panjang teks | "Pesan kamar, bayar di tempat" dan "Book now, pay at the homestay" beda lebar, seperti yang diukur di pelajaran UI/UX. |
Menghitung teks hard-coded di halaman Bu Sri
Hard-coded artinya teksnya ditulis langsung di dalam kode, bukan diambil dari kamus. Ini kartu Bu Sri sebelum di-i18n:
<html lang="id">
<head>
<title>Kamar Teras · Homestay Kabut</title>
<style>.card { padding-left: 20px; border-left: 4px solid #15803d; }</style>
</head>
<body>
<section class="card">
<h1>Kamar Teras</h1>
<p>Rp 350.000 / malam</p>
<p>Check-in 12 Des 2026, 14.00</p>
<div role="group" aria-label="Lama menginap">
<button>1 malam</button>
<button aria-pressed="true">2 malam</button>
<button>3 malam</button>
</div>
<p id="total">Total 2 malam: Rp 700.000</p>
<button>Pesan kamar, bayar di tempat</button>
<p>Gratis batal sampai 3 hari sebelum check-in.</p>
</section>
<script>
function pilih(n) {
document.getElementById('total').textContent =
'Total ' + n + ' malam: Rp ' + (350000 * n).toLocaleString('id-ID');
}
</script>
</body>
</html>
Ada 11 teks yang dibaca atau didengar tamu:
| Jenis | Teks | Jumlah |
|---|---|---|
| Cuma kata | <title>, judul "Kamar Teras", aria-label "Lama menginap", tombol "Pesan kamar, bayar di tempat" |
4 |
| Kata plus angka, uang, tanggal, atau jumlah | "Rp 350.000 / malam", "Check-in 12 Des 2026, 14.00", "1 malam", "2 malam", "3 malam", "Total 2 malam: Rp 700.000", "Gratis batal sampai 3 hari sebelum check-in." | 7 |
Cuma 4 dari 11 yang bisa diterjemahkan kata per kata, jadi kurang dari separuh. Itu jawaban tebakannya. Tujuh sisanya butuh Intl atau aturan jamak, karena angka, tanggal, dan bentuk katanya berubah per locale. Lalu ada 3 tempat lagi di luar teks:
lang="id"di<html>, yang harus ikut locale.- Script yang menyambung
'Total ' + n + ' malam: Rp 'dan menguncitoLocaleString('id-ID'). Potongan kalimat seperti ini gak bisa diterjemahkan: bahasa Inggris butuh "Total for 2 nights", bahasa Arab butuh bentuk dual. - CSS
padding-leftdanborder-left, yang gak ikut pindah ke kanan untukar-EG.
Dua yang paling sering terlupa: <title> dan aria-label. Keduanya gak kelihatan di kartu, tapi muncul di tab browser dan dibacakan screen reader.
⚠️ Jebakan yang sering ketemu
- Menganggap i18n sama dengan terjemahan. Kata-katanya sudah bahasa Jepang, tapi harganya masih "Rp 700.000" dan jumlahnya "2 malam": itu baru setengah jalan.
- Menulis locale dengan garis bawah.
id_IDmelemparRangeErrordiIntl. Pakaiid-ID. - Lupa teks yang gak kelihatan.
<title>,aria-label,alt,placeholder, dan pesan error juga teks hard-coded. - Locale tanpa wilayah untuk format.
armemakai angka 0 sampai 9,ar-EGmemakai ٠ sampai ٩, danar-SAdi Safari memakai kalender Hijriah. Sebut locale lengkap untuk format, lalu cek di lebih dari satu browser.
TL;DR: i18n (i, 18 huruf, n: internationalization) menyiapkan arsitektur kode supaya bisa multi-bahasa tanpa kodenya diubah; l10n (localization) mengisi satu locale: terjemahan plus format uang, tanggal, jumlah, dan arah tulisan. Translation cuma bagian dari l10n, dan g11n adalah keputusan melayani pasar lain. Locale ditulis BCP 47 dengan tanda minus: bahasa, aksara, wilayah (id-ID, zh-Hant-TW, sr-Latn); id_ID melempar RangeError. Track ini memakai id-ID (sumber), en-US, ja-JP (CJK, tanpa jamak), dan ar-EG (RTL, angka ٠ sampai ٩, enam kategori jamak). Yang berubah bukan cuma kata: angka, uang, tanggal, jamak, arah, urutan abjad, nama, alamat. Kartu Bu Sri punya 11 teks hard-coded, dan cuma 4 yang bisa diterjemahkan kata per kata; ditambah lang, potongan kalimat di script, dan CSS kiri kanan.