Ajukan pertanyaan Anda dan dapatkan ringkasan dokumen dengan merujuk halaman ini dan penyedia AI pilihan Anda
Konten halaman ini diterjemahkan menggunakan AI.
Lihat versi terakhir dari konten aslinya dalam bahasa InggrisJika Anda memiliki ide untuk meningkatkan dokumentasi ini, silakan berkontribusi dengan mengajukan pull request di GitHub.
Tautan GitHub ke dokumentasiSalin Markdown dokumentasi ke clipboard
Format Pesan ICU: Sintaksis dan Bagian yang Sering Menjebak Pengembang
ICU MessageFormat adalah sintaksis string yang memungkinkan terjemahan memiliki logika percabangannya sendiri: bentuk jamak, bentuk berdasarkan gender, serta pemformatan angka dan tanggal. Gagasan utamanya adalah bahwa tata bahasa merupakan ranah penerjemah, bukan pengembang yang menulis if (count === 1). Artikel ini mengulas sintaksis dasar, aspek ketergantungan bahasa yang menggagalkan implementasi sederhana, dan bagaimana ekosistem JavaScript mengelolanya.
Daftar Isi
Masalah Nyata di Lapangan
Berikut adalah kode yang hampir selalu ditulis pertama kali oleh pengembang:
Salin kode ke clipboard
Cara ini berfungsi dengan baik dalam bahasa Inggris tetapi gagal di hampir semua bahasa lain:
- Bahasa Rusia dan Polandia membutuhkan tiga atau empat bentuk, bukan dua.
- Bahasa Indonesia dan Jepang hanya memerlukan satu bentuk, dan spasi yang digabungkan secara manual menjadi tidak tepat.
- Bahasa Arab memerlukan enam bentuk jamak, dan angka itu sendiri harus ditampilkan dalam sistem penomoran lokal.
- Bahasa Prancis menyisipkan spasi yang tidak dapat diputus (non-breaking space) sebelum tanda baca tertentu, yang langsung rusak oleh
+ " ".
Masalah yang lebih mendasar adalah kalimat telah terpotong menjadi beberapa fragmen. Penerjemah hanya melihat kata item dan items tanpa konteks serta tanpa kemampuan untuk mengatur ulang susunan kata dalam kalimat. ICU MessageFormat mengatasi hal ini dengan mempertahankan seluruh kalimat dalam satu string tunggal yang dapat diterjemahkan, sembari memberi penerjemah operator percabangan.
Argumen Sederhana
Unit terkecil adalah placeholder di dalam kurung kurawal tunggal:
Salin kode ke clipboard
Saat proses pemformatan, Anda meneruskan { name: "Alice" } dan menghasilkan Hello, Alice!. Kurung kurawal adalah satu-satunya karakter khusus. Untuk mencetak tanda kurung kurawal secara harfiah, bungkus dengan tanda kutip tunggal: '{'.
Itulah keseluruhan fitur interpolasi. Segala hal lain dalam ICU dibangun di atas mekanisme dasar ini.
Bentuk Jamak (plural)
Operator plural memilih cabang berdasarkan nilai numerik:
Salin kode ke clipboard
Tiga poin penting yang harus dipahami:
#digantikan oleh nilaicountyang telah diformat sesuai lokal. Misalnya,1234menjadi1,234dalamen-USdan1.234dalamid-ID.otherbersifat wajib. Setiap implementasi ICU akan memunculkan error atau gagal validasi jikaothertidak disertakan. Ini adalah fallback ketika tidak ada kategori yang cocok.=0,=1, … mencocokkan nilai persis dan dievaluasi sebelum kategori CLDR. Gunakan untuk teks kasus khusus (seperti "Tidak ada pesan"), bukan sebagai penggantione.
Salin kode ke clipboard
offset
offset:n mengurangi n dari nilai angka sebelum pemilihan kategori dan penggantian #. Fitur ini berguna untuk pola seperti "Alice dan 3 orang lainnya menyukai ini":
Salin kode ke clipboard
Dengan count: 4, tanda # akan menghasilkan angka 3. Fitur offset sangat berguna namun tingkat dukungannya bervariasi di beberapa runtime, jadi selalu periksa lingkungan Anda sebelum mengandalkannya.
Kategori Jamak Bergantung pada Bahasa
Ini adalah bagian yang paling sering disalahpahami. Nama kategori zero, one, two, few, many, other bukanlah wadah universal yang berlaku sama untuk setiap bahasa. Setiap lokal menggunakan subset tertentu yang ditentukan oleh aturan jamak CLDR, dan aturan ini bersifat gramatikal, bukan sekadar intuisi matematika.
Buka tabel dalam modal untuk melihat semua isi data dengan jelas
| Bahasa | Tag | Kategori yang Digunakan | Total |
|---|---|---|---|
| Indonesia | id | other | 1 |
| Jepang | ja | other | 1 |
| Tionghoa | zh | other | 1 |
| Inggris | en | one, other | 2 |
| Jerman | de | one, other | 2 |
| Prancis | fr | one, many, other | 3 |
| Ceko | cs | one, few, many, other | 4 |
| Polandia | pl | one, few, many, other | 4 |
| Rusia | ru | one, few, many, other | 4 |
| Arab | ar | zero, one, two, few, many, other | 6 |
| Wales | cy | zero, one, two, few, many, other | 6 |
Dua konsekuensi yang sering mengejutkan:
onetidak selalu berarti angka "1". Dalam bahasa Rusia,onemencakup 1, 21, 31, 101: angka apa pun yang berakhiran 1 kecuali yang berakhiran 11. Dalam bahasa Prancis, angka0juga masuk ke dalam kategorione.- Menambahkan kategori pada teks sumber bahasa Inggris tidak berpengaruh apa pun. Pesan bahasa Inggris hanya memerlukan
onedanother; sedangkan terjemahan bahasa Polandia memerlukan empat cabang, dan struktur tersebut harus berada di string bahasa Polandia, bukan di bahasa Inggris. Format yang memaksa semua bahasa memiliki struktur kunci yang sama akan menimbulkan kendala di sini.
Anda dapat memverifikasi perilaku runtime secara langsung tanpa menginstal dependensi apa pun:
Salin kode ke clipboard
Objek bawaan Intl.PluralRules menyediakan data CLDR di semua browser modern dan Node.js. Pustaka mana pun yang mendukung aturan jamak CLDR hampir selalu memanggil API bawaan ini.
select dan selectordinal
select membuat percabangan berdasarkan string apa pun: gender, peran pengguna, status, atau tingkatan paket.
Salin kode ke clipboard
Kunci dicocokkan secara harfiah dan cabang other juga wajib ada di sini. select adalah alat yang tepat ketika struktur kalimat bergantung pada nilai enum, karena setiap bahasa memiliki perbedaan dalam menentukan nilai mana yang memengaruhi tata bahasanya.
selectordinal memiliki bentuk yang sama dengan plural, tetapi menggunakan aturan jamak ordinal (ke-1, ke-2, dll.) yang tabelnya berbeda dari angka kardinal:
Salin kode ke clipboard
Bahasa Inggris menggunakan empat kategori ordinal (1st, 2nd, 3rd, 4th) meskipun hanya menggunakan dua kategori kardinal. Perbedaan inilah yang mendasari pemisahan kedua operator tersebut.
Argumen Angka, Tanggal, dan Waktu
ICU dapat memformat nilai yang diinterpolasi secara langsung:
Salin kode ke clipboard
Format modern yang disarankan adalah skeleton, yang diperkenalkan pada ICU 60 dan ditandai dengan awalan ::. Skeleton jauh lebih ekspresif daripada gaya penamaan lama:
Salin kode ke clipboard
Dukungan terhadap skeleton bervariasi di seluruh ekosistem. FormatJS mengimplementasikannya secara penuh, sementara beberapa runtime lain hanya menerima format lama seperti number, currency atau date, long. Pastikan untuk memeriksa lingkungan Anda sebelum menerapkannya di produksi.
Struktur Bersarang dan Keterbacaan
Sintaksis ICU bersifat modular. Cabang jamak dapat memuat select, yang pada gilirannya dapat memuat cabang jamak lainnya:
Salin kode ke clipboard
Ini adalah contoh klasik ICU sekaligus argumen utama untuk menghindari struktur bersarang yang terlalu dalam. Di atas dua tingkat, penerjemah mulai rentan melakukan kesalahan kurung kurawal dan editor TMS menjadi kurang efektif. Batasi hingga maksimal dua tingkat; jika membutuhkan tingkat ketiga, pisahkan kalimat menjadi dua pesan terpisah.
Dukungan ICU di Pustaka JavaScript
Buka tabel dalam modal untuk melihat semua isi data dengan jelas
| Pustaka | Dukungan ICU | Yang Sebenarnya Ditulis |
|---|---|---|
| react-intl (FormatJS) | Asli, penuh | String ICU lengkap, termasuk skeleton dan tag rich-text |
| next-intl | Asli | String ICU melalui paket intl-messageformat dari FormatJS |
| i18next | Perlu plugin | Akhiran key_one / key_other dan {{name}}; ICU via i18next-icu |
| vue-i18n | Sebagian / mandiri | Interpolasi {name} dan cabang jamak yang dipisahkan garis vertikal |
Angular ($localize) | Sebagian | ICU plural / select di dalam template, diekstrak ke XLIFF |
Catatan penting terkait tabel:
- Sintaksis default i18next bukanlah ICU, dan ini bukan kekurangan. Akhiran kunci (
item_one,item_few) dipetakan ke kategoriIntl.PluralRulesdan sering kali lebih mudah diedit dalam file JSON datar. Namun,selectdan percabangan bersarang bukan bagian dari fitur intinya, sehingga Anda harus menambahkani18next-icuatau menulis logika dalam kode. - Bentuk jamak vue-i18n dengan pipa secara default menggunakan fungsi aturan per lokal, bukan kategori CLDR. Fitur ini bekerja dengan baik, tetapi aturan jamak berada dalam konfigurasi aplikasi dan bukan di dalam data.
- FormatJS adalah implementasi acuan di dunia JS. Ketika pengembang membicarakan "ICU MessageFormat" dalam konteks JavaScript, biasanya yang dimaksud adalah format yang diterima oleh FormatJS.
- Dukungan penuh ICU membawa dampak ukuran bundle. Parser dan penanganan skeleton menambah sekitar 10 KB JavaScript terkompresi. Lihat mengapa ICU tidak dibuat untuk JavaScript.
Pendekatan Intlayer
Intlayer tidak menggunakan DSL berbasis string. Operator percabangan adalah fungsi TypeScript dalam file deklarasi konten bertipe data ketat, sehingga setiap lokal hanya mendeklarasikan kategori yang benar-benar dibutuhkan oleh tata bahasanya:
Salin kode ke clipboard
Salin kode ke clipboard
Pemetaan ke konsep ICU sangat jelas dan langsung:
Buka tabel dalam modal untuk melihat semua isi data dengan jelas
| Konstruksi ICU | Padanan di Intlayer |
|---|---|
{name} | insert("Hello {{name}}"), atau deteksi otomatis |
{count, plural, …} | plural({ one, few, many, other }) |
{value, select, …} | select({ draft, published, fallback }) |
cabang gender di select | gender({ male, female, fallback }) |
cabang boolean di select | cond({ true, false }) |
| rentang angka (non-CLDR) | enu({ "0": …, ">5": …, fallback: … }) |
{n, number, ::currency/EUR} | useCurrency()(1234.5, { currency: "EUR" }) |
Operator plural menyerahkan pemilihan kategori kepada Intl.PluralRules, sehingga tabel CLDR di atas berlaku tanpa perubahan. Logika pemformatan tetap terpisah: angka, tanggal, mata uang, dan daftar ditangani melalui hooks pemformatan, alih-alih dicampur ke dalam teks pesan.
Batasan praktis:
- Intlayer memerlukan tahap build: compiler mengekstrak deklarasi saat proses build aplikasi. Jika Anda menginginkan JSON biasa yang dimuat saat runtime, itu adalah model yang berbeda.
- Saat ini cabang
pluralbelum dapat memuatt()secara bersarang di dalamnya; Anda membungkuspluraldi dalamt(), bukan sebaliknya. - Ekosistemnya lebih baru dibandingkan i18next, dengan integrasi bawaan TMS yang masih terus berkembang.
Jika Anda beralih dari basis kode yang sudah memuat string ICU asli, adapter kompatibilitas react-intl dapat langsung menguraikannya: plural, select, selectordinal, #, dan argumen lama number, date, time. Skeleton dan offset: belum didukung oleh parser tersebut dan perlu diperiksa saat migrasi. Sementara itu, adapter i18next menyelesaikan bentuk akhiran (key_one, key_male) melalui Intl.PluralRules.
Kesalahan yang Sering Terjadi
- Menuliskan logika jamak langsung di kode JS. Ungkapan
count === 1 ? a : bmenghasilkan keluaran yang salah untuk 8 dari 10 bahasa pada tabel di atas. Sekali operator ternary berada di kode, penerjemah tidak dapat memperbaikinya. - Menggabungkan fragmen terjemahan. Urutan kata, kesesuaian tata bahasa, dan spasi sebelum tanda baca bergantung pada lokal. Selalu pertahankan kalimat secara utuh.
- Melewatkan cabang
other. Ini adalah persyaratan spesifikasi resmi, bukan opsi opsional. Sebagian besar parser akan menolak pesan tersebut, dan sisanya tidak akan menampilkan apa pun. - Menganggap semua bahasa memiliki kategori yang sama. Fakta bahwa sumber bahasa Inggris hanya memiliki
onedanothertidak berarti bahasa Polandia hanya memiliki dua cabang. Biarkan setiap lokal mendeklarasikan cabangnya sendiri. Lihat deklarasi konten per lokal. - Menggunakan
=1padahal yang dimaksud adalahone.=1hanya cocok persis dengan angka 1. Dalam bahasa Rusia, angka 21 membutuhkan kategorione, dan aturan=1tidak akan pernah aktif untuk angka tersebut. - Menempatkan
#di luar cabang plural. Simbol#hanya memiliki arti khusus di dalampluralatauselectordinal. Di tempat lain, simbol ini diperlakukan sebagai karakter tanda pagar biasa. - Lupa bahwa
#sudah diformat. Jika Anda membutuhkan angka murni tanpa pemisah ribuan lokal, gunakan interpolasi argumen berdasarkan namanya.
Pelajari Lebih Lanjut
Komentar
Belum ada komentar. Jadilah yang pertama membagikan pemikiran Anda.
