
बिना किसी safety net के तीस भाषाएँ ship करना
GeekBye v1.8.3 ने react-i18next को जोड़ा और पूरे app को 30 भाषाओं में translate कर दिया। library वाला हिस्सा रवायती था। दिलचस्प हिस्सा वह है जो ग़ायब था: न कोई key-parity check, न कोई string extractor — इसलिए hardcoded English रिस गई, एक Danish typo ship हो गया, और changelog यह तय ही नहीं कर पाया कि app 28, 29 या 30 भाषाएँ बोलता है।
कुछ रिलीज़ एक feature होती हैं। GeekBye v1.8.3 भी वैसी ही दिखती है — "app अब 30 भाषाएँ बोलता है" — पर feature ही आसान हिस्सा था, और यह post उसके बारे में नहीं है। February 17 और 19, 2026 के बीच, दो pull requests ने react-i18next को app में wire किया, हर hardcoded English string को एक translation call में refactor किया, और तीस locale files bundle कीं। यह असली काम है, पर यह उसी किस्म का काम है जिसे रवायती बनाने के लिए एक library बनी होती है। दिलचस्प engineering वह सब है जो रिलीज़ ने नहीं बनाया — वह safety net जो पकड़ लेती जो टूटा हुआ ship हुआ।
wiring आसान वाला 80% थी
infrastructure commit ने i18next के ऊपर react-i18next जोड़ा और वही रवायती चीज़ की: एक i18n/index.ts जो initReactI18next को call करता है, सभी तीस locale JSONs को statically import करता है, और उन्हें एक resources object के नीचे register करता है। कोई lazy loading नहीं — हर भाषा bundle में ship होती है। translation strings src/i18n/locales/*.json में flat, dot-namespaced maps के रूप में रहती हैं: sidebar.meetings, startMeeting.start, एक key से एक string।
hardcoded English से t('key') तक का migration ईमानदार तरीक़े से हुआ, component group दर component group, और आप इस बहाव को commit log में पढ़ सकते हैं: पहले sidebar, navigation, और chat; फिर settings, login, और onboarding; फिर meetings, dashboard, toasts, और navbar tooltips। हर commit ने literal strings के एक batch को translation calls से बदला। उनतीस non-English files एक ही commit में उतरीं — नौ-हज़ार लाइनों की एक बौछार जिसने English source को Bulgarian से Vietnamese तक हर चीज़ में translate किया।
इनमें से कुछ भी सही करना मुश्किल नहीं है, क्योंकि इसे ग़लत करना ज़ोरदार होता है: एक missing provider crash करा देता है, एक malformed JSON parse होने से मना कर देता है, एक ख़राब import build तोड़ देता है। library आपको यांत्रिक ग़लतियों के लिए guardrails देती है। जो वह नहीं देती, वह उस ग़लती के लिए guardrail है जो असल में हुई।
तीन language settings, और यह क्यों सही है
इससे पहले कि हम बताएँ क्या टूटा, एक चीज़ जो v1.8.3 ने बिल्कुल सही की, क्योंकि यह एक ऐसा फ़र्क़ है जिसे बहुत सारे apps चपटा कर देते हैं और नहीं करना चाहिए। इस रिलीज़ के बाद GeekBye में तीन स्वतंत्र language settings हैं:
- AI-response language (
output_language) — assistant किस भाषा में जवाब देता है। तीनों में सबसे पुरानी, November 2025 से। - Transcript language (
transcriptLanguage) — speech engine आपके microphone को किस भाषा में transcribe करता है। कुछ releases पहले, v1.7.6 में जोड़ी गई। - App language (
app_language) — buttons, menus, और onboarding की भाषा। v1.8.3 में नई।
ये सचमुच अलग-अलग धुरियाँ हैं। Berlin का एक developer एक German interface चाह सकता है, English AI जवाब (क्योंकि वही उन docs की भाषा है जिन्हें वह paste कर रहा है), और English transcription (क्योंकि meeting English में है)। इन्हें एक "language" setting में समेट देना उस इंसान के लिए ग़लत होता, और इस रिलीज़ में जोड़ा गया onboarding step तीनों को ठीक इसी वजह से अलग dropdowns के रूप में पेश करता है।
अच्छी बात upgrade path है। एक one-time migration हर मौजूदा user के output_language को update के बाद पहले launch पर नई app_language key में copy कर देता है, और provider भाषा को एक fallback chain से हल करता है — app_language, फिर output_language, फिर 'en'। तो जिन users ने app को पहले ही बता रखा था कि वे Spanish AI जवाब चाहते हैं, वे एक Spanish interface के साथ जागे, बजाय इसके कि वे English पर reset हो जाते और setting ढूँढ़ते फिरते। एक नई preference को उससे जुड़ी किसी पुरानी से भर देना एक छोटी सी नेकी है जिसकी क़ीमत एक migration है और जो हर upgrade करने वाले को एक झुँझलाहट से बचा लेती है।
वह onboarding re-render जो हुआ ही नहीं
i18n के काम में से एक असली bug निकालने लायक़ है, क्योंकि यह एक ऐसा React फंदा है जिसमें runtime language switching करने वाला हर कोई फँसेगा। onboarding wizard अपनी कुछ option lists एक useMemo के अंदर बनाता है। जब आप अपनी भाषा language step पर ही बदलते हैं, तो UI को तुरंत नई भाषा में फिर से खिंच जाना चाहिए — और ऐसा नहीं हुआ, क्योंकि t memo की dependency array में नहीं था। language बदलने पर translation function अपनी identity बदल देता है; अगर आपका memoized value t से बना है पर उस पर depend नहीं करता, तो React ख़ुशी-ख़ुशी आपको पुराना, पिछली-भाषा वाला version थमा देता है। fix log में दो बार दिखता है — एक बार wizard के लिए, एक बार settings dropdown list के लिए — जो बताता है कि यह उस किस्म की ग़लती है जो आप हर उस जगह करते हैं जहाँ आप translated content memoize करते हैं, जब तक आप हमेशा t को list करना नहीं सीख लेते।
onboarding में एक झोल और था जिसका changelog ज़िक्र नहीं करता: क्योंकि यह एक white-label codebase है, translate करने के लिए दो onboarding trees हैं — एक GeekBye wizard और एक Pavleur वाला — जो समानांतर onboarding.* और onboarding.pavleur.* key namespaces के नीचे रहते हैं। हर onboarding string दो बार translate हुई, दो brand voices में, सभी उनतीस भाषाओं में।
build को नहीं पता था कि उससे क्या छूट रहा है
यहाँ वह हिस्सा है जो इसे एक checklist की बजाय एक सबक़ बना देता है। v1.8.3 के पास hardcoded strings निकालने का कोई automated तरीक़ा नहीं था और locales के बीच key parity के लिए कोई CI check नहीं था। तो "done" की परिभाषा थी "किसी ने उन components को देखा जो उसे याद थे और उन strings को wrap कर दिया जो उसे दिखीं।" वह परिभाषा रिसती है।
रिलीज़ के दो हफ़्ते बाद, एक cleanup commit इस message के साथ उतरा — "translate all hardcoded English strings across 10 components into 30 languages।" दस components — issue-report form, summary और metrics tabs, report tab, transcript और chat content, usage-limit prompt, chat messages, copy-code button, floating action buttons — v1.8.3 में हर किसी से, हर भाषा में, अब भी English बोलते हुए ship हुए थे। किसी का build fail नहीं हुआ। कोई test लाल नहीं हुआ। एक German user को report tab में बस English दिखी, और इकलौता detector एक इंसान था जिसने आख़िरकार उसे देखा।
वही अनुपस्थिति छोटी-छोटी शर्मिंदगियाँ भी पैदा करती है। एक Danish translation ग़लत शब्द के साथ ship हुई — Luk application helt के बजाय Luk applikationen helt — और एक बाद की रिलीज़ में उसे ठीक किया गया, क्योंकि न कोई native reviewer gate था और न pipeline के पास जानने का कोई ज़रिया। "Quit app" keys शुरुआती batch से ग़ायब थीं और कुछ दिन बाद भरी गईं। और उसके बाद ship हुआ हर एक feature — एक modifier-key preset, mic mute, recap chips, overlay opacity — अपने पीछे अपना "नई keys को 29 locales में translate करो" वाला commit घसीटता रहा, हमेशा के लिए, क्योंकि कुछ भी उस invariant को अपने-आप enforce नहीं करता था।
आप इस अव्यवस्था को commit messages में नाप भी सकते हैं। वही तीस locale files, रिलीज़ दर रिलीज़, "30 languages," "29 languages," और — एक commit में — "28 locales" के रूप में वर्णित हैं। कुछ जोड़ा या हटाया नहीं गया; v1.8.3 से v2 तक हर tag पर तीस files हैं। संख्या इसलिए खिसकती है क्योंकि "हम कितनी भाषाएँ ship करते हैं" का कोई single source of truth नहीं था, इसलिए हर commit author ने हाथ से गिना, कभी English को एक भाषा गिनते हुए और कभी source। एक changelog जो अपनी ही गिनती स्थिर नहीं रख सकता, एक छोटा, ईमानदार संकेत है कि जिस चीज़ का वह ज़िक्र कर रहा है, उसे किसी machine से enforce नहीं किया जा रहा।
pluralization की बारूदी सुरंग
एक और चीज़ इशारा करने लायक़ है, इसलिए नहीं कि यह ज़ोर से टूटी, बल्कि इसलिए कि यह उस किस्म का bug है जिसे यह setup न्योता देता है और जिसके बारे में आपको चेतावनी नहीं देगा। इन locale files में pluralization हाथ से किया गया है, जोड़ीदार keys के साथ: meetings.meetingCount और meetings.meetingCountPlural, profiles.filesAttached और filesAttachedPlural। यह एक साफ़-सुथरा English singular/plural बँटवारा है। यह app जिन भाषाओं को अब support करने का दावा करता है, उनके एक हिस्से के लिए यह ग़लत भी है। Russian, Polish, और Czech में संख्या के हिसाब से तीन या चार plural forms होती हैं — "1 file," "2 files," "5 files," और "21 files" अलग-अलग शब्द-अंत ले सकते हैं। दो-key वाला singular/plural तरीक़ा यह व्यक्त नहीं कर सकता, इसलिए वे गिनतियाँ व्याकरण की दृष्टि से बेढब render होती हैं। i18next के पास ठीक इसी के लिए असली plural machinery है; manual pairs उसे किनारे कर देते हैं, और कोई commit इस खाई को स्वीकार नहीं करता। यह hardcoded-strings रिसाव का pluralization वाला जुड़वाँ है: build के लिए अदृश्य, सिर्फ़ एक native speaker के लिए दृश्यमान।
इस रिलीज़ ने हमें तीन बातें सिखाईं
- library आसान वाला 80% है; tooling मुश्किल वाला 20% है।
react-i18nextको wire करना और strings का bulk translation एक हल हो चुकी समस्या है। तीस files को हमेशा parity में रखना नहीं — और इसके लिए hardcoded strings का एक extractor और missing keys के लिए एक CI check चाहिए, जिनमें से कोई भी library आपके लिए ship नहीं करती। इन्हें "full i18n" का दावा करने से पहले बनाओ, वरना आपने एक ऐसे invariant का दावा कर लिया जिसे थामने का आपके पास कोई ज़रिया नहीं। - जो language settings सचमुच अलग हैं, उन्हें अलग करो। UI language, transcript language, और AI-response language तीन धुरियाँ हैं, और v1.8.3 ने हर एक को उसकी अपनी key देकर सही किया — और नई को किसी संबंधित पुरानी से migration के ज़रिए भरकर और भी सही किया, ताकि upgrade करने में users को कुछ न चुकाना पड़े।
- आपके changelog की गिनती एक अनुशासन-मीट्रिक है। जब वही file set तीन commits में 28, 29, और 30 भाषाएँ हो, तो समस्या संख्या नहीं है — ग़ायब source of truth है। अगर कोई machine आपकी भाषाएँ नहीं गिन रहा, तो उन्हें कोई भी दो बार एक जैसा नहीं गिन रहा।
v1 कहानी के पिछले अध्याय के लिए देखें Dashboard को एक ही wave chart के इर्द-गिर्द फिर से design करना (v1.8.2); और पूरे चाप के लिए, सॉफ़्टवेयर को परिपूर्णता तक पहुँचाकर भेजने की शारीर-रचना।