Skip to content

Tutorial 5 Localization hi

James Morris edited this page Jul 29, 2026 · 1 revision

ट्यूटोरियल 5 · लोकलाइज़ेशन (i18n)

लक्ष्य: समझें कि LockedIn CLI कैसे 33 भाषाएँ बोलती है — और एक एजेंट को एक और भाषा जोड़ने के लिए निर्देशित करने का अभ्यास करें। लोकलाइज़ेशन एक शानदार एजेंट टास्क है: यह delegate करने लायक पर्याप्त यांत्रिक है, पर इसमें असली constraints हैं (एक test गेट, layout नियम, व्याकरण review) जो आपको review करना सिखाते हैं।

← पिछला: ट्यूटोरियल 4 प्रॉम्प्टिंग और रिव्यू · होम पर वापस


यहाँ "localized" का मतलब क्या है

CLI को स्पेनिश, हिन्दी, जापानी, सरलीकृत चीनी, या किसी भी shipped भाषा में चलाएँ और सब कुछ बदल जाता है — splash, help table, हर कमांड का output, chat session, यहाँ तक कि legal fine print भी। सिर्फ़ मज़ाक नहीं: पूरी दृश्यमान सतह।

lockedin --lang hi post
LOCKEDIN_LANG=hi lockedin
lockedin --lang zh aura

भाषा startup पर autodetect होती है, प्राथमिकता क्रम में हल होती है:

  1. --lang flag (--lang hi, --lang=fr, -l ja)
  2. LOCKEDIN_LANG environment variable
  3. आपका locale (LC_ALL / LC_MESSAGES / LANG, फिर OS/runtime locale)
  4. अंग्रेज़ी, fallback के रूप में

normalizeLang() सामान्यतः locale के primary subtag का उपयोग करता है। इसका मतलब de-DE de चुनता है, पर tlh गलती से tl नहीं बन जाता; असली aliases fil और tgl जानबूझकर Tagalog (tl) पर map होते हैं, नॉर्वेजियन nb और nn no पर map होते हैं, legacy Indonesian in id पर map होता है, और legacy Hebrew iw he पर map होता है। दो regional codes उनके primary subtag में मोड़ने के बजाय हूबहू संरक्षित रहते हैं: pt-BR/pt_BR canonical regional code चुनते हैं जबकि generic pt backward-compatible Brazilian Portuguese bundle रहता है (दोनों Brazilian Portuguese हैं और एक ही pools/UI साझा करते हैं), और en-SG/en_SG Singlish रखते हैं (generic en अंग्रेज़ी रहता है)। Hong Kong Traditional Chinese उसी तरह का अपवाद है: zh-HK, zh_HK.UTF-8, और zh-Hant-HK zh-HK चुनते हैं, जबकि generic zh और mainland tags सरलीकृत चीनी (zh) चुनते हैं।

बीच में switch — /language panel। CLI हमेशा किसी और भाषा में शुरू हो सकती थी (--lang, LOCKEDIN_LANG); अब आप session के बीच में switch कर सकते हैं। /language टाइप करें (aliases /lang और /languages) सभी 33 भाषाओं को code के हिसाब से सूचीबद्ध करने के लिए, हर एक अपनी script में; /language el बाकी session के लिए switch कर देता है। बात है escape hatch की: switch के बाद यह नई भाषा में फिर से draw करता है और फिर, उसी भाषा में जिसे आपने अभी छोड़ा, ठीक वापसी का रास्ता print करता है — अभी /language en, अगली बार lockedin --lang en — ताकि गलती से 日本語 या ಕನ್ನಡ में जा पड़ने पर भी आप कभी न फँसें। (दो बार switch करें और आपका LOCKEDIN_LANG जिस भाषा का नाम लेता है वह भी पेश की जाती है।) --lang और LOCKEDIN_LANG अपरिवर्तित हैं। /a11y की तरह, यह एक सच्ची utility है, satire का हिस्सा नहीं।

विचार: language bundles

सारा translatable text bundles में रहता है, प्रति भाषा एक, हर एक का आकार ऐसा:

{ meta: { lang: 'hi', name: 'हिन्दी', dir: 'ltr' },
  pools: { HOOKS: [ /* ~25 */ ], LESSONS: [ /* ... */ ], /* ... */ },
  ui:    { buzzwordDensity: 'Buzzword घनत्व: ', /* labels, headings */ } }
  • pools वे content arrays (मज़ाक) हैं जिनसे आप अध्याय 2 में मिले।
  • ui chrome strings हैं: labels, headings, और छोटे templates।

अंग्रेज़ी src/lockedin.js के अंदर reference bundle है; बाकी 32 bundle modules src/content/*.js में रहते हैं: ar, bn, bo, de, el, en-SG, es, eu, fa, fi, fr, he, hi, id, is, it, ja, kn, ms, nl, no, pl, pt, pt-BR, ru, sv, tl, tr, uk, ur, zh, और zh-HK (pt-BR pt के pools/UI दोबारा इस्तेमाल करता है पर अलग से register होता है)। हर एक BUNDLES में register है; SUPPORTED_LANGS उन keys से बनता है, और renderHelp() वह बनी हुई code सूची print करता है। कोई UI bundle सूची को hard-code नहीं करता।

setLang('fr');       // active भाषा को French bundle की ओर इंगित करें
// L = सक्रिय pools, U = सक्रिय ui
pick(L.HOOKS)        // एक French hook
U.buzzwordDensity    // "Densité de jargon : "

चूँकि हर renderer L और U पढ़ता है (कभी hardcoded string नहीं), अकेला setLang पूरा अनुभव बदल देता है। यही पूरी तरकीब है।

safety net: key parity

यही वह invariant है जो एक भाषा जोड़ना सुरक्षित बनाता है:

हर bundle को अंग्रेज़ी जैसी ठीक वही pools और ui keys expose करनी चाहिए।

एक test इसे सभी 33 bundles में लागू करता है। अगर आप अंग्रेज़ी में एक नई UI string जोड़ते हैं और यूक्रेनियन में अनुवाद करना भूल जाते हैं, npm test लाल हो जाता है और बताता है कौन-सी key गायब है। आप चुपके से एक आधी-अनुवादित भाषा ship नहीं कर सकते।

कठिन हिस्सा: terminal layout

भाषाएँ terminal layout पर अलग-अलग तरीकों से दबाव डालती हैं:

  • जापानी, सरलीकृत चीनी, और Hong Kong Traditional Chinese East Asian Wide / Fullwidth characters इस्तेमाल करते हैं। vw() उन्हें दो columns गिनता है, और wrap() लंबे space-रहित tokens को hard-break करता है ताकि CJK text cards और boxes के अंदर रहे।
  • हिन्दी और कन्नड़ nonspacing/enclosing combining marks (Mn / Me) इस्तेमाल करते हैं, जैसे मात्राएँ और विराम। vw() उन्हें शून्य columns गिनता है ताकि वे मापी गई width को न फुलाएँ।
  • box() हर body line को pad करने से पहले wrap करता है, ताकि एक लंबा अनुवादित banner अब border को न भेद सके।
  • हर bundle sentenceEnd और listSep सेट करता है (उदाहरण के लिए . / , , / ) ताकि generator-रचित वाक्य स्वाभाविक रूप से पढ़ें।

जब आप एक भाषा जोड़ते हैं, card header strings (cardSubtitle, cardMeta, cardFooter) को अब भी ≤ 60 visible columns में फिट होना चाहिए। अरबी, फ़ारसी, हिब्रू, और उर्दू meta.dir: 'rtl' सेट करते हैं। Output में default रूप से कोई bidi controls नहीं होते, क्योंकि कुछ terminals उन्हें boxed labels के रूप में render करते हैं। LOCKEDIN_BIDI=on स्पष्ट रूप से wrapping के बाद balanced isolates सक्षम करता है उन terminals के लिए जो उन्हें support करने के लिए जाने जाते हैं, ANSI, ASCII commands, और logical copy/paste क्रम संरक्षित रखते हुए। Accessible output हमेशा उन controls को हटा देता है। opt-in के बिना, मिश्रित RTL/LTR क्रम कम परिष्कृत हो सकता है; कभी support probe या infer न करें।

चालाक हिस्सा: raw user input के आस-पास व्याकरण

कुछ UI templates {cap} जैसे placeholders के साथ raw user clauses splice करते हैं। उन्हें slot-for-slot अनुवाद न करें। वाक्य को व्याकरणसम्मत रहना चाहिए जब placeholder एक ऐसा phrase हो जिसे user ने type किया, न कि कोई साफ़-सुथरा noun।

एक असली सावधानी वाला bug: जापानी templates जो {cap} के ठीक बाद लगाते हैं, गलत लग सकते हैं जब {cap} एक पूरा clause हो। इलाज "और ज़ोर से अनुवाद करना" नहीं है; इलाज है template को फिर से संरचित करना (उदाहरण के लिए, एक nominalizer जोड़ना या placeholder हटाना) ताकि कोई भी user input अब भी फिट हो।

✅ अपने एजेंट के साथ आज़माएँ — एक भाषा जोड़ें

यह अभ्यास ठीक उसी तरह काम करता है। ऐसी भाषा चुनें जिसे आप sanity-check कर सकें (या एजेंट से करवाएँ), और उसे शुरू से अंत तक चलाएँ। पहले spec लिखें:

डैनिश (da) जोड़ें। अंग्रेज़ी जैसी वही keys के साथ src/content/da.js को एक { meta, pools, ui } bundle के रूप में बनाएँ, हर entry का अनुवाद करते हुए (content pools ~25 प्रत्येक, सारी UI strings)। src/lockedin.js में BUNDLES में da register करें। --lang da और एक da-* locale को इसे चुनना चाहिए। card header strings को width सीमा के भीतर रखें। npm test हरा रहना चाहिए, और मौजूदा localized वालों को प्रतिबिंबित करते हुए डैनिश invariants + detection tests जोड़ें।

फिर अध्याय 3–4 का loop चलाएँ:

  1. पहले plan। "कोड लिखने से पहले, बताओ कौन-सी फ़ाइलें बदलोगे और अंग्रेज़ी के साथ key parity कैसे रखोगे।"
  2. पहले tests। "failing tests जोड़ो: da detection, da के लिए key parity, और एक डैनिश reflect/connect invariant। bundle अभी मत बनाओ।"
  3. Implement। "अब एक मौजूदा bundle को key दर key अनुवाद करके src/content/da.js बनाओ, उसे register करो, और tests पास कराओ। randomness के लिए सिर्फ़ pick/shuffle।"
  4. गेट + review। npm test, फिर lockedin --lang da post — और diff को पढ़ो: क्या हर key का अनुवाद हुआ? क्या card borders अब भी line up होते हैं? क्या {cap} वाले templates raw user clauses में टिकते हैं?

अगर पूरी भाषा बहुत ज़्यादा है तो छोटे warm-up अभ्यास:

  • "सभी 33 language bundles में एक और TAGLINE जोड़ो, counts बराबर रखते हुए।"
  • "जाँचो कि कन्नड़ cardFooter ≤ 60 visible columns है या नहीं और समझाओ कि combining marks कैसे मापी गईं।"
  • "वह test दिखाओ जो fail होगा अगर मैं ja.js से एक ui key delete कर दूँ।"

आगे कहाँ जाएँ

  • src/content/es.js स्किम करें — यह अब भी एक नए bundle के लिए एक friendly template है।
  • docs/HANDOFF.md → "Adding a language" फिर से पढ़ें।
  • कमांड रेफरेंस में बहुभाषी मज़ाक का आनंद लें।

यही पूरा ट्यूटोरियल है। अब आप एक AI एजेंट को features बनाने और उन्हें एक test गेट के पीछे localize करने के लिए निर्देशित कर सकते हैं — 33 भाषाओं में और और के लिए तैयार। Agree? 👇

📘 LockedIn CLI wiki

Tutorial

Reference


Satire · Sátira · 風刺. Not affiliated with LinkedIn. GPL-3.0-or-later.

Clone this wiki locally