Arsitektur internasionalisasi untuk aplikasi berbasis chat: tentukan kunci string yang stabil, aturan plural, dan satu alur terjemahan yang konsisten di web dan mobile.

Hal pertama yang rusak bukanlah kode. Itu adalah kata-kata.
Aplikasi berbasis chat sering dimulai sebagai prototipe cepat: Anda mengetik “Tambahkan tombol bertulis Simpan”, UI muncul, dan Anda melanjutkan. Beberapa minggu kemudian, Anda ingin bahasa Spanyol dan Jerman, dan Anda menemukan label “sementara” itu tersebar di layar, komponen, email, dan pesan kesalahan.
Perubahan teks juga biasanya lebih sering daripada perubahan kode. Nama produk diubah, teks legal berubah, onboarding ditulis ulang, dan dukungan meminta pesan kesalahan yang lebih jelas. Jika teks berada langsung di dalam kode UI, setiap perubahan kata kecil menjadi rilis yang berisiko, dan Anda akan melewatkan tempat di mana gagasan yang sama diungkapkan secara berbeda.
Berikut gejala awal yang menandakan Anda membangun utang terjemahan:
Contoh realistis: Anda membangun CRM sederhana di Koder.ai. Aplikasi web menampilkan “Deal stage”, aplikasi mobile menampilkan “Pipeline step”, dan toast error mengatakan “Invalid status”. Bahkan jika ketiganya diterjemahkan, pengguna akan merasa aplikasi tidak konsisten karena konsepnya tidak cocok.
“Konsisten” bukan berarti “karakter yang sama di mana-mana”. Maksudnya:
Setelah Anda memperlakukan teks sebagai data produk, bukan dekorasi, menambah bahasa tidak lagi menjadi panik melainkan rutinitas pembangunan.
Internasionalisasi (i18n) adalah pekerjaan agar sebuah aplikasi bisa mendukung banyak bahasa tanpa perlu menulis ulang. Lokalisasi (l10n) adalah konten aktual untuk bahasa dan wilayah tertentu, misalnya Prancis (Kanada) dengan kata-kata, format tanggal, dan nada yang tepat.
Tujuan sederhana: setiap teks yang terlihat pengguna dipilih berdasarkan kunci yang stabil, bukan diketik langsung ke kode UI. Jika Anda bisa mengubah satu kalimat tanpa membuka komponen React atau widget Flutter, Anda ada di jalur yang benar. Ini inti arsitektur internasionalisasi untuk aplikasi berbasis chat, di mana mudah tidak sengaja mengirimkan salinan yang tertanam yang dihasilkan selama sesi chat.
Teks yang terlihat pengguna lebih luas dari yang banyak tim duga. Itu mencakup tombol, label, error validasi, empty state, tips onboarding, push notification, email, ekspor PDF, dan pesan apa pun yang bisa dilihat atau didengar pengguna. Biasanya tidak termasuk log internal, nama kolom database, ID event analytics, feature flag, atau output debug khusus admin.
Di mana terjemahan sebaiknya disimpan? Dalam praktik, seringkali di frontend dan backend, dengan batasan yang jelas.
Kesalahan yang harus dihindari adalah mencampur tanggung jawab. Jika backend mengembalikan kalimat bahasa Inggris yang sudah jadi untuk error UI, frontend tidak bisa melokalisasinya dengan bersih. Pola yang lebih baik: backend mengembalikan kode error (dan mungkin parameter aman), dan klien memetakan kode itu ke pesan terlokalisasi.
Kepemilikan copy adalah keputusan produk, bukan detail teknis. Putuskan sejak awal siapa yang boleh mengubah kata dan menyetujui nada.
Jika produk yang memegang copy, perlakukan terjemahan seperti konten: versioning, review, dan beri produk cara aman untuk meminta perubahan. Jika engineering yang memegang copy, buat aturan bahwa string UI baru harus disertai kunci dan terjemahan default sebelum bisa dirilis.
Contoh: jika flow signup Anda menampilkan “Create account” di tiga layar berbeda, buat satu kunci yang dipakai di mana-mana. Itu menjaga makna konsisten, mempercepat penerjemah, dan mencegah perubahan kata kecil menjadi pembersihan multi-layar nanti.
Kunci adalah kontrak antara UI dan terjemahan Anda. Jika kontrak itu terus berubah, Anda akan mendapat teks hilang, perbaikan tergesa, dan kata-kata yang tidak konsisten di web dan mobile. Arsitektur internasionalisasi yang baik untuk aplikasi berbasis chat dimulai dengan satu aturan: kunci harus mendeskripsikan makna, bukan kalimat Inggris saat ini.
Gunakan ID stabil sebagai kunci (misalnya billing.invoice.payNow) alih-alih menulis seluruh copy (misalnya Pay now). Kunci berupa kalimat akan rusak ketika seseorang mengubah kata, menambah tanda baca, atau mengganti huruf kapital.
Polanya yang praktis dan mudah dibaca: screen (atau domain) + komponen + intent. Jaga agar membosankan dan dapat diprediksi.
Contoh:
auth.login.titleauth.login.emailLabelbilling.checkout.payButtonnav.settingserrors.network.offlineTentukan kapan harus menggunakan kembali kunci versus membuat yang baru dengan bertanya: “Apakah maknanya identik di setiap tempat?” Gunakan kembali kunci untuk aksi yang benar-benar generik, tapi pisahkan kunci saat konteks berubah. Misalnya, “Save” di layar profil mungkin merupakan aksi sederhana, sementara “Save” di editor kompleks mungkin perlu nada yang berbeda di beberapa bahasa.
Simpan teks UI bersama di namespace khusus agar tidak terduplikasi antar layar. Ember kategori yang bekerja baik:
common.actions.* (save, cancel, delete)common.status.* (loading, success)common.fields.* (search, password)errors.* (validation, network)nav.* (tabs, menu items)Ketika kata berubah tapi makna tetap sama, pertahankan kunci dan hanya perbarui nilai terjemahan. Itu tujuan utama ID stabil. Jika makna berubah (meskipun sedikit), buat kunci baru dan biarkan yang lama tetap ada sampai Anda yakin tidak terpakai. Ini menghindari ketidaksesuaian “diam-diam” di mana terjemahan lama masih ada tetapi sekarang salah.
Contoh kecil dari alur gaya Koder.ai: chat Anda menghasilkan aplikasi React web dan Flutter mobile. Jika keduanya menggunakan common.actions.save, Anda mendapat terjemahan yang konsisten di mana-mana. Tapi jika web menggunakan profile.save dan mobile menggunakan account.saveButton, keduanya akan menyimpang seiring waktu, meskipun bahasa Inggrisnya terlihat sama hari ini.
Perlakukan bahasa sumber (seringnya Inggris) sebagai satu-satunya sumber kebenaran. Simpan di satu tempat, review seperti kode, dan hindari membiarkan string muncul di komponen acak “sebentar saja”. Ini cara tercepat untuk menghindari copy UI yang tertanam dan pekerjaan ulang nanti.
Aturan sederhana: aplikasi hanya boleh menampilkan teks dari sistem i18n. Jika seseorang butuh copy baru, mereka menambahkan kunci dan pesan default dulu, lalu memakai kunci itu di UI. Ini menjaga arsitektur internasionalisasi untuk aplikasi berbasis chat tetap stabil meskipun fitur berpindah-pindah.
Jika Anda mengirimkan web dan mobile, Anda ingin satu katalog kunci bersama, plus ruang bagi tim fitur bekerja tanpa saling mengganggu. Susunan praktis:
Jaga agar kunci identik di seluruh platform, walau implementasinya berbeda (React di web, Flutter di mobile). Jika Anda menggunakan platform seperti Koder.ai untuk menghasilkan kedua aplikasi dari chat, mengekspor source code lebih mudah dikelola ketika kedua proyek mengacu pada nama kunci dan format pesan yang sama.
Terjemahan berubah seiring waktu. Perlakukan perubahan seperti perubahan produk: kecil, direview, dan dapat dilacak. Review yang baik fokus pada makna dan reuse, bukan sekadar ejaan.
Untuk mencegah kunci menyimpang antar tim, buat kepemilikan berdasarkan fitur (billing., auth.), dan jangan pernah mengganti nama kunci hanya karena kata-katanya berubah. Perbarui pesannya, pertahankan kuncinya. Kunci adalah identifier, bukan copy.
Aturan plural berbeda tiap bahasa, jadi pola sederhana Inggris (1 vs lainnya) cepat rusak. Beberapa bahasa punya bentuk terpisah untuk 0, 1, 2-4, dan banyak lagi. Lainnya mengubah seluruh kalimat, bukan hanya kata benda. Jika Anda menanam logika plural di UI dengan if-else, Anda akan menggandakan copy dan melewatkan kasus tepi.
Pendekatan yang lebih aman: pertahankan satu pesan fleksibel per gagasan dan biarkan lapisan i18n memilih bentuk yang tepat. Pesan gaya ICU dibuat untuk ini. Mereka menempatkan keputusan tata bahasa pada terjemahan, bukan pada komponen Anda.
Berikut contoh kecil yang menutupi kasus yang sering terlupakan:
itemsCount = "{count, plural, =0 {No items} one {# item} other {# items}}"
Satu kunci itu menangani 0, 1, dan semuanya. Penerjemah bisa menggantinya dengan bentuk plural yang benar untuk bahasanya tanpa Anda menyentuh kode.
Saat Anda perlu kata yang bergantung gender atau peran, hindari membuat kunci terpisah seperti welcome_male dan welcome_female kecuali produk benar-benar memerlukannya. Gunakan select sehingga kalimat tetap menjadi satu kesatuan:
welcomeUser = "{gender, select, female {Welcome, Ms. {name}} male {Welcome, Mr. {name}} other {Welcome, {name}}}"
Untuk menghindari masalah kasus tata bahasa, pertahankan kalimat seutuh mungkin. Jangan menyambung potongan seperti "{count} " + t('items') karena banyak bahasa tidak bisa mengubah urutan kata seperti itu. Lebih baik satu pesan yang mencakup angka, kata benda, dan kata-kata di sekitarnya.
Aturan sederhana yang bekerja baik di aplikasi berbasis chat (termasuk proyek Koder.ai): jika sebuah kalimat mengandung angka, orang, atau status, buatlah menggunakan ICU sejak hari pertama. Biayanya sedikit lebih di awal tetapi menghemat banyak utang terjemahan nantinya.
Jika aplikasi React web dan Flutter mobile masing-masing menyimpan file terjemahan sendiri, keduanya akan menyimpang. Tombol yang sama akhirnya memakai kata berbeda, sebuah kunci berarti satu hal di web dan hal lain di mobile, dan tiket dukungan mulai menyebut “aplikasi mengatakan X tapi website mengatakan Y”.
Perbaikan paling sederhana sekaligus terpenting: pilih satu format sumber kebenaran dan perlakukan seperti kode. Untuk kebanyakan tim, itu berarti satu set file locale bersama (misalnya JSON menggunakan pesan gaya ICU) yang dikonsumsi web dan mobile. Ketika Anda membangun cepat lewat chat dan generator, ini semakin penting karena mudah tanpa sengaja membuat teks baru di dua tempat.
Pengaturan praktis adalah paket kecil “i18n” atau folder yang berisi:
React dan Flutter lantas menjadi konsumen. Mereka tidak boleh menemukan kunci baru secara lokal. Dalam alur kerja gaya Koder.ai (React web, Flutter mobile), Anda bisa menghasilkan kedua klien dari set kunci yang sama, dan menjaga perubahan dalam review layaknya perubahan kode lain.
Keselarasan backend bagian dari cerita yang sama. Error, notifikasi, dan email tidak seharusnya menjadi kalimat bahasa Inggris yang ditulis manual di Go. Sebaliknya, kembalikan kode error stabil (mis. auth.invalid_password) plus parameter aman. Kemudian klien memetakan kode itu ke teks terjemahan. Untuk email yang dirender server-side, server bisa merender template menggunakan kunci dan file locale yang sama.
Buat satu buku aturan kecil dan tegakkan di code review:
Untuk mencegah kunci duplikat dengan makna berbeda, tambahkan bidang “deskripsi” (atau file komentar) untuk penerjemah dan Anda di masa depan. Contoh: billing.trial_days_left harus menjelaskan apakah ditampilkan sebagai banner, email, atau keduanya. Satu kalimat itu sering menghentikan penggunaan ulang “cukup mirip” yang menciptakan utang terjemahan.
Konsistensi ini adalah tulang punggung arsitektur internasionalisasi untuk aplikasi berbasis chat: satu kosakata bersama, banyak permukaan, dan tidak ada kejutan saat Anda meluncurkan bahasa berikutnya.
Arsitektur internasionalisasi yang baik untuk aplikasi berbasis chat dimulai sederhana: satu set kunci pesan, satu sumber kebenaran untuk copy, dan aturan yang sama di web dan mobile. Jika Anda membangun cepat (misalnya dengan Koder.ai), struktur ini menjaga kecepatan tanpa menimbulkan utang terjemahan.
Pilih locale Anda sejak awal dan putuskan apa yang terjadi ketika terjemahan hilang. Pilihan umum: tampilkan bahasa pengguna bila tersedia, jika tidak fallback ke Inggris, dan log kunci yang hilang agar bisa diperbaiki sebelum rilis berikutnya.
Lalu terapkan ini:
billing.plan_name.pro atau auth.error.invalid_password. Gunakan kunci yang sama di mana-mana.t("key") di komponen. Di Flutter, gunakan wrapper lokalisasi dan panggil lookup berbasis kunci yang sama di widget. Tujuannya adalah kunci yang sama, bukan library yang sama.if (count === 1) yang berserakan.Akhirnya, uji satu bahasa dengan kata-kata lebih panjang (Jerman klasik) dan satu dengan tanda baca berbeda. Ini cepat memperlihatkan tombol yang meluber, judul yang terbungkus buruk, dan tata letak yang mengasumsikan panjang kata bahasa Inggris.
Jika Anda menyimpan terjemahan di folder bersama (atau paket yang dihasilkan) dan memperlakukan perubahan copy seperti perubahan kode, web dan mobile Anda tetap konsisten meski fitur dibuat cepat lewat chat.
String UI yang diterjemahkan hanya setengah masalah. Sebagian besar aplikasi juga menampilkan nilai yang berubah seperti tanggal, harga, jumlah, dan nama. Jika Anda memperlakukan nilai itu seperti teks biasa, Anda akan mendapatkan format aneh, zona waktu yang salah, dan kalimat yang terdengar “aneh” di banyak bahasa.
Mulailah dengan memformat angka, mata uang, dan tanggal menggunakan aturan locale, bukan kode kustom. Pengguna di Prancis mengharapkan “1 234,50 €”, sementara pengguna AS mengharapkan “$1,234.50”. Hal yang sama berlaku untuk tanggal: “03/04/2026” ambigu, tapi format locale membuatnya jelas.
Zona waktu adalah perangkap berikutnya. Server sebaiknya menyimpan timestamp dalam bentuk netral (biasanya UTC), tapi pengguna mengharapkan melihat waktu di zona mereka. Misalnya: order dibuat pukul 23:30 UTC mungkin “besok” untuk seseorang di Tokyo. Tentukan satu aturan per layar: tampilkan waktu lokal pengguna untuk event personal, dan tampilkan zona waktu bisnis tetap untuk hal seperti jendela pengambilan toko (dan beri label dengan jelas).
Hindari membangun kalimat dengan menggabungkan fragmen terjemahan. Itu merusak tata bahasa karena urutan kata berbeda per bahasa. Alih-alih:
"{count} " + t("items") + " " + t("in_cart")
gunakan satu pesan dengan placeholder, misalnya: "{count} items in your cart". Penerjemah kemudian bisa menyusun ulang kata dengan aman.
RTL bukan hanya arah teks. Alur tata letak terbalik, beberapa ikon perlu dimirror (seperti panah kembali), dan konten campuran (Arab plus kode produk Inggris) bisa tampil dalam urutan yang mengejutkan. Uji layar nyata, bukan hanya satu label, dan pastikan komponen UI mendukung perubahan arah.
Jangan pernah menerjemahkan apa yang ditulis pengguna (nama, alamat, tiket dukungan, pesan chat). Anda bisa menerjemahkan label di sekitarnya, dan memformat metadata (tanggal, angka), tapi kontennya sendiri harus tetap apa adanya. Jika Anda menambahkan auto-translation nanti, jadikan fitur eksplisit dengan toggle "asli/terjemahan".
Contoh praktis: aplikasi yang dibangun Koder.ai mungkin menampilkan “{name} renewed on {date} for {amount}”. Pertahankan sebagai satu pesan, format {date} dan {amount} berdasarkan locale, dan tampilkan dalam zona waktu pengguna. Pola ini mencegah banyak utang terjemahan.
Aturan cepat yang biasanya mencegah bug:
Utang terjemahan biasanya dimulai sebagai “hanya satu string cepat” dan berubah menjadi minggu pembersihan. Dalam proyek berbasis chat, ini bisa terjadi lebih cepat karena teks UI dihasilkan di dalam komponen, form, dan bahkan pesan backend.
Masalah paling mahal adalah yang menyebar di seluruh aplikasi dan sulit ditemukan.
Bayangkan aplikasi React web dan Flutter mobile sama-sama menampilkan banner billing: “You have 1 free credit left”. Seseorang mengubah teks web menjadi “You have one credit remaining” dan mempertahankan kunci sebagai keseluruhan kalimat. Mobile masih memakai kunci lama. Sekarang Anda punya dua kunci untuk satu konsep, dan penerjemah melihat keduanya.
Pola yang lebih baik adalah kunci stabil (mis. billing.creditsRemaining) dan pluralisasi dengan pesan ICU agar tata bahasa benar di banyak bahasa. Jika Anda menggunakan alat vibe-coding seperti Koder.ai, tambahkan aturan awal: setiap teks yang terlihat pengguna yang dihasilkan di chat harus masuk ke file terjemahan, bukan di dalam komponen atau error server. Kebiasaan kecil ini melindungi arsitektur internasionalisasi untuk aplikasi berbasis chat saat proyek tumbuh.
Saat internasionalisasi terasa berantakan, biasanya karena dasar-dasarnya tidak ditulis. Daftar cek kecil dan satu contoh konkret bisa menjaga tim Anda (dan Anda di masa depan) dari utang terjemahan.
Berikut daftar cek cepat untuk setiap layar baru:
billing.invoice.paidStatus, bukan billing.greenLabel).Contoh sederhana: Anda meluncurkan layar billing dalam bahasa Inggris, Spanyol, dan Jepang. UI berisi: “Invoice”, “Paid”, “Due in 3 days”, “1 payment method” / “2 payment methods”, dan total seperti “$1,234.50”. Jika Anda membangun ini dengan arsitektur internasionalisasi untuk aplikasi berbasis chat, Anda mendefinisikan kunci sekali (dibagikan di web dan mobile), dan setiap bahasa hanya mengisi nilai. “Due in {days} days” menjadi pesan ICU, dan pemformatan uang berasal dari formatter yang peka terhadap locale, bukan dari koma yang tertulis keras.
Gelar dukungan bahasa per fitur, bukan sebagai rewrite besar:
Dokumentasikan dua hal agar fitur baru tetap konsisten: aturan penamaan kunci Anda (dengan contoh) dan “definisi selesai” untuk string (tidak ada copy tertanam, ICU untuk plural, pemformatan tanggal/angka, ditambahkan ke katalog bersama).
Langkah berikutnya: jika Anda membangun di Koder.ai, gunakan Mode Perencanaan untuk mendefinisikan layar dan kunci sebelum menghasilkan UI. Lalu gunakan snapshot dan rollback untuk beriterasi aman pada copy dan terjemahan di web dan mobile tanpa risiko rilis yang rusak.