Steven
Steven8 menit baca

Merilis Tiga Puluh Bahasa Tanpa Jaring Pengaman

GeekBye v1.8.3 memasang react-i18next dan menerjemahkan seluruh aplikasi ke 30 bahasa. Bagian library-nya rutin. Bagian menariknya adalah apa yang hilang: tidak ada pemeriksaan paritas kunci dan tidak ada extractor string — sehingga bahasa Inggris hardcoded lolos, sebuah salah ketik bahasa Denmark terlanjur dirilis, dan changelog tidak bisa sepakat apakah aplikasi berbicara 28, 29, atau 30 bahasa.

Engineering
i18n
Desktop
GeekBye Releases
Merilis Tiga Puluh Bahasa Tanpa Jaring Pengaman

Beberapa rilis adalah sebuah fitur. GeekBye v1.8.3 tampak seperti itu — "aplikasi kini berbicara 30 bahasa" — tetapi fitur itu adalah bagian yang mudah, dan bukan itu yang dibahas tulisan ini. Antara 17 dan 19 Februari 2026, dua pull request memasang react-i18next ke dalam aplikasi, merefaktor setiap string Inggris hardcoded menjadi panggilan terjemahan, dan membundel tiga puluh berkas locale. Itu kerja sungguhan, tetapi itu jenis kerja yang memang dirancang untuk dijadikan rutin oleh sebuah library. Rekayasa yang menarik adalah segala hal yang tidak dibangun rilis ini — jaring pengaman yang mestinya menangkap apa yang dirilisnya dalam keadaan rusak.

Pemasangannya adalah 80% yang mudah

Commit infrastruktur menambahkan react-i18next di atas i18next dan melakukan hal yang konvensional: sebuah i18n/index.ts yang memanggil initReactI18next, mengimpor secara statis ketiga puluh JSON locale, dan mendaftarkannya di bawah satu objek resources. Tanpa lazy loading — setiap bahasa ikut dalam bundle. String terjemahan tinggal di src/i18n/locales/*.json sebagai peta datar ber-namespace titik: sidebar.meetings, startMeeting.start, satu kunci untuk satu string.

Migrasi dari bahasa Inggris hardcoded ke t('key') dilakukan dengan cara yang jujur, kelompok komponen demi kelompok komponen, dan kamu bisa membaca sapuannya di log commit: sidebar, navigasi, dan chat lebih dulu; lalu settings, login, dan onboarding; lalu meetings, dashboard, toast, dan tooltip navbar. Setiap commit mengganti satu batch string literal dengan panggilan terjemahan. Dua puluh sembilan berkas non-Inggris mendarat dalam satu commit — sebuah drop sembilan ribu baris yang menerjemahkan sumber bahasa Inggris ke segalanya dari bahasa Bulgaria hingga Vietnam.

Tak satu pun dari itu sulit dilakukan dengan benar, karena melakukannya dengan salah itu berisik: sebuah provider yang hilang membuat crash, sebuah JSON yang cacat gagal di-parse, sebuah import yang buruk mematahkan build. Library memberimu pagar pengaman untuk kesalahan-kesalahan mekanis. Yang tidak diberikannya adalah pagar pengaman untuk kesalahan yang benar-benar terjadi.

Tiga pengaturan bahasa, dan mengapa itu benar

Sebelum sampai ke apa yang rusak, ada satu hal yang benar-benar dilakukan dengan tepat oleh v1.8.3, karena ini adalah pembedaan yang banyak aplikasi ratakan padahal tak seharusnya. Setelah rilis ini, GeekBye punya tiga pengaturan bahasa yang independen:

  • Bahasa respons AI (output_language) — bahasa apa yang dipakai asisten untuk menjawab. Yang tertua dari ketiganya, sejak November 2025.
  • Bahasa transkrip (transcriptLanguage) — bahasa apa yang dipakai mesin suara untuk menuliskan mikrofonmu. Dipasang beberapa rilis sebelumnya, di v1.7.6.
  • Bahasa aplikasi (app_language) — bahasa dari tombol, menu, dan onboarding. Baru di v1.8.3.

Ini benar-benar sumbu yang berbeda. Seorang developer di Berlin mungkin ingin antarmuka berbahasa Jerman, jawaban AI berbahasa Inggris (karena itu bahasa dari dokumen yang ia tempel), dan transkripsi berbahasa Inggris (karena rapatnya berbahasa Inggris). Meleburkan itu semua menjadi satu pengaturan "bahasa" akan salah bagi orang itu, dan langkah onboarding yang ditambahkan di rilis ini menyajikan ketiganya sebagai dropdown terpisah justru karena alasan itu.

Sentuhan yang menyenangkan adalah jalur upgrade-nya. Sebuah migrasi sekali jalan menyalin output_language setiap pengguna yang sudah ada ke kunci app_language yang baru pada peluncuran pertama setelah memperbarui, dan provider menyelesaikan bahasa melalui rantai fallback — app_language, lalu output_language, lalu 'en'. Jadi pengguna yang sudah memberi tahu aplikasi bahwa mereka ingin jawaban AI berbahasa Spanyol terbangun dengan antarmuka berbahasa Spanyol, alih-alih direset ke bahasa Inggris dan dibuat mencari-cari pengaturannya. Menyemai preferensi baru dari preferensi lama yang berkaitan adalah kebaikan kecil yang berbiaya satu migrasi dan menyelamatkan setiap pengguna yang meng-upgrade dari satu gangguan kecil.

Render ulang onboarding yang enggan terjadi

Ada satu bug sejati yang layak diangkat dari kerja i18n ini, karena ini adalah jebakan React yang akan ditemui siapa pun yang melakukan pergantian bahasa saat runtime. Wizard onboarding membangun sebagian daftar opsinya di dalam sebuah useMemo. Ketika kamu mengubah bahasamu di langkah bahasa itu sendiri, UI-nya seharusnya langsung menggambar ulang dalam bahasa yang baru — dan tidak, karena t tidak ada di dependency array milik memo itu. Fungsi terjemahan berganti identitas ketika bahasa berubah; jika nilai ter-memoize-mu dibangun dari t tetapi tidak bergantung padanya, React dengan senang hati memberimu versi basi dari bahasa sebelumnya. Perbaikannya muncul dua kali di log — sekali untuk wizard, sekali untuk daftar dropdown settings — yang memberitahumu bahwa ini jenis kesalahan yang kamu buat di setiap tempat kamu me-memoize konten terjemahan sampai kamu belajar untuk selalu mencantumkan t.

Onboarding juga membawa satu kerutan yang tidak disebutkan changelog: karena ini adalah codebase white-label, ada dua pohon onboarding untuk diterjemahkan — sebuah wizard GeekBye dan sebuah wizard Pavleur — yang tinggal di bawah namespace kunci paralel onboarding.* dan onboarding.pavleur.*. Setiap string onboarding diterjemahkan dua kali, ke dalam dua suara merek, di seluruh dua puluh sembilan bahasa.

Apa yang tak disadari build sedang hilang

Inilah bagian yang membuat ini sebuah pelajaran alih-alih sebuah checklist. v1.8.3 tidak punya cara otomatis untuk mengekstrak string hardcoded dan tidak punya pemeriksaan CI untuk paritas kunci lintas locale. Jadi definisi "selesai" adalah "seseorang mengunjungi komponen-komponen yang ia ingat dan membungkus string-string yang ia lihat." Definisi itu bocor.

Dua minggu setelah rilis, sebuah commit pembersihan mendarat dengan pesan "translate all hardcoded English strings across 10 components into 30 languages." Sepuluh komponen — formulir lapor-masalah, tab ringkasan dan metrik, tab laporan, konten transkrip dan chat, prompt batas-penggunaan, pesan chat, tombol salin-kode, tombol aksi mengambang — telah dirilis di v1.8.3 dengan tetap berbahasa Inggris kepada semua orang, di semua bahasa. Build siapa pun tak ada yang gagal. Tak ada tes yang berubah merah. Seorang pengguna Jerman cuma melihat bahasa Inggris di tab laporan, dan satu-satunya pendeteksi adalah manusia yang akhirnya melihatnya.

Ketiadaan yang sama menghasilkan rasa malu yang lebih kecil. Sebuah terjemahan bahasa Denmark dirilis dengan kata yang salah — Luk application helt alih-alih Luk applikationen helt — dan ditambal di rilis berikutnya, karena tidak ada gerbang peninjau penutur asli dan tidak ada cara bagi pipeline untuk tahu. Kunci "quit app" hilang dari batch awal dan diisi-ulang beberapa hari kemudian. Dan setiap fitur yang dirilis sesudahnya — sebuah preset tombol modifier, mute mikrofon, chip rekap, opasitas overlay — menyeret commit "terjemahkan kunci-kunci baru ke 29 locale"-nya sendiri di belakangnya, selamanya, karena tak ada apa pun yang menegakkan invarian itu secara otomatis.

Kamu bahkan bisa mengukur kekacauannya di pesan-pesan commit. Tiga puluh berkas locale yang sama itu digambarkan, dari rilis ke rilis, sebagai "30 bahasa," "29 bahasa," dan — di satu commit — "28 locale." Tak ada yang ditambahkan atau dihapus; ada tiga puluh berkas di setiap tag dari v1.8.3 hingga v2. Angkanya melayang karena tak ada satu sumber kebenaran untuk "berapa banyak bahasa yang kita rilis," jadi setiap penulis commit menghitung dengan tangan, kadang memasukkan bahasa Inggris sebagai sebuah bahasa dan kadang sebagai sumbernya. Sebuah changelog yang tak bisa menjaga hitungannya sendiri tetap stabil adalah sinyal kecil nan jujur bahwa hal yang digambarkannya tidak sedang ditegakkan oleh sebuah mesin.

Ranjau pluralisasi

Satu hal lagi yang layak ditandai, bukan karena ia rusak dengan berisik melainkan karena ini jenis bug yang diundang oleh susunan ini dan tak akan memperingatkanmu. Pluralisasi di berkas-berkas locale ini dilakukan secara manual, dengan kunci berpasangan: meetings.meetingCount dan meetings.meetingCountPlural, profiles.filesAttached dan filesAttachedPlural. Itu adalah pemisahan tunggal/jamak bahasa Inggris yang rapi. Ia juga salah untuk sebagian dari bahasa-bahasa yang kini diklaim didukung aplikasi. Bahasa Rusia, Polandia, dan Ceko punya tiga atau empat bentuk jamak tergantung angkanya — "1 file," "2 files," "5 files," dan "21 files" bisa mengambil akhiran kata yang berbeda. Skema dua-kunci tunggal/jamak tak bisa mengungkapkan itu, jadi jumlah-jumlah itu tampil salah secara gramatikal. i18next punya mesin jamak sungguhan persis untuk ini; pasangan manual itu menghindarinya, dan tak ada commit yang mengakui celah itu. Ini adalah padanan pluralisasi dari kebocoran string-hardcoded: tak terlihat oleh build, terlihat hanya oleh penutur asli.

Tiga hal yang diajarkan rilis ini

  1. Library adalah 80% yang mudah; perkakas adalah 20% yang sulit. Memasang react-i18next dan menerjemahkan string secara massal adalah masalah yang sudah terpecahkan. Menjaga tiga puluh berkas tetap dalam paritas selamanya tidak — dan itu butuh sebuah extractor untuk string hardcoded dan sebuah pemeriksaan CI untuk kunci yang hilang, yang keduanya tak dirilis oleh sebuah library untukmu. Bangun itu sebelum kamu mengklaim "i18n penuh," atau kamu telah mengklaim sebuah invarian yang tak punya cara untuk kamu pertahankan.
  2. Pisahkan pengaturan bahasa yang memang berbeda. Bahasa UI, bahasa transkrip, dan bahasa respons AI adalah tiga sumbu, dan v1.8.3 benar memberi masing-masing kuncinya sendiri — dan lebih benar lagi menyemai yang baru dari yang lama yang berkaitan lewat migrasi, sehingga meng-upgrade tak berbiaya apa pun bagi pengguna.
  3. Hitungan changelog-mu adalah metrik disiplin. Ketika set berkas yang sama adalah 28, 29, dan 30 bahasa di tiga commit, angkanya bukan masalahnya — sumber kebenaran yang hilang itulah masalahnya. Jika sebuah mesin tidak menghitung bahasa-bahasamu, tak seorang pun menghitungnya dengan cara yang sama dua kali.

Untuk bab sebelumnya dalam kisah v1, mendesain ulang dashboard di sekitar satu grafik gelombang (v1.8.2); dan untuk keseluruhan alurnya, anatomi merilis software sampai sempurna.