
Kolmekümne keele tarnimine ilma turvavõrguta
GeekBye v1.8.3 ühendas react-i18next ja tõlkis kogu rakenduse 30 keelde. Teegi osa oli rutiin. Huvitav on see, mis puudus: polnud võtmete pariteedi kontrolli ega stringiekstraktorit — nii et kõvakodeeritud inglise keel lipsas läbi, taani kirjaviga jõudis toodangusse ja muudatuste logi ei suutnud kokku leppida, kas rakendus räägib 28, 29 või 30 keelt.
Mõni väljalase on funktsioon. GeekBye v1.8.3 näeb välja nagu üks — "rakendus räägib nüüd 30 keelt" — aga funktsioon oli lihtne osa ja see postitus pole sellest. 17.–19. veebruaril 2026 ühendasid kaks pull request'i rakendusega react-i18next, tegid iga kõvakodeeritud inglise stringi ümber tõlkekutseks ja pakkisid kaasa kolmkümmend lokaadifaili. See on päris töö, aga selline töö, mille teek on loodud rutiiniks muutma. Huvitav insenertöö on kõik see, mida väljalase ei ehitanud — turvavõrk, mis oleks püüdnud kinni selle, mille ta katkisena tarnis.
Ühendamine oli lihtne 80%
Infrastruktuuri commit lisas react-i18next i18next'i peale ja tegi tavapärase asja: i18n/index.ts, mis kutsub initReactI18next, impordib staatiliselt kõik kolmkümmend lokaadi-JSON-i ja registreerib need ühe resources objekti alla. Ei mingit laiska laadimist — iga keel tarnitakse komplektis. Tõlkestringid elavad src/i18n/locales/*.json failides lamedate, punktidega nimeruumitud kaartidena: sidebar.meetings, startMeeting.start, üks võti ühe stringi kohta.
Migratsioon kõvakodeeritud inglise keelest t('key')-ile tehti ausalt, komponendigrupp komponendigrupi haaval, ja selle käigu saab commit-logist välja lugeda: esmalt külgriba, navigatsioon ja vestlus; siis seaded, sisselogimine ja onboarding; siis kohtumised, töölaud, tõsted ja navbari kohtspikrid. Iga commit asendas partii literaalseid stringe tõlkekutsetega. Kakskümmend üheksa mitte-inglise faili maandusid ühes commitis — üheksa tuhande realine tilk, mis tõlkis inglise lähteteksti kõigeks bulgaaria keelest vietnami keeleni.
Midagi sellest pole raske õigesti teha, sest valesti tegemine on vali: puuduv provider jookseb kokku, vigane JSON ei parsu, halb import lõhub build'i. Teek annab sulle kaitsepiirded mehaaniliste vigade vastu. Mida ta sulle ei anna, on kaitsepiire vea vastu, mis tegelikult juhtus.
Kolm keeleseadet ja miks see on õige
Enne kui jõuame selleni, mis katki läks, üks asi, mille v1.8.3 tegi täpselt õigesti, sest see on eristus, mille paljud rakendused kokku suruvad, kuigi ei peaks. Pärast seda väljalaset on GeekBye'l kolm sõltumatut keeleseadet:
- AI-vastuse keel (
output_language) — keel, milles assistent vastab. Kolmest vanim, 2025. aasta novembrist. - Transkriptsiooni keel (
transcriptLanguage) — keel, milleks kõnemootor su mikrofoni transkribeerib. Ühendatud paar väljalaset varem, v1.7.6-s. - Rakenduse keel (
app_language) — nuppude, menüüde ja onboarding'i keel. Uus v1.8.3-s.
Need on tõesti erinevad teljed. Berliinis olev arendaja võib tahta saksakeelset liidest, ingliskeelseid AI-vastuseid (sest see on keel dokumentatsioonile, mida ta kleebib) ja ingliskeelset transkriptsiooni (sest kohtumine on inglise keeles). Nende kokkusurumine üheks "keele" seadeks oleks selle inimese jaoks vale, ja selles väljalaskes lisatud onboarding'i samm esitab kõik kolm eraldi rippmenüüdena just sel põhjusel.
Meeldiv detail on uuendustee. Ühekordne migratsioon kopeerib esimesel käivitusel pärast uuendamist iga olemasoleva kasutaja output_language'i uude app_language võtmesse ning provider lahendab keele varuahela kaudu — app_language, siis output_language, siis 'en'. Nii et kasutajad, kes olid juba rakendusele öelnud, et soovivad hispaaniakeelseid AI-vastuseid, ärkasid hispaaniakeelse liidese juurde, selle asemel et neid inglise keelele lähtestataks ja seadet otsima pandaks. Uue eelistuse külvamine seotud vanast on väike lahkus, mis maksab ühe migratsiooni ja säästab iga uuendaja väikesest tüütusest.
Onboarding'i taasrenderdus, mis jäi tulemata
Üks päris bug tasub i18n-tööst välja tõsta, sest see on React'i lõks, millesse satub igaüks, kes teeb keele vahetamist käitusajal. Onboarding'i viisard ehitab osa oma valikuloenditest useMemo sees. Kui vahetad keelt keele sammul endal, peaks liides kohe uues keeles ümber joonistuma — ja ei joonistunud, sest t polnud memo sõltuvusmassiivis. Tõlkefunktsioon vahetab identiteeti, kui keel muutub; kui su memoiseeritud väärtus on ehitatud t-st, aga ei sõltu sellest, ulatab React sulle rõõmsalt aegunud, eelmise keele versiooni. Parandus esineb logis kaks korda — kord viisardi jaoks, kord seadete rippmenüü loendi jaoks — mis ütleb, et see on selline viga, mida teed igas kohas, kus memoiseerid tõlgitud sisu, kuni õpid alati t loetlema.
Onboarding kandis ka konarust, mida muudatuste logi ei maini: kuna see on white-label koodibaas, on kaks onboarding'i puud, mida tõlkida — GeekBye viisard ja Pavleur oma — mis elavad paralleelsete onboarding.* ja onboarding.pavleur.* võtmenimeruumide all. Iga onboarding'i string tõlgiti kaks korda, kahte brändihäälde, üle kõigi kahekümne üheksa keele.
Mida build ei teadnud, et tal puudub
Siin on osa, mis teeb sellest õppetunni, mitte kontroll-loendi. v1.8.3-l polnud automaatset viisi kõvakodeeritud stringide väljavõtmiseks ega CI kontrolli võtmete pariteedile lokaatide vahel. Nii et "valmis" definitsioon oli "keegi käis läbi komponendid, mis talle meenusid, ja mähkis stringid, mida ta nägi." See definitsioon laseb asju läbi.
Kaks nädalat pärast väljalaset maandus koristus-commit sõnumiga "translate all hardcoded English strings across 10 components into 30 languages." Kümme komponenti — probleemiteate vorm, kokkuvõtte ja mõõdikute vahelehed, aruande vaheleht, transkriptsiooni ja vestluse sisu, kasutuslimiidi viip, vestlussõnumid, koodikopeerimise nupp, hõljuvad tegevusnupud — olid tarnitud v1.8.3-s, rääkides endiselt kõigiga inglise keeles, igas keeles. Kellegi build ei kukkunud läbi. Ükski test ei läinud punaseks. Saksa kasutaja lihtsalt nägi aruande vahelehel inglise keelt ja ainus detektor oli inimene, kes lõpuks sellele otsa vaatas.
Sama puudumine tekitas väiksemad piinlikkused. Taani tõlge tarniti vale sõnaga — Luk application helt Luk applikationen helt asemel — ja parandati hilisemas väljalaskes, sest polnud emakeelse ülevaataja väravat ega viisi, kuidas torustik seda teada saaks. "Quit app" võtmed puudusid esialgsest partiist ja täideti tagantjärele päevi hiljem. Ja iga üksik funktsioon, mis pärast tarniti — modifikaatorklahvi eelseadistus, mikrofoni vaigistus, kokkuvõtte-kiibid, ülekatte läbipaistmatus — vedas endaga alati kaasa oma "tõlgi uued võtmed 29 lokaati" commiti, igavesti, sest miski ei jõustanud invarianti automaatselt.
Korratust saab isegi commit-sõnumites mõõta. Samu kolmekümmet lokaadifaili kirjeldatakse väljalaskest väljalaskesse kui "30 keelt", "29 keelt" ja — ühes commitis — "28 lokaati". Midagi ei lisatud ega eemaldatud; igas tag'is v1.8.3-st kuni v2-ni on kolmkümmend faili. Arv triivib, sest polnud ühtset tõeallikat selle kohta, "mitu keelt me tarnime", nii et iga commit'i autor luges käsitsi, mõnikord arvestades inglise keelt keelena ja mõnikord lähtekeelena. Muudatuste logi, mis ei suuda oma arvu stabiilsena hoida, on väike, aus signaal, et asja, mida see kirjeldab, ei jõusta masin.
Mitmuse peidetud lõks
Veel üks asi, mida tasub esile tõsta, mitte sellepärast, et see valjult katki läks, vaid sellepärast, et see on selline bug, mille see ülesehitus kutsub esile ega hoiata sind selle eest. Mitmus nendes lokaadifailides tehakse käsitsi, paaris võtmetega: meetings.meetingCount ja meetings.meetingCountPlural, profiles.filesAttached ja filesAttachedPlural. See on puhas inglise ainsuse/mitmuse jaotus. See on ka vale osa keelte jaoks, mida rakendus nüüd väidab toetavat. Vene, poola ja tšehhi keeles on kolm või neli mitmusevormi olenevalt arvust — "1 fail", "2 faili", "5 faili" ja "21 faili" võivad võtta erinevaid sõnalõppe. Kahe võtmega ainsuse/mitmuse skeem ei suuda seda väljendada, nii et need arvud renderduvad grammatiliselt valesti. i18next'il on täpselt selleks päris mitmusemasinavärk; käsitsi paarid hiilivad sellest mööda ja ükski commit ei tunnista seda lünka. See on kõvakodeeritud stringide probleemi mitmusevaste: buildile nähtamatu, nähtav ainult emakeelekõnelejale.
Kolm asja, mida see väljalase meile õpetas
- Teek on lihtne 80%; tööriistad on raske 20%.
react-i18next'i ühendamine ja stringide masstõlkimine on lahendatud probleem. Kolmekümne faili igaveses pariteedis hoidmine ei ole — ja see vajab ekstraktorit kõvakodeeritud stringidele ja CI kontrolli puuduvatele võtmetele, millest kumbagi teek sulle ei tarni. Ehita need enne, kui väidad "täielikku i18n-i", muidu oled väitnud invarianti, mida sul pole kuidagi võimalik hoida. - Eralda keeleseaded, mis on tegelikult erinevad. Liidese keel, transkriptsiooni keel ja AI-vastuse keel on kolm telge ja v1.8.3-l oli õigus anda igaühele oma võti — ja veel õigem külvata uus seotud vanast migratsiooni kaudu, nii et uuendamine ei maksnud kasutajatele midagi.
- Su muudatuste logi arv on distsipliinimõõdik. Kui sama failikomplekt on kolmes commitis 28, 29 ja 30 keelt, pole probleem arv — probleem on puuduv tõeallikas. Kui masin ei loe su keeli, ei loe keegi neid kaks korda ühtemoodi.
Eelmise peatüki jaoks v1 loos — töölaua ümberkujundamine ühe lainegraafiku ümber (v1.8.2); ja kogu kaare jaoks tarkvara täiuslikkuseni tarnimise anatoomia.