চ্যাট-নির্মিত অ্যাপের জন্য আন্তর্জাতিকীকরণ আর্কিটেকচার
চ্যাট-নির্মিত অ্যাপের জন্য আন্তর্জাতিকীকরণ আর্কিটেকচার: স্থিতিশীল স্ট্রিং কী, বহুবচন নিয়ম এবং ওয়েব ও মোবাইল উভয়েই একরকম থাকা অনুবাদ কর্মপ্রবাহ নির্ধারণ করুন।

What breaks first when you add more languages
প্রথম যে জিনিস ভাঙে তা কোড নয়। তা হলো শব্দগুলো।
চ্যাট-নির্মিত অ্যাপগুলো প্রায়ই দ্রুত প্রোটোটাইপ হিসেবে শুরু হয়: আপনি টাইপ করেন “Add a button that says Save”, UI দেখা যায়, এবং আপনি আগানো যান। কয়েক সপ্তাহ পরে, আপনি স্প্যানিশ এবং জার্মান চান, এবং খুঁজে পান যে সেই “অস্থায়ী” লেবেলগুলো স্ক্রিন, কম্পোনেন্ট, ইমেইল এবং এরর মেসেজ জুড়ে ছড়িয়ে আছে।
কপি পরিবর্তন কোড পরিবর্তনের চেয়ে বেশি ঘনঘন ঘটে। প্রোডাক্ট নাম বদলায়, আইনি টেক্সট আপডেট হয়, অনবোর্ডিং পুনর্লিখিত হয়, এবং সাপোর্ট পরিষ্কার এরর মেসেজ চায়। যদি টেক্সট সরাসরি UI কোডের ভেতর থাকে, প্রতিটি ছোট শব্দের পরিবর্তনই একটি ঝুঁকিপূর্ণ রিলিজে পরিণত হয়, এবং আপনি এমন জায়গাগুলো মিস করবেন যেখানে একই ধারণা আলাদাভাবে বলা হয়েছে।
নিচে কিছু প্রাথমিক লক্ষণ আছে যা ইঙ্গিত করে যে আপনি অনুবাদের দেনা তৈরি করছেন:
- একটি স্ক্রিনে মিশ্র ভাষা (কিছু স্ট্রিং অনুবাদ আছে, অন্যগুলো এখনও ইংরেজিতে)।
- একই লেবেল ছোট পার্থক্যসহ ডুপ্লিকেট ( “Sign up”, “Sign Up”, “Create account”).
- টেক্সট লম্বা হলে ব্রেক হওয়া লেআউট (বাটন ওভারফ্লো, শিরোনাম খারাপভাবে র্যাপ)।
- মোবাইল এবং ওয়েব আলাদা পথে চলে যাওয়া (একই অ্যাকশনের জন্য ভিন্ন শব্দ)।
- সাপোর্ট কন্টেন্ট এবং সিস্টেম মেসেজ UI-র পিছনে লেগে থাকা।
একটি বাস্তব উদাহরণ: আপনি Koder.ai-তে একটি সাধারণ CRM তৈরি করেন। ওয়েব অ্যাপে লেখা আছে “Deal stage”, মোবাইল অ্যাপে লেখা আছে “Pipeline step”, এবং একটি এরর টোস্ট বলে “Invalid status”。 এমনকি তিনই অনুবাদ করা থাকলেও, ব্যবহারকারীরা অ্যাপকে অপ্রতিসংগত মনে করবে কারণ ধারণাগুলো মিলছে না।
“সঙ্গতিপূর্ণ” মানে সব জায়গায় একই অক্ষর নয়। এর মানে হলো:
- একই ধারণার জন্য একই কী এবং একই অর্থ ব্যবহার করা।
- ওয়েব এবং মোবাইল উভয়ই অনুবাদের জন্য একই থলিকে (source of truth) ভাগ করে নেয়।
- টোন এবং পরিভাষা স্থিতিশীল থাকে (আনুষ্ঠানিক বনাম অনানুষ্ঠানিক, “customer” বনাম “client”)।
- UI লেআউটগুলো লম্বা এবং ছোট উভয় বাক্য সামলাতে ডিজাইন করা থাকে।
একবার আপনি টেক্সটকে সজ্জা নয় বরং প্রোডাক্ট ডেটা হিসেবে ধরলে, ভাষা যোগ করা আর হাহাকার হয়ে উঠবে না বরং বিল্ডিং-এর এক নিয়মিত অংশ হয়ে যাবে।
Basic concepts and a simple goal to aim for
Internationalization (i18n) হলো সেই কাজ যাতে একটি অ্যাপ বহু ভাষা সমর্থন করতে পারে পুনঃলিখন ছাড়া। Localization (l10n) হলো নির্দিষ্ট ভাষা ও অঞ্চলের জন্য বাস্তব কন্টেন্ট—যেমন French (Canada) যেখানে সঠিক শব্দ, তারিখ ফরম্যাট এবং টোন থাকে।
একটি সহজ লক্ষ্য: প্রতিটি ব্যবহারকারী-উন্মুখ টেক্সট একটি স্থিতিশীল কী দ্বারা নির্বাচিত হোক, UI কোডে সরাসরি টাইপ করা না হয়। যদি আপনি একটি বাক্য পরিবর্তন করতে পারেন React কম্পোনেন্ট বা Flutter উইজেট খুলে না করেই, আপনি সঠিক পথে আছেন। এটা চ্যাট-নির্মিত অ্যাপগুলোর জন্য i18n আর্কিটেকচারের 핵। সেখানে চ্যাট সেশন চলাকালে সহজে হার্ড-কোডেড কপি পাঠিয়ে দেওয়া হয়ে যায়।
ব্যবহারকারী-উন্মুখ টেক্সট অনেক বেশি বিস্তৃত যা বেশিরভাগ টিম আশা করে না। এর মধ্যে আছে বাটন, লেবেল, ভ্যালিডেশন এরর, খালি স্টেট, অনবোর্ডিং টিপস, পুশ নোটিফিকেশন, ইমেইল, PDF এক্সপোর্ট এবং যে কোনো মেসেজ যা ব্যবহারকারী দেখতে বা শুনতে পারে। সাধারণত এর মধ্যে অন্তর্ভুক্ত নয়: ইনটার্নাল লগ, ডাটাবেস কলাম নাম, অ্যানালিটিক্স ইভেন্ট আইডি, ফিচার ফ্ল্যাগ বা অ্যাডমিন-শুধুমাত্র ডিবাগ আউটপुट।
অনুবাদ কোথায় থাকা উচিত? বাস্তবে, এটি প্রায়ই উভয়—ফ্রন্টেন্ড এবং ব্যাকএন্ড—এ থাকে, একটি পরিষ্কার সীমানা সহ:
- ফ্রন্টএন্ড দায়িত্বে নেয় UI ক্রোম: ন্যাভিগেশন, ফর্ম, মেনু এবং অধিকাংশ স্ক্রিন টেক্সট।
- ব্যাকএন্ড দায়ী করে যে মেসেজগুলো সে তৈরি করে: ট্রানজ্যাকশনাল ইমেইল, সার্ভার-সাইড ভ্যালিডেশন এরর, এবং যে কোনো রেসপন্সে ফেরত দেওয়া মেসেজ।
- শেয়ার্ড ডোমেইন (যেমন অর্ডার স্ট্যাটাস লেবেল) এক উৎস থেকে নেওয়া উচিত, যাতে ওয়েব এবং মোবাইল বিচ্ছিন্ন না হয়।
ভুল যা এড়াতে হবে—দায়িত্ব মিশ্রিত করা। যদি ব্যাকএন্ড UI এররগুলোর জন্য সম্পূর্ণ লেখা ইংরেজি বাক্য ফেরত দেয়, তাহলে ফ্রন্টএন্ড সেগুলোকে সুন্দরভাবে লোকালাইজ করতে পারবে না। একটি ভালো প্যাটার্ন হলো: ব্যাকএন্ড একটি এরর কোড ফেরত দেয় (এবং সম্ভব হলে নিরাপদ প্যারামিটার), এবং ক্লায়েন্ট সেই কোডকে লোকালাইজড মেসেজে ম্যাপ করে।
কপি মালিকানা একটি প্রোডাক্ট সিদ্ধান্ত, প্রযুক্তিগত বিস্তারিত নয়। শুরুতেই ঠিক করুন কে শব্দগুলো পরিবর্তন করতে এবং টোন অনুমোদন করতে পারবে।
যদি প্রোডাক্ট কপি মালিক থাকে, অনুবাদকে কন্টেন্ট হিসেবে বিবেচনা করুন: ভার্সন করুন, রিভিউ দিন এবং প্রোডাক্টকে পরিবর্তনের অনুরোধ করার নিরাপদ উপায় দিন। যদি ইঞ্জিনিয়ারিং কপি মালিক হয়, নীতি ঠিক করুন যে কোনো নতুন UI স্ট্রিং শিপ করার আগে তার সাথে একটি কী এবং ডিফল্ট অনুবাদ থাকতে হবে।
উদাহরণ: যদি আপনার সাইনআপ ফ্লো তিনটি আলাদা স্ক্রিনে “Create account” বলে, একটাই কী ব্যবহার করুন। এটা অর্থ সঙ্গত রাখে, অনুবাদককে দ্রুত করে এবং ছোট শব্দ পরিবর্তনকে পরবর্তী সময়ে একাধিক স্ক্রিন ক্লিনআপে পরিণত হওয়া থেকে রোধ করে।
How to structure string keys so they stay stable
কীগুলো হলো আপনার UI এবং অনুবাদের মধ্যে চুক্তি। যদি সেই চুক্তি বারবার বদলে যায়, আপনি মিসিং টেক্সট, তাড়াহুড়ো ফিক্স, এবং ওয়েব ও মোবাইলের মধ্যে অসমঞ্জস্য পাবেন। চ্যাট-নির্মিত অ্যাপগুলোর জন্য ভালো i18n আর্কিটেকচার শুরু হয় এক নিয়ম দিয়ে: কীগুলো অর্থ বর্ণনা করুক, বর্তমান ইংরেজি বাক্য নয়।
স্থিতিশীল আইডি ব্যবহার করুন কী হিসেবে (যেমন billing.invoice.payNow) পুরো বাক্য হিসেবে (যেমন "Pay now") এর বদলে। বাক্য-কী তখনই ভেঙে যায় যখন কেউ শব্দ পরিবর্তন করে, বিরামচিহ্ন যোগ করে, বা কেস বদলে দেয়।
একটি ব্যবহারিক প্যাটার্ন যা রিডেবল এবং স্থিতিশীল থাকে: screen (অথবা domain) + component + intent। বোরিং এবং পূর্বানুমানযোগ্য রাখুন।
উদাহরণ:
auth.login.titleauth.login.emailLabelbilling.checkout.payButtonnav.settingserrors.network.offline
কী পুনরায় ব্যবহার করবেন না করলে কবে করবেন—এমন সিদ্ধান্ত নিন: “প্রতিটি জায়গায় অর্থ কি পুরোপুরি একই?” সাধারণ ক্রিয়াগুলোর জন্য কী পুনরায় ব্যবহার করুন, কিন্তু প্রাসঙ্গিকতা বদলে গেলে কী আলাদা করে ফেলুন। উদাহরণস্বরূপ, প্রোফাইল স্ক্রীনের “Save” হয়তো সরল অ্যাকশন, যেখানে একটি জটিল এডিটরে “Save” কিছু ভাষায় ভিন্ন টোন প্রয়োজন হতে পারে—তবে তখন আলাদা কী ব্যবহার করা উচিত।
শেয়ার করা UI টেক্সটকে নিবেদিত namespace-এ রাখুন যাতে স্ক্রিন জুড়ে ডুপ্লিকেশন না হয়। সাধারণভাবে কাজ করে এমন বকেটগুলো:
common.actions.*(save, cancel, delete)common.status.*(loading, success)common.fields.*(search, password)errors.*(validation, network)nav.*(tabs, menu items)
যখন অর্থ একই থাকে কিন্তু শব্দ পরিবর্তিত হয়, কী রাখুন এবং শুধুমাত্র অনুবাদ আপডেট করুন। এটিই স্থিতিশীল আইডির পুরো উদ্দেশ্য। যদি অর্থ বদলে যায় (এমনকি সূক্ষ্মভাবে), নতুন কী তৈরি করুন এবং পুরনোটি তখনও ব্যবহার না হওয়া নিশ্চিত হওয়া পর্যন্ত রাখুন। এতে এমন “নীরব” অসঙ্গতি এড়ায় যেখানে পুরনো অনুবাদ আছে কিন্তু এখন ভুল।
Koder.ai-স্টাইল ফ্লো থেকে একটি ছোট উদাহরণ: আপনার চ্যাট একই সাথে React ওয়েব অ্যাপ এবং Flutter মোবাইল অ্যাপ উত্পন্ন করে। যদি উভয়ই common.actions.save ব্যবহার করে, আপনি সারাক্ষণ সঙ্গতিপূর্ণ অনুবাদ পাবেন। কিন্তু যদি ওয়েব profile.save ব্যবহার করে এবং মোবাইল account.saveButton ব্যবহার করে, সময়ের সাথে আপনি বিচ্যুত হবেন, যদিও ইংরেজি আজ একই দেখাচ্ছে।
Where strings live and how to organize translation files
আপনার সোর্স ভাষা (আসলে প্রায়শই ইংরেজি) কে একক সত্যের উৎস হিসেবে বিবেচনা করুন। এক জায়গায় রাখুন, কোডের মতো রিভিউ করুন, এবং স্ট্রিংগুলোকে র্যান্ডম কম্পোনেন্টে “অপেক্ষার জন্য” ঢুকতে দেবেন না। এটা হার্ড-কোডেড UI কপি এড়ানোর সবচেয়ে দ্রুত উপায়।
একটি সহজ নিয়ম সাহায্য করে: অ্যাপ কেবল i18n সিস্টেম থেকে টেক্সট দেখাতে পারবে। কেউ যদি নতুন কপি প্রয়োজন মনে করে, আগে কী ও ডিফল্ট মেসেজ যোগ করে তারপর UI-তে সেই কী ব্যবহার করবে। এটি আপনার চ্যাট-নির্মিত অ্যাপগুলোর জন্য i18n আর্কিটেকচারকে স্থিতিশীল রাখে—যখন ফিচারগুলি সরায়।
A folder layout that stays sane
যদি আপনি ওয়েব এবং মোবাইল উভয়ই শিপ করেন, একটি শেয়ার্ড কী ক্যাটালগ চান, প্লাস ফিচার টিমগুলোর কাজ করার স্থান যাতে তারা একে অপরের ওপর পা না ফেলে। একটি ব্যবহারিক লেআউট:
- /i18n
- /i18n/locales/en.json (source)
- /i18n/locales/es.json, /i18n/locales/fr.json, ...
- /i18n/features/billing.json, /i18n/features/auth.json, ...
- /i18n/shared.json (buttons, common labels, errors)
প্ল্যাটফর্ম জোড়ে কী একই রাখুন, যদিও ইমপ্লিমেন্টেশন আলাদা (React ওয়েবে, Flutter মোবাইলে)। যদি আপনি Koder.ai-এর মতো প্ল্যাটফর্ম ব্যবহার করে চ্যাট থেকে উভয় অ্যাপ জেনারেট করেন, সোর্স কোড এক্সপোর্ট করা সহজতর হয় যখন উভয় প্রজেক্ট একই কী নাম এবং একই মেসেজ ফরম্যাট নির্দেশ করে।
Versioning and reviews that prevent translation debt
অনুবাদ সময়ের সাথে বদলায়। পরিবর্তনগুলোকে প্রোডাক্ট পরিবর্তনের মতো ট্রিট করুন: ছোট, রিভিউ করা এবং ট্র্যাকেবল। একটি ভালো রিভিউ অর্থ ও পুনরায় ব্যবহারের ওপর মনোযোগ দেয়, কেবল বানান নয়।
- সোর্স লোকেলে কোনো পরিবর্তনের জন্য PR রিভিউ বাধ্যতামূলক করুন
- কী ডিলিট করা ব্লক করুন বশর্তে সার্চ ও একটি পরিকল্পনা ছাড়া
- অনুবাদকদের জন্য অস্পষ্ট টেক্সটের নোট যোগ করুন
- CI-এ একটি “মিসিং অনুবাদ” চেক ব্যবহার করুন
কীগুলো ভিন্ন টিমের মধ্যে ভেসে যেতে না দেওয়ার জন্য, কীগুলো ফিচারভিত্তিক (billing., auth.) করে মালিকানাধীন করুন, এবং কেবল শব্দ পরিবর্তন হওয়ায় কী নাম বদলাবেন না। কী হলো আইডেন্টিফায়ার, কপি নয়।
Pluralization and grammar without hacks
বহুবচন নিয়ম ভাষাভেদে বদলে যায়, তাই ইংরেজির সহজ প্যাটার্ন (1 বনাম সবকিছু) দ্রুত ভাঙে। কিছু ভাষায় 0, 1, 2-4 আলাদা ফর্ম থাকে, এবং অন্যগুলোর ক্ষেত্রে পুরো বাক্য বদলে যায়, শুধুমাত্র নাম নয়। যদি আপনি UI-তে if-else দিয়ে বহুবচন লজিক বেক করেন, তখন আপনি কপি ডুপ্লিকেট করবেন এবং এজ-কেস মিস করবেন।
একটি নিরাপদ উপায় হলো প্রতিটি ধারণার জন্য একটি নমনীয় মেসেজ রাখা এবং i18n স্তরকে সঠিক ফর্ম বেছে নিতে দেওয়া। ICU-স্টাইল মেসেজগুলো এই কাজে করা। এগুলো গ্রাম্যাটিক সিদ্ধান্তগুলো অনুবাদে রাখে, কোডে না।
নিচে একটি ছোট উদাহরণ যা মানুষ প্রায় ভুলে যায়ঃ
itemsCount = "{count, plural, =0 {No items} one {# item} other {# items}}"
উই একক কী 0, 1 এবং অন্যান্য সব কভার করে। অনুবাদকরা তাদের ভাষার সঠিক বহুবচন ফর্ম দিয়ে এটি প্রতিস্থাপন করতে পারবেন কোড স্পর্শ না করে।
যখন লিঙ্গ বা ভূমিকা-ভিত্তিক লেখা প্রয়োজন হয়, আলাদা কী তৈরি করা এড়ান যেমন welcome_male এবং welcome_female যদি প্রোডাক্ট সত্যিই তা চায় না। select ব্যবহার করুন যাতে বাক্য এক ইউনিট থাকে:
welcomeUser = "{gender, select, female {Welcome, Ms. {name}} male {Welcome, Mr. {name}} other {Welcome, {name}}}"
ব্যাকরণগত কেস নিয়ে নিজেকে জটিল পরিস্থিতিতে ঠেলে দেওয়া থেকে বাঁচতে, বাক্যগুলো যতটা সম্ভব পূর্ণ রাখুন। এমন ফ্র্যাগমেন্ট একত্রিত করে তৈরি করা যেমন "{count} " + t('items') ব্যবহার করা এড়ান, কারণ অনেক ভাষায় শব্দের ক্রম পরিবর্তন করা যাবে না। একটি মেসেজে সংখ্যা, নাম এবং চারপাশের শব্দগুলো মিলিয়ে রাখুন।
চ্যাট-নির্মিত অ্যাপগুলোতে (Koder.ai প্রজেক্টসহ) একটি সহজ নিয়ম কাজ করে: যদি একটি বাক্যে সংখ্যা, কোনো ব্যক্তি, অথবা একটি স্ট্যাটাস থাকে, প্রথম দিন থেকেই এটিকে ICU করুন। এটা সামান্য অতিরিক্ত খরচ করে কিন্তু পরে অনেক অনুবাদ দেনা বাঁচায়।
Keeping web and mobile translations consistent
যদি আপনার React ওয়েব অ্যাপ ও Flutter মোবাইল অ্যাপ আলাদা অনুবাদ ফাইল রাখে, তারা বিচ্ছিন্ন হবে। একই বাটন ভিন্ন শব্দ পাবে, একটি কী ওয়েবে এক অর্থ নেবে এবং মোবাইলের আরেকটি, এবং সাপোর্ট টিকেটে লেখা থাকবে “অ্যাপ বলছে X কিন্তু ওয়েবসাইট বলছে Y”।
সহজতম সমাধানই সবচেয়ে গুরুত্বপূর্ণ: একটি উৎস ফরম্যাট বেছে নিন এবং সেটাকে কোডের মতো ট্রিট করুন। বেশিরভাগ টিমের জন্য তা মানে একটি শেয়ারড সেট লোকেল ফাইল (উদাহরণ: JSON ব্যবহার করে ICU-স্টাইল মেসেজ) যা ওয়েব ও মোবাইল দুটোই ব্যবহার করে। যখন আপনি চ্যাট ও জেনারেটর ব্যবহার করে অ্যাপ তৈরি করেন, এটা আরও গুরুত্বপূর্ণ, কারণ সহজে দুটি জায়গায় নতুন টেক্সট তৈরি হয়ে যেতে পারে।
One shared source of truth
একটি ব্যবহারিক সেটআপ হলো একটি ছোট “i18n প্যাকেজ” বা ফোল্ডার যাতে থাকে:
- প্রতিটি ভাষার লোকেল ফাইল (সব জায়গায় একই কী)
- মেসেজ ফরম্যাট নিয়ম (ICU বহুবচন ও প্লেসহোল্ডার জন্য)
- কী কী যোগ করার নিয়ম বোঝানো একটি সংক্ষিপ্ত README
React এবং Flutter তারপর কেবল কনজিউমার হয়। তাদের নতুন কী লোকালি তৈরি করা উচিত নয়। Koder.ai-স্টাইল ওয়ার্কফ্লোতে (React ওয়েব, Flutter মোবাইল) আপনি উভয় ক্লায়েন্ট একই কী সেট থেকে জেনারেট করতে পারেন এবং পরিবর্তনগুলো অন্যান্য কোড পরিবর্তনের মতো রিভিউ করে রাখতে পারেন।
ব্যাকএন্ড সমন্বয় একই গল্পের অংশ। এরর, নোটিফিকেশন এবং ইমেইলগুলো Go-তে হাতে-লিখিত ইংরেজি স্ট্রিং হয়ে থাকা উচিত নয়। বরং স্টেবল এরর কোড ফেরত দিন (যেমন auth.invalid_password) এবং নিরাপদ প্যারামিটার সহ। তারপর ক্লায়েন্টগুলো কোডকে অনুবাদিত টেক্সটে ম্যাপ করে। সার্ভার-সাইড ইমেইলের জন্য সার্ভার একই কী এবং লোকেল ফাইল ব্যবহার করে টেমপ্লেট রেন্ডার করতে পারে।
Rules that keep you in sync
একটি ছোট রুলবুক তৈরি করুন এবং কোড রিভিউতে সেটা প্রয়োগ করুন:
- নতুন UI টেক্সট আগে শেয়ার্ড লোকেল ফাইলগুলোতে নতুন কী দাবি করে
- কীগুলোতে পরিষ্কার namespace ও intent থাকা লাগবে (স্ক্রিন পজিশন নয়)
- প্রতিটি কী-তে প্লেসহোল্ডার একবার সংজ্ঞায়িত করে এবং সব জায়গায় একইভাবে ব্যবহার করা হবে
- যদি দুটি বাক্য অর্থে ভিন্ন হয়, তারা একই কী শেয়ার করতে পারবে না
- যদি দুটি কী একই অর্থ বহন করে, একটিকে মুছে দিন এবং একটি বিজয়ী বেছে নিন
ডুপ্লিকেট কী ও বিভিন্ন অর্থ ঠেকাতে অনুবাদক এবং ভবিষ্যৎ আপনার জন্য “description” ফিল্ড (অথবা একটি কমেন্ট ফাইল) যোগ করুন। উদাহরণ: billing.trial_days_left বর্ণনা করে দিন এটি একটি ব্যানারে দেখাচ্ছে নাকি ইমেইলে—একটি বাক্য প্রায়ই “ক্লোজ এনাফ” পুনঃব্যবহার রোধ করে যা পরে দেনা সৃষ্টি করে।
এই সঙ্গতিটাই চ্যাট-নির্মিত অ্যাপগুলোর জন্য একটি আন্তর্জাতিকীকরণ আর্কিটেকচারের কাঁধ: একটি শেয়ার্ড শব্দভাণ্ডার, বহু সারফেস, এবং পরবর্তী ভাষা শিপ করার সময় কোনো বিস্ময় নেই।
Step-by-step setup you can follow on a real project
চ্যাট-নির্মিত অ্যাপগুলোর জন্য একটি ভালো i18n আর্কিটেকচার সরলভাবে শুরু করে: একটি কী সেট, কপি’র জন্য একটি উৎস-স্থান, এবং একই নিয়ম ওয়েব ও মোবাইলে। যদি আপনি দ্রুত বিল্ড করেন (উদাহরণস্বরূপ Koder.ai দিয়ে), এই কাঠামো দ্রুততা ধরে রাখে কিন্তু অনুবাদ দেনা তৈরি হতে দেয় না।
A practical setup (web + mobile)
আপনার লোকেলগুলো আগেভাগেই নির্ধারণ করুন এবং মিসিং অনুবাদ হলে কী হবে তা ঠিক করুন। সাধারণ পছন্দ হলো: ব্যবহারকারীর পছন্দভাষা থাকলে তা দেখান, নতুবা ইংরেজিতে ফেলব্যাক করুন, এবং মিসিং কী লগ করুন যাতে পরের রিলিজের আগে ঠিক করা যায়।
তারপর এটি স্থাপন করুন:
- Locales ও fallback নির্ধারণ: সমর্থিত ভাষা, ডিফল্ট লোকেল, এবং স্পষ্ট fallback অর্ডার ঠিক করুন। কিভাবে লোকেল ডিটেক্ট করবেন (ব্রাউজার/অ্যাপ সেটিং, ব্যবহারকারী প্রোফাইল) তাও নির্ধারণ করুন।
- অনুবাদ ফাংশন ও কী কনভেনশন: স্থিতিশীল, অর্থভিত্তিক কী ব্যবহার করুন (পুরো বাক্য নয়)। উদাহরণ:
billing.plan_name.proবাauth.error.invalid_password. একই কী সব জায়গায় রাখুন। - React ও Flutter-এ অন্তর্ভুক্ত করুন: React-এ আপনার অ্যাপকে একটি i18n প্রদানকারীর সাথে বেঁধে দিন এবং কম্পোনেন্টে
t("key")ব্যবহার করুন। Flutter-এ একটি লোকালাইজেশন ওয়্রাপার ব্যবহার করুন এবং উইজেটে একই কী-ভিত্তিক লগিক কল করুন। লক্ষ্য হলো একই কী ব্যবহার, লাইব্রেরি হওয়া না। - শুরু থেকেই ভ্যারিয়েবল ও বহুবচন সমর্থন করুন: ICU-স্টাইল মেসেজ ব্যবহার করুন যেমন
{count, plural, one {# file} other {# files}}এবংHello, {name}। এতে স্ক্রিন জুড়েif (count === 1)জাতীয় হ্যাক ছড়ায় না। - হালকা কপি রিভিউ ধাপ যোগ করুন: শিপ করার আগে নতুন বা পরিবর্তিত স্ট্রিংগুলো রিভিউ করুন: কী নামকরণ ঠিক আছে কি না, হার্ড-কোডেড কপি মুছে গেছে কি না, প্লেসহোল্ডার মিলছে কি না, ওয়েব ও মোবাইল উভয়ই পরিবর্তনটি নিয়েছে কি না।
শেষে, একটি ভাষা টেস্ট করুন যার শব্দ দীর্ঘ হয় (জার্মান ক্লাসিক) এবং আরেকটি যেখানে বিরামচিহ্ন ভিন্ন। এটি দ্রুত বাটন ওভারফ্লো, শিরোনামের র্যাপ এবং লেআউট অনুমানবিহীনতা উন্মোচিত করবে।
যদি আপনি অনুবাদগুলো শেয়ার্ড ফোল্ডারে রাখেন (অথবা জেনারেটেড প্যাকেজ) এবং কপি পরিবর্তনগুলোকে কোড পরিবর্তনের মতো ট্রিট করেন, আপনার ওয়েব ও মোবাইল অ্যাপগুলো দ্রুতই সঙ্গতিপূর্ণ থাকে এমনকি যখন ফিচারগুলো চ্যাটে দ্রুত তৈরি করা হয়।
Dynamic content: dates, numbers, and user text
অনুবাদিত UI স্ট্রিং কেবল সমস্যার অর্ধেক। বেশিরভাগ অ্যাপ এছাড়াও পরিবর্তনশীল মান দেখায় যেমন তারিখ, দাম, গণনা, এবং নাম। যদি আপনি এই মানগুলোকে সাধারণ টেক্সট মেনে নেন, আপনি অদ্ভুত ফরম্যাট, ভুল টাইমজোন, এবং এমন বাক্য পাবেন যা অনেক ভাষায় “অদ্ভুত” শোনায়।
শুরুতেই সংখ্য, মুদ্রা, ও তারিখগুলো লোকেল নিয়ম ব্যবহার করে ফরম্যাট করুন, কাস্টম কোড দিয়ে নয়। ফ্রান্সের একজন ব্যবহারকারী আশা করে “1 234,50 €”, আর মার্কিন ব্যবহারকারী আশা করে “$1,234.50”。একই নিয়ম তারিখেও প্রযোজ্য: “03/04/2026” অস্পষ্ট হতে পারে, কিন্তু লোকেল ফরম্যাটিং স্পষ্ট করে।
টাইমজোন পরবর্তী ফাঁদ। সার্ভার সাধারনত timestamp গুলো neutral ফরমে (সাধারণত UTC) স্টোর করে, কিন্তু ব্যবহারকারীরা তাদের নিজের জোনে সময় দেখা আশা করে। উদাহরণ: একটি অর্ডার 23:30 UTC-তে তৈরি হলে টোকিওর কারো জন্য সেটা “আগামীকাল” হতে পারে। প্রতিটি স্ক্রিনে একটি নীতি সিদ্ধান্ত নিন: ব্যক্তিগত ইভেন্টে ব্যবহারকারীর লোকাল সময় দেখান, এবং স্টোর পিকআপ উইন্ডোর মতো ব্যবসায়িক টাইম জোনে ফিক্সড সময় দেখান (এবং স্পষ্ট লেবেল দিন)।
অনুবাদকৃত ফ্র্যাগমেন্ট গেঁথে বাক্য তৈরি করা এড়ান। এটা ব্যাকরণ ভেঙে দেয় কারণ শব্দের ক্রম ভাষাভেদে বদলে যায়। এর বদলে:
"{count} " + t("items") + " " + t("in_cart")
এরকম নয়—একটি মেসেজ ব্যবহার করুন প্লেসহোল্ডারসহ, যেমন: "{count} items in your cart"। অনুবাদক তখন শব্দগুলো সঠিকভাবে বিন্যস্ত করতে পারবেন।
Right-to-left (RTL) languages
RTL কেবল টেক্সট দিক নয়। লেআউট ফ্লো উল্টে যায়, কিছু আইকন মিরর করতে হয় (যেমন ব্যাক অ্যারো), এবং মিশ্র কনটেন্ট (আরবী সঙ্গে ইংরেজি প্রোডাক্ট কোড) অপ্রত্যাশিত অর্ডারে রেন্ডার হতে পারে। আসল স্ক্রিনগুলো টেস্ট করুন, শুধু একটি লেবেল নয়, এবং নিশ্চিত করুন আপনার UI কম্পোনেন্টগুলো ডিরেকশন পরিবর্তন সমর্থন করে।
User-generated content
ব্যবহারকারী যা লিখেছে তা কখনও অনুবাদ করবেন না (নাম, ঠিকানা, সাপোর্ট টিকিট, চ্যাট মেসেজ)। আপনি এর চারপাশের লেবেল অনুবাদ করতে পারেন, এবং চারপাশের মেটাডাটা (তারিখ, সংখ্যা) ফরম্যাট করতে পারেন, কিন্তু কন্টেন্টই অক্ষত রাখুন। যদি পরে অটো-অনুবাদ যোগ করেন, তা একটি স্পষ্ট ফিচার হিসেবে রাখুন যেখানে একটি “original/translated” টগল আছে।
একটি ব্যবহারিক উদাহরণ: একটি Koder.ai-নির্মিত অ্যাপ দেখাতে পারে “{name} renewed on {date} for {amount}”。এটিকে একটি মেসেজ হিসেবে রাখুন, {date} ও {amount} লোকেল অনুযায়ী ফরম্যাট করুন, এবং ব্যবহারকারীর টাইমজোনে দেখান। এই এক প্যাটার্ন অনেক অনুবাদ দেনা রোধ করে।
দ্রুত নিয়মগুলো যা সাধারণত বাগ প্রতিরোধ করে:
- টাইমস্ট্যাম্পগুলো UTC-তে স্টোর করুন, ভিউয়ারের লোকেল ও টাইমজোন অনুযায়ী ফরম্যাট করুন।
- পূর্ণ বাক্যের মধ্যে প্লেসহোল্ডার ব্যবহার করুন, কখনই ফ্র্যাগমেন্ট জোড়া করবেন না।
- মুদ্রা লোকেল নিয়ম ও সঠিক কারেন্সি কোড ব্যবহার করে ফরম্যাট করুন।
- বাস্তব স্ক্রিনে কমপক্ষে একটি RTL লোকেল টেস্ট করুন।
- ডিফল্টভাবে ব্যবহারকারী-উত্পন্ন টেক্সট অনুবাদ করবেন না।
Common mistakes that create translation debt
অনুবাদ দেনা সাধারণত শুরু হয় “একটি দ্রুত স্ট্রিং” হিসেবে এবং পরে সপ্তাহের পর সপ্তাহ পরিষ্কার করার প্রয়োজন হয়। চ্যাট-নির্মিত প্রজেক্টে, এটা আরও দ্রুত হয় কারণ UI টেক্সট কম্পোনেন্ট, ফর্ম এবং এমনকি ব্যাকএন্ড মেসেজের ভেতরেই জেনারেট হয়ে যায়।
The problems that hurt later
যেগুলো সবচেয়ে ব্যয়বহুল সমস্যা সেগুলো হলো যেগুলো অ্যাপ জুড়ে ছড়িয়ে পড়ে এবং খুঁজে পাওয়া কঠিন হয়।
- UI কম্পোনেন্টের ভেতর কপি হার্ড-কোড করা, প্লেসহোল্ডার, খালি স্টেট, এবং বাটন লেবেলসহ। আপনি তা অডিট বা পুনরায় ব্যবহার করতে পারবেন না, এবং ছোট শব্দ পরিবর্তন কোড এডিট দাবি করে।
- ব্যাকএন্ড ভ্যালিডেশন ও API এররগুলোকে ইংরেজি বাক্য হিসেবে ফেরত দেয়া। UI মিশ্র ভাষা দেখায় এবং আপনি নির্ভরযোগ্যভাবে এররগুলোকে অনুবাদী মেসেজে ম্যাপ করতে পারবেন না।
- সম্পূর্ণ ইংরেজি বাক্যকে অনুবাদ কী হিসেবে ব্যবহার করা। এটা সুবিধাজনক মনে হয় যতক্ষণ না কপি পরিবর্তিত হয়, তখন কী দ্রুত churn করে, পুরনো কী লিঙ্গে পড়ে, এবং অনুবাদ মেমোরি হারায়।
- ওয়েব ও মোবাইলের মধ্যে কীগুলো কপি করা এবং আলাদাভাবে সম্পাদনা করা। সময়ের সাথে “একই” স্ক্রিন বিচ্যুত হয় এবং ব্যবহারকারীরা বিরক্ত হয়।
- প্রথম অ-ইংরেজি ভাষা যোগ করার আগে বহুবচন নিয়ম পেছনে রাখা। তারপর আপনি ডজনভাগ “1 items” বাগ এবং অদ্ভুত ব্যাকরণ পাবেন যা সহজ if-statements দিয়ে ঠিক করা যাবে না।
A quick example (what it looks like in real life)
ধরুন একটি React ওয়েব অ্যাপ এবং একটি Flutter মোবাইল অ্যাপ উভয়ই একটি বিলিং ব্যানার দেখায়: “You have 1 free credit left”。 কেউ ওয়েব টেক্সট বদলে “You have one credit remaining” করে এবং কীকে পুরো বাক্য রেখেই রাখে। মোবাইল এখনও পুরনো কী ব্যবহার করে। এখন আপনার এক ধারণার জন্য দুইটি কী হয়ে গেছে, এবং অনুবাদক উভয়টি দেখেন।
একটি ভালো প্যাটার্ন হলো স্থিতিশীল কীগুলো (যেমন billing.creditsRemaining) এবং ICU-ভিত্তিক বহুবচন যাতে ব্যাকরণ সব ভাষায় সঠিক থাকে। যদি আপনি Koder.ai-এর মতো ভিব-কোডিং টুল ব্যবহার করেন, একটি নিয়ম শুরুর দিকে যোগ করুন: চ্যাটে তৈরি কোনো ব্যবহারকারী-উন্মুখ টেক্সট অবশ্যই ট্রান্সলেশন ফাইলেই নামুক, কম্পোনেন্ট বা সার্ভার এররগুলোর ভেতর নয়। এই ছোট অভ্যাসটি আপনার চ্যাট-নির্মিত অ্যাপগুলোর i18n আর্কিটেকচারকে বড় হয়ে ওঠার সময় রক্ষা করবে।
Quick checklist, a realistic example, and next steps
যখন আন্তর্জাতিকীকরণ অগোছালো মনে হয়, সাধারণত কারণ বেসিকগুলো লেখা হয়নি। একটি ছোট চেকলিস্ট এবং একটি কনক্রিট উদাহরণ আপনার টিম (এবং ভবিষ্যৎ আপনি) কে অনুবাদ দেনা থেকে রাখবে।
নিচে একটি দ্রুত চেকলিস্ট প্রতিটি নতুন স্ক্রিনে চালানোর জন্য:
- স্থিতিশীল কিজ: একটি অর্থপ্রতি একটি কী, না যে শব্দটি (উদাহরণ:
billing.invoice.paidStatus, নয়billing.greenLabel)। - Fallbacks: একটি স্পষ্ট ডিফল্ট ভাষা নির্ধারণ করুন, এবং কী মিসিং হলে কী করা হবে সিদ্ধান্ত নিন (ফেলব্যাক টেক্সট দেখানো, লগ করা, অথবা রিলিজ ব্লক করা)।
- Plural rules: বহুবচনের জন্য ICU-স্টাইল মেসেজ ব্যবহার করুন (0, 1, many) স্ট্রিং-হ্যাকের বদলে।
- Formatting: দিন, টাকা এবং সংখ্যাগুলো লোকেল অনুযায়ী ফরম্যাট করুন (এবং মুদ্রাকে ভাষা থেকে আলাদা রাখুন)।
- RTL চেক: কমপক্ষে একটি রাইট-টু-লেফট ভাষা আগে থেকে টেস্ট করুন যাতে লেআউট সমস্যা 200 স্ক্রিন হওয়ার আগে দেখা যায়।
একটি সহজ উদাহরণ: আপনি ইংরেজি, স্প্যানিশ, এবং জাপানি-তে একটি বিলিং স্ক্রিন লঞ্চ করতে যাচ্ছেন। UI-তে আছে: “Invoice”, “Paid”, “Due in 3 days”, “1 payment method” / “2 payment methods”, এবং একটি টোটাল যেমন “$1,234.50”。 যদি আপনি একটি আন্তর্জাতিকীকরণ আর্কিটেকচারে এটি বানান, আপনি একবার কী সংজ্ঞায়িত করবেন (ওয়েব ও মোবাইলে শেয়ার করা), এবং প্রতিটি ভাষা কেবল মান পূরণ করবে। “Due in {days} days” একটি ICU মেসেজ হবে, এবং মুদ্রা ফরম্যাটিং লোকেল-সচেতন ফরম্যাটারের মাধ্যমে হবে, না হার্ড-কোডেড কমার দিয়ে।
ভাষা সাপোর্ট ধাপে ধাপে ফেলুন, পুরো রিরাইট নয়:
- প্রথমে এক উচ্চ-ট্র্যাফিক ফ্লো (বিলিং, অনবোর্ডিং, অথবা চেকআউট) থেকে শুরু করুন।
- হার্ড-কোডেড UI কপি ট্রান্সলেশন ফাইলে সরান এবং কী দিয়ে রিপ্লেস করুন।
- একই ফ্লো জন্য বহুবচন মেসেজ ও ফরম্যাটিং যোগ করুন।
- পরবর্তী ফিচারে তখনই যান যখন মিসিং কিজ প্রায় শূন্য।
দুইটি জিনিস ডকুমেন্ট করুন যেন নতুন ফিচারগুলো সঙ্গতিশীল থাকে: আপনার কী নামকরণ নিয়ম (উদাহরণসহ) এবং স্ট্রিংগুলোর “ডেফিনিশন অফ ডান” (কোনো হার্ড-কোডেড কপি নয়, বহুবচনের জন্য ICU, তারিখ/সংখ্যার ফরম্যাটিং, শেয়ার্ড ক্যাটালগে যোগ করা)।
পরবর্তী ধাপ: যদি আপনি Koder.ai-তে বিল্ড করছেন, Planning Mode ব্যবহার করে স্ক্রিন ও কীগুলো জেনারেট করার আগে নির্ধারণ করুন। তারপর স্ন্যাপশট ও রোলব্যাক ব্যবহার করে নিরাপদে কপি ও অনুবাদ নিয়ে ওয়েব ও মোবাইলে পুনরাবৃত্তি করুন যাতে কোনো ভাঙা রিলিজের ঝুঁকি না থাকে।
সাধারণ প্রশ্ন
অনুবাদের কীগুলোর নাম কীভাবে দেব?
ইংরেজি বাক্যটিকে কী হিসেবে ব্যবহার না করে billing.invoice.payNow-এর মতো স্থিতিশীল, অর্থভিত্তিক কী ব্যবহার করুন। এতে কোড রেফারেন্স না বদলিয়েই বা ডুপ্লিকেট অনুবাদ তৈরি না করেই শব্দচয়ন বদলাতে পারবেন।
অনুবাদ ফাইলে কোন টেক্সট রাখতে হবে?
ত্রুটি, খালি অবস্থা, ইমেল, নোটিফিকেশন ও অনবোর্ডিং টিপসসহ ব্যবহারকারীর সামনে দেখা যায় এমন প্রতিটি স্ট্রিং আপনার অনুবাদ ব্যবস্থায় রাখুন। অভ্যন্তরীণ লগ, অ্যানালিটিক্স আইডি ও ডেটাবেস ফিল্ডে সাধারণত অনুবাদ দরকার হয় না।
ওয়েব ও মোবাইলের ভাষা কীভাবে সামঞ্জস্যপূর্ণ রাখব?
উভয় ক্লায়েন্টের জন্য কী ও লোকেল মেসেজের একটি যৌথ ক্যাটালগ ব্যবহার করুন। React ও Flutter ভিন্ন লাইব্রেরি ব্যবহার করতে পারে, তবে তাদের একই কী নাম ও মেসেজ নিয়ম উল্লেখ করা উচিত।
ব্যাকএন্ডের কি অনূদিত ত্রুটি বার্তা ফেরত দেওয়া উচিত?
ব্যাকএন্ড থেকে একটি স্থিতিশীল ত্রুটি কোড ও নিরাপদ মান ফেরত দিন, তারপর ক্লায়েন্টে স্থানীয়কৃত মেসেজ দেখান। উদাহরণস্বরূপ, ইংরেজি বাক্যের বদলে auth.invalid_password ফেরত দিন।
বিভিন্ন ভাষায় বহুবচন কীভাবে সামলাব?
ICU-ধাঁচের বহুবচন মেসেজ ব্যবহার করুন, যাতে প্রতিটি ভাষা নিজের ব্যাকরণগত নিয়ম প্রয়োগ করতে পারে। আলাদাভাবে অনূদিত বিশেষ্যের সঙ্গে সংখ্যা যোগ না করে পুরো বাক্যটি একটি মেসেজে রাখুন।
অনুবাদ ফাইল কোথায় রাখা উচিত?
উৎস লোকেল, যা প্রায়ই ইংরেজি, সেটিকে সত্যের উৎস হিসেবে রাখুন এবং কোডের সঙ্গে পরিবর্তনগুলো পর্যালোচনা করুন। মেসেজগুলো ফিচার অনুযায়ী সাজান এবং সাধারণ অ্যাকশন, ফিল্ড, নেভিগেশন ও ত্রুটির জন্য যৌথ নেমস্পেস সংরক্ষণ করুন।
কপি বদলালেই কি প্রতিবার নতুন কী লাগবে?
শব্দচয়ন বদলালেও অর্থ একই থাকলে আগের কী-ই রাখুন। অর্থ বা প্রসঙ্গ বদলালেই শুধু নতুন কী তৈরি করুন, তারপর কিছুই এটি ব্যবহার করছে না নিশ্চিত হয়ে পুরোনো কীটি সরিয়ে দিন।
তারিখ, টাকা ও টাইম জোন কীভাবে লোকালাইজ করব?
টাইমস্ট্যাম্প UTC-তে সংরক্ষণ করুন, তারপর দর্শকের লোকেল ও টাইম জোন অনুযায়ী তারিখ, সময়, সংখ্যা ও মুদ্রা ফরম্যাট করুন। হার্ড-কোড করা কমা, মুদ্রা চিহ্ন বা তারিখের প্যাটার্নের বদলে লোকেল-সচেতন ফরম্যাটার ব্যবহার করুন।
ডান থেকে বামে লেখা ভাষার জন্য কী পরীক্ষা করা উচিত?
শুধু লেবেল নয়, RTL লোকেলে সম্পূর্ণ স্ক্রিন ডিজাইন করুন। প্রয়োজন হলে লেআউটের দিক বদলান, ব্যাক অ্যারোর মতো দিকনির্দেশক আইকন মিরর করুন এবং পণ্য কোডের মতো মিশ্র আরবি ও লাতিন টেক্সট পরীক্ষা করুন।
বিদ্যমান অ্যাপে i18n যোগ করার সবচেয়ে সহজ উপায় কী?
অনবোর্ডিং, বিলিং বা চেকআউটের মতো ব্যস্ত একটি ফ্লো দিয়ে শুরু করুন। এর হার্ড-কোড করা কপি যৌথ মেসেজে সরান, বহুবচন ও ফরম্যাটিং সহায়তা যোগ করুন, দীর্ঘ অনুবাদ পরীক্ষা করুন, তারপর পরের ফিচারের জন্য একই কাজ করুন।