Steven
Steven7 perc olvasás

Harminc nyelv szállítása biztonsági háló nélkül

A GeekBye v1.8.3 bekötötte a react-i18next-et, és lefordította az egész alkalmazást 30 nyelvre. A library-rész rutin volt. Az érdekes rész az, ami hiányzott: semmilyen kulcsparitás-ellenőrzés és semmilyen string-kinyerő — így hardcoded angol szöveg szivárgott át, egy dán elgépelés jutott ki, a changelog pedig nem tudott megegyezni abban, hogy az alkalmazás 28, 29 vagy 30 nyelven beszél-e.

Mérnöki munka
i18n
Desktop
GeekBye kiadások
Harminc nyelv szállítása biztonsági háló nélkül

Néhány kiadás egy funkció. A GeekBye v1.8.3 úgy néz ki, mint egy — „az alkalmazás most 30 nyelven beszél" —, de a funkció volt a könnyű rész, és nem erről szól ez az írás. 2026. február 17. és 19. között két pull request bekötötte a react-i18next-et az alkalmazásba, minden hardcoded angol stringet fordítási hívássá alakított, és becsomagolt harminc locale fájlt. Ez valódi munka, de ez az a fajta munka, amelyet egy library úgy van tervezve, hogy rutinná tegyen. Az érdekes mérnöki munka mindaz, amit a kiadás nem épített meg — a biztonsági háló, amely elkapta volna azt, amit hibásan szállított.

A bekötés volt a könnyű 80%

Az infrastruktúra-commit hozzáadta a react-i18next-et az i18next tetejére, és a szokványos dolgot tette: egy i18n/index.ts, amely meghívja az initReactI18next-et, statikusan importálja mind a harminc locale JSON-t, és egyetlen resources objektum alá regisztrálja őket. Semmi lazy loading — minden nyelv a bundle-ben utazik. A fordítási stringek a src/i18n/locales/*.json-ban élnek lapos, ponttal névterezett térképekként: sidebar.meetings, startMeeting.start, egy kulcs egy stringhez.

A hardcoded angolról a t('key')-re való átállás a becsületes módon történt, komponenscsoportról komponenscsoportra, és a söprést elolvashatod a commit logban: először sidebar, navigáció és chat; aztán beállítások, login és onboarding; aztán meetings, dashboard, toastok és a navbar tooltipjei. Minden commit egy adag literál stringet cserélt le fordítási hívásokra. Huszonkilenc nem angol fájl landolt egyetlen commitban — egy kilencezer soros ejtés, amely az angol forrást lefordította mindenre a bolgártól a vietnámiig.

Ebből semmit sem nehéz jól csinálni, mert rosszul csinálni hangos: egy hiányzó provider crashel, egy rosszul formázott JSON nem parse-olódik, egy rossz import eltöri a buildet. A library korlátokat ad a mechanikus hibákhoz. Amit nem ad, az egy korlát ahhoz a hibához, amely valójában megtörtént.

Három nyelvi beállítás, és miért helyes ez

Mielőtt rátérnénk arra, ami eltört, egy dolgot a v1.8.3 pontosan eltalált, mert ez egy olyan megkülönböztetés, amelyet sok alkalmazás összelapít, pedig nem kellene. E kiadás után a GeekBye-nak három független nyelvi beállítása van:

  • AI-válaszok nyelve (output_language) — milyen nyelven válaszol az asszisztens. A három közül a legrégebbi, 2025 novemberéből.
  • Transzkripció nyelve (transcriptLanguage) — milyen nyelvre írja át a beszédmotor a mikrofonodat. Néhány kiadással korábban vezették be, a v1.7.6-ban.
  • Alkalmazás nyelve (app_language) — a gombok, menük és az onboarding nyelve. Új a v1.8.3-ban.

Ezek valóban különböző tengelyek. Egy berlini fejlesztő akarhat német felületet, angol AI-válaszokat (mert az a dokumentáció nyelve, amelyet beilleszt) és angol transzkripciót (mert a megbeszélés angolul folyik). Ezeket egyetlen „nyelv" beállításba összevonni hibás lenne annak a személynek, és az ebben a kiadásban hozzáadott onboarding lépés pontosan ezért mutatja mind a hármat külön legördülőként.

A kellemes részlet a frissítési útvonal. Egy egyszeri migráció minden meglévő felhasználó output_language-ét az új app_language kulcsba másolja a frissítés utáni első indításkor, a provider pedig egy fallback-láncon keresztül oldja fel a nyelvet — app_language, aztán output_language, aztán 'en'. Így azok a felhasználók, akik már megmondták az alkalmazásnak, hogy spanyol AI-válaszokat akarnak, spanyol felülettel ébredtek, ahelyett hogy visszaállították volna őket angolra és keresniük kellett volna a beállítást. Egy új preferencia egy kapcsolódó régiből való feltöltése apró kedvesség, amely egy migrációba kerül, és minden frissítőt megkímél egy apró bosszúságtól.

Az onboarding újrarenderelés, amely nem akart

Van egy valódi bug, amelyet érdemes kiemelni az i18n-munkából, mert ez egy React-csapda, amelybe mindenki bele fog futni, aki futásidejű nyelvváltást csinál. Az onboarding varázsló néhány opciólistáját egy useMemo-n belül építi fel. Amikor magán a nyelvi lépésen változtatod meg a nyelvedet, a felületnek azonnal újra kellene rajzolódnia az új nyelven — és nem tette, mert a t nem volt benne a memo függőségi tömbjében. A fordítási függvény identitást vált, amikor a nyelv változik; ha a memoizált értéked a t-ből épül, de nem függ tőle, a React vidáman átadja neked az elavult, előző nyelvű változatot. A javítás kétszer jelenik meg a logban — egyszer a varázslóhoz, egyszer a beállítások legördülő listájához —, ami elárulja, hogy ez az a fajta hiba, amelyet minden helyen elkövetsz, ahol fordított tartalmat memoizálsz, amíg meg nem tanulod, hogy mindig sorold fel a t-t.

Az onboarding egy olyan ráncot is hordozott, amelyet a changelog nem említ: mivel ez egy white-label codebase, két onboarding-fa van lefordítandó — egy GeekBye varázsló és egy Pavleur — amelyek a párhuzamos onboarding.* és onboarding.pavleur.* kulcs-névterek alatt élnek. Minden onboarding stringet kétszer fordítottak le, két márkahangon, mind a huszonkilenc nyelven.

Amiről a build nem tudta, hogy hiányzik

Itt az a rész, amely ezt leckévé teszi checklist helyett. A v1.8.3-nak nem volt automatikus módja a hardcoded stringek kinyerésére, és nem volt CI-ellenőrzés a kulcsparitásra a locale-ok között. Így a „kész" definíciója az volt, hogy „valaki felkereste a komponenseket, amelyekre emlékezett, és becsomagolta a stringeket, amelyeket látott". Ez a definíció átereszt.

Két héttel a kiadás után egy takarító commit landolt a "translate all hardcoded English strings across 10 components into 30 languages" (fordítsd le az összes hardcoded angol stringet 10 komponensben 30 nyelvre) üzenettel. Tíz komponens — a hibabejelentő űrlap, az összegzés és metrikák fülek, a jelentés fül, a transzkripció és chat tartalma, a használati limit prompt, a chat üzenetek, a kódmásoló gomb, a lebegő akciógombok — a v1.8.3-ban úgy jelent meg, hogy még mindig angolul beszélt mindenkihez, minden nyelven. Senki buildje nem bukott el. Egyetlen teszt sem lett piros. Egy német felhasználó egyszerűen angolt látott a jelentés fülön, és az egyetlen érzékelő egy ember volt, aki végül ránézett.

Ugyanaz a hiány termelte a kisebb kínos helyzeteket. Egy dán fordítás rossz szóval jelent meg — Luk application helt a Luk applikationen helt helyett — és egy későbbi kiadásban foltozták be, mert nem volt anyanyelvi lektor-kapu, és a pipeline sem tudhatta. A „quit app" kulcsok hiányoztak a kezdeti adagból, és napokkal később töltötték fel őket. És minden egyes funkció, amely utána jelent meg — egy módosítóbillentyű-preset, mikrofon némítás, recap chipek, overlay átlátszóság — maga után vonszolta a saját „fordítsd le az új kulcsokat 29 locale-ra" commitját, örökké, mert semmi sem kényszerítette ki az invariánst automatikusan.

Meg is mérheted a rendetlenséget a commit üzenetekben. Ugyanazt a harminc locale fájlt kiadásról kiadásra „30 nyelvnek", „29 nyelvnek" és — egy commitban — „28 locale-nak" írják le. Semmit sem adtak hozzá vagy távolítottak el; harminc fájl van minden tagnél a v1.8.3-tól a v2-ig. A szám elsodródik, mert nem volt egyetlen igazságforrás arra, hogy „hány nyelvet szállítunk", így minden commit szerzője kézzel számolt, néha az angolt nyelvként, néha forrásként számítva. Egy changelog, amely nem tudja stabilan tartani a saját számát, apró, becsületes jel arról, hogy amit leír, azt nem egy gép kényszeríti ki.

A többesszám taposóaknája

Még egy dolog, amit érdemes jelezni, nem azért, mert hangosan tört el, hanem mert ez az a fajta bug, amelyet ez a felállás magához vonz, és amelyről nem fog figyelmeztetni. A többesszám ezekben a locale fájlokban kézzel készül, párosított kulcsokkal: meetings.meetingCount és meetings.meetingCountPlural, profiles.filesAttached és filesAttachedPlural. Ez egy tiszta angol egyes/többes felosztás. Egyben hibás is az alkalmazás által most támogatni állított nyelvek egy részére. Az orosznak, lengyelnek és csehnek három vagy négy többesszám-alakja van a számtól függően — „1 fájl", „2 fájl", „5 fájl" és „21 fájl" különböző szóvégződéseket vehet fel. Egy kétkulcsos egyes/többes séma ezt nem tudja kifejezni, így azok a számok nyelvtanilag hibásan jelennek meg. Az i18next-nek van valódi többesszám-gépezete pontosan erre; a kézi párok kikerülik, és egyetlen commit sem ismeri el a hiányt. Ez a hardcoded stringek szivárgásának a többesszám-megfelelője: láthatatlan a build számára, látható csak egy anyanyelvi beszélő számára.

Három dolog, amit ez a kiadás tanított nekünk

  1. A library a könnyű 80%; az eszköz a nehéz 20%. A react-i18next bekötése és a stringek tömeges fordítása megoldott probléma. Harminc fájlt örökre paritásban tartani nem az — és szükség van hozzá egy kinyerőre a hardcoded stringekhez és egy CI-ellenőrzésre a hiányzó kulcsokhoz, amelyek közül egy library sem szállít neked egyet sem. Építsd meg őket azelőtt, hogy „teljes i18n"-t állítanál, különben olyan invariánst állítottál, amelyet nincs mód megtartanod.
  2. Válaszd szét a nyelvi beállításokat, amelyek valóban különböznek. A felület nyelve, a transzkripció nyelve és az AI-válaszok nyelve három tengely, és a v1.8.3 helyesen adott mindegyiknek saját kulcsot — és még helyesebben töltötte fel az újat egy kapcsolódó régiből migrációval, így a frissítés semmibe sem került a felhasználóknak.
  3. A changelogod száma fegyelmi metrika. Amikor ugyanaz a fájlkészlet 28, 29 és 30 nyelv három commiton át, nem a szám a probléma — a hiányzó igazságforrás az. Ha egy gép nem számolja a nyelveidet, senki sem számolja őket kétszer ugyanúgy.

A v1-történet előző fejezetéért lásd a dashboard újratervezése egyetlen hullámdiagram köré (v1.8.2); a teljes ívért pedig a szoftver tökéletesre szállításának anatómiája.