-
Notifications
You must be signed in to change notification settings - Fork 0
Tutorial 5 Localization bn
লক্ষ্য: বুঝুন LockedIn CLI কীভাবে ৩৩টি ভাষায় কথা বলে — এবং একটি এজেন্টকে দিয়ে আরেকটি ভাষা যোগ করানোর অনুশীলন করুন। লোকালাইজেশন একটি দুর্দান্ত এজেন্ট টাস্ক: এটি delegate করার মতো যথেষ্ট যান্ত্রিক, কিন্তু এর সত্যিকারের constraint আছে (একটি test গেট, layout নিয়ম, ব্যাকরণ review) যা আপনাকে review করতে শেখায়।
← পূর্ববর্তী: টিউটোরিয়াল ৪ প্রম্পটিং ও রিভিউ · হোম-এ ফিরুন
CLI-কে স্প্যানিশ, হিন্দি, জাপানি, সরলীকৃত চীনা, বা যেকোনো shipped ভাষায় চালান এবং সবকিছু বদলায় — splash, help table, প্রতিটি কমান্ডের output, chat session, এমনকি legal fine print। শুধু রসিকতা নয়: গোটা দৃশ্যমান পৃষ্ঠতল।
lockedin --lang bn post
LOCKEDIN_LANG=hi lockedin
lockedin --lang zh auraভাষা startup-এ autodetect হয়, অগ্রাধিকার ক্রমে সমাধান করা হয়:
-
--langflag (--lang bn,--lang=fr,-l ja) -
LOCKEDIN_LANGenvironment variable - আপনার locale (
LC_ALL/LC_MESSAGES/LANG, তারপর OS/runtime locale) - ইংরেজি, fallback হিসেবে
normalizeLang() সাধারণত locale-এর প্রাথমিক subtag ব্যবহার করে। এর মানে de-DE de
বেছে নেয়, কিন্তু tlh ভুলবশত tl হয়ে যায় না; আসল alias fil ও tgl ইচ্ছাকৃতভাবে
Tagalog (tl)-এ map করে, নরওয়েজিয়ান nb ও nn no-তে map করে, legacy Indonesian
in id-তে map করে, এবং legacy Hebrew iw he-তে map করে। দুটি regional code
তাদের প্রাথমিক subtag-এ ভাঁজ না করে হুবহু সংরক্ষিত থাকে: pt-BR/pt_BR canonical
regional code বেছে নেয় যখন generic pt backward-compatible Brazilian Portuguese
bundle থাকে (দুটিই Brazilian Portuguese এবং একই pool/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 tag সরলীকৃত চীনা (zh) বেছে নেয়।
মাঝপথে সুইচ — /language panel। CLI সবসময় আরেকটি ভাষায় শুরু করতে পারত
(--lang, LOCKEDIN_LANG); এখন আপনি session-এর মাঝে সুইচ করতে পারেন। /language
টাইপ করুন (alias /lang ও /languages) সব ৩৩টি ভাষা code অনুযায়ী তালিকা করতে,
প্রতিটি নিজের script-এ; /language el বাকি session-এর জন্য সুইচ করে। মূল কথা হলো
escape hatch: সুইচের পর এটি নতুন ভাষায় নতুন করে আঁকে এবং তারপর, আপনি যে ভাষা এইমাত্র
ছাড়লেন সেই ভাষায়, ঠিক ফেরার পথ print করে — এখন /language en, পরের বার
lockedin --lang en — যাতে ভুল করে 日本語 বা ಕನ್ನಡ-তে গিয়ে পড়লেও আপনি কখনো আটকে না
যান। (দুবার সুইচ করুন এবং আপনার LOCKEDIN_LANG যে ভাষার নাম বলে সেটিও প্রস্তাব করা হয়।)
--lang ও LOCKEDIN_LANG অপরিবর্তিত। /a11y-র মতো, এটি একটি আন্তরিক utility,
স্যাটায়ারের অংশ নয়।
সমস্ত translatable text থাকে bundle-এ, প্রতি ভাষায় একটি, প্রতিটির আকার এমন:
{ meta: { lang: 'bn', name: 'বাংলা', dir: 'ltr' },
pools: { HOOKS: [ /* ~25 */ ], LESSONS: [ /* ... */ ], /* ... */ },
ui: { buzzwordDensity: 'Buzzword ঘনত্ব: ', /* labels, headings */ } }-
poolsহলো content array (রসিকতা) যা আপনি অধ্যায় ২-এ পেয়েছেন। -
uiহলো chrome string: label, heading, এবং ছোট template।
ইংরেজি হলো src/lockedin.js-এর ভেতরের reference bundle; বাকি ৩২টি bundle module থাকে
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-র
pool/UI পুনর্ব্যবহার করে কিন্তু আলাদাভাবে নিবন্ধিত)। প্রতিটি BUNDLES-এ নিবন্ধিত;
SUPPORTED_LANGS ওই key থেকে তৈরি, এবং 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 পড়ে (কখনো hardcode করা string নয়), শুধু
setLang-ই গোটা অভিজ্ঞতা বদলে দেয়। এটাই পুরো কৌশল।
এই invariant-ই একটি ভাষা যোগ করা নিরাপদ করে:
প্রতিটি bundle-কে ইংরেজির ঠিক একই
poolsওuikey প্রকাশ করতে হবে।
একটি test এটি সব ৩৩টি bundle জুড়ে প্রয়োগ করে। আপনি যদি ইংরেজিতে একটি নতুন UI string
যোগ করেন এবং ইউক্রেনীয়তে অনুবাদ করতে ভুলে যান, npm test লাল হয় এবং বলে কোন key
নেই। আপনি নীরবে একটি অর্ধ-অনূদিত ভাষা ship করতে পারবেন না।
ভাষা terminal layout-কে বিভিন্নভাবে চাপে ফেলে:
-
জাপানি, সরলীকৃত চীনা, এবং Hong Kong Traditional Chinese East Asian Wide /
Fullwidth অক্ষর ব্যবহার করে।
vw()সেগুলোকে দুই column গণনা করে, এবংwrap()লম্বা space-হীন token hard-break করে যাতে CJK text card ও box-এর ভেতরে থাকে। -
হিন্দি ও কন্নড় nonspacing/enclosing combining mark (
Mn/Me) ব্যবহার করে, যেমন মাত্রা ও বিরাম।vw()সেগুলোকে শূন্য column গণনা করে যাতে সেগুলো মাপা width স্ফীত না করে। -
box()প্রতিটি body line pad করার আগে wrap করে, যাতে একটি লম্বা অনূদিত banner আর border ভেদ করতে না পারে। - প্রতিটি bundle
sentenceEndওlistSepসেট করে (উদাহরণস্বরূপ./。,,/、) যাতে generator-রচিত বাক্য স্বাভাবিকভাবে পড়ে।
আপনি যখন একটি ভাষা যোগ করেন, card header string (cardSubtitle, cardMeta,
cardFooter)-কে এখনো ≤ ৬০ visible column-এ ফিট করতে হবে। আরবি, ফারসি, হিব্রু, ও
উর্দু meta.dir: 'rtl' সেট করে। Output-এ default-এ কোনো bidi control থাকে না, কারণ
কিছু terminal সেগুলোকে boxed label হিসেবে render করে। LOCKEDIN_BIDI=on স্পষ্টভাবে
wrapping-এর পরে balanced isolate সক্রিয় করে সেই terminal-এর জন্য যেগুলো সেগুলো সমর্থন
করে জানা, ANSI, ASCII command, এবং logical copy/paste ক্রম সংরক্ষণ করে। Accessible
output সবসময় ওই control সরিয়ে দেয়। opt-in ছাড়া, মিশ্র RTL/LTR ক্রম কম পরিশীলিত হতে
পারে; কখনো support probe বা infer করবেন না।
কিছু UI template {cap}-এর মতো placeholder দিয়ে raw user clause splice করে। সেগুলো
slot-for-slot অনুবাদ করবেন না। placeholder যখন ব্যবহারকারীর টাইপ করা একটি phrase হয়,
পরিপাটি বিশেষ্য নয়, তখনও বাক্যটি ব্যাকরণসম্মত থাকতে হবে।
একটি সত্যিকারের সাবধানবাণী bug: জাপানি template যেগুলো {cap}-এর ঠিক পরে は বসায়,
{cap} যখন একটি পূর্ণ clause হয় তখন ভুল শোনাতে পারে। সমাধান "আরও কঠিনভাবে অনুবাদ করা"
নয়; সমাধান হলো template-টি পুনর্গঠন করা (উদাহরণস্বরূপ, একটি nominalizer যোগ করা বা
placeholder সরানো) যাতে যেকোনো user input এখনো মানানসই হয়।
এই অনুশীলন ঠিক একইভাবে কাজ করে। এমন একটি ভাষা বেছে নিন যা আপনি sanity-check করতে পারেন (বা এজেন্টকে করতে বলুন), এবং এটি শুরু থেকে শেষ পর্যন্ত চালান। প্রথমে spec লিখুন:
ড্যানিশ (
da) যোগ করুন। ইংরেজির একই key সহsrc/content/da.js-কে একটি{ meta, pools, ui }bundle হিসেবে তৈরি করুন, প্রতিটি entry অনুবাদ করে (content pool প্রতিটি ~২৫টি করে, সব UI string)।src/lockedin.js-এBUNDLES-এdaনিবন্ধন করুন।--lang daএবং একটিda-*locale-কে এটি বেছে নিতে হবে। card header string width সীমার মধ্যে রাখুন।npm testসবুজ থাকতে হবে, এবং বিদ্যমান localized-গুলোর প্রতিফলন করে ড্যানিশ invariant + detection test যোগ করুন।
তারপর অধ্যায় ৩–৪-এর loop চালান:
- আগে plan। "কোড লেখার আগে, বলো কোন ফাইলগুলো বদলাবে এবং ইংরেজির সঙ্গে key parity কীভাবে রাখবে।"
-
আগে test। "failing test যোগ করো:
dadetection,da-র জন্য key parity, এবং একটি ড্যানিশ reflect/connect invariant। bundle-টা এখনো তৈরি করো না।" -
Implement। "এবার একটি বিদ্যমান bundle key ধরে ধরে অনুবাদ করে
src/content/da.jsতৈরি করো, নিবন্ধন করো, এবং test পাস করাও। randomness-এর জন্য শুধুpick/shuffle।" -
গেট + review।
npm test, তারপরlockedin --lang da post— এবং diff-টা পড়ো: প্রতিটি key কি অনূদিত হয়েছে? card border কি এখনো সারিবদ্ধ?{cap}সহ template কি raw user clause-এ টিকে থাকে?
একটি গোটা ভাষা যদি বেশি হয়, ছোট warm-up অনুশীলন:
- "সব ৩৩টি language bundle-এ আরেকটি
TAGLINEযোগ করো, count সমান রেখে।" - "কন্নড়
cardFooterকি ≤ ৬০ visible column তা পরীক্ষা করো এবং ব্যাখ্যা করো combining mark কীভাবে মাপা হয়েছিল।" - "
ja.jsথেকে একটিuikey মুছলে যে test fail হবে সেটি দেখাও।"
-
src/content/es.jsচোখ বুলান — এটি এখনো একটি নতুন bundle-এর জন্য বন্ধুত্বপূর্ণ template। -
docs/HANDOFF.md→ "Adding a language" আবার পড়ুন। - কমান্ড রেফারেন্স-এর বহুভাষিক রসিকতা উপভোগ করুন।
এটাই সম্পূর্ণ টিউটোরিয়াল। আপনি এখন একটি AI এজেন্টকে দিয়ে feature তৈরি এবং সেগুলো একটি test গেটের পেছনে localize করাতে নির্দেশ দিতে পারেন — ৩৩টি ভাষায় এবং আরও কিছুর জন্য প্রস্তুত। Agree? 👇
Tutorial
- 1 · Orientation
- 2 · How the Code Works
- 3 · Your First Agent Task
- 4 · Prompting & Reviewing
- 5 · Localization
Reference
Satire · Sátira · 風刺. Not affiliated with LinkedIn. GPL-3.0-or-later.