Skip to main content

Flask i18n: Flask-Babel के साथ बहुभाषी ऐप बनाएँ

gettext की बुनियादी बातों से लेकर प्रोडक्शन डिप्लॉयमेंट तक: Flask-Babel, PO फ़ाइलों और स्वचालित AI अनुवाद से अपने Flask ऐप का अंतरराष्ट्रीयकरण करें।

1

Flask-Babel इंस्टॉल करें

Flask-Babel, Flask के लिए मानक अंतरराष्ट्रीयकरण एक्सटेंशन है। यह GNU gettext को Flask और Jinja2 टेम्प्लेट के साथ इंटीग्रेट करता है तथा अनुवाद फ़ंक्शन, लोकेल चयन और टाइमज़ोन सपोर्ट पहले से उपलब्ध कराता है।

Flask-Babel, Babel (Python i18n लाइब्रेरी) को रैप करके उसे Flask के रिक्वेस्ट लाइफ़साइकल के साथ इंटीग्रेट करता है। यह आपको gettext(), ngettext() और lazy_gettext() फ़ंक्शन के साथ ब्राउज़र हेडर से स्वचालित लोकेल पहचान भी देता है।
Terminal
pip install Flask-Babel
2

Babel कॉन्फ़िगर करें

pybabel को यह बताने के लिए babel.cfg फ़ाइल बनाएँ कि अनुवाद योग्य स्ट्रिंग कहाँ खोजनी हैं। फिर Flask-Babel को ऐसे locale selector फ़ंक्शन के साथ इनिशियलाइज़ करें जो हर रिक्वेस्ट के लिए उपलब्ध कराई जाने वाली भाषा निर्धारित करे।

babel.cfg
# babel.cfg — tells pybabel where to find translatable strings
[python: **.py]
[jinja2: **/templates/**.html]
extensions=jinja2.ext.autoescape,jinja2.ext.with_
app.py
from flask import Flask, request
from flask_babel import Babel

app = Flask(__name__)
app.config['BABEL_DEFAULT_LOCALE'] = 'en'
app.config['BABEL_DEFAULT_TIMEZONE'] = 'UTC'
# Directory where translations live (default: "translations")
app.config['BABEL_TRANSLATION_DIRECTORIES'] = 'translations'

def get_locale():
    # 1. Check URL parameter or session
    # 2. Fall back to browser Accept-Language header
    return request.accept_languages.best_match(['en', 'de', 'ja', 'es', 'fr'])

babel = Babel(app, locale_selector=get_locale)
locale_selector फ़ंक्शन हर रिक्वेस्ट पर कॉल किया जाता है। यदि यह ऐसा लोकेल लौटाता है जिसकी कंपाइल की गई .mo फ़ाइल उपलब्ध नहीं है, तो Flask-Babel बिना कोई सूचना दिए डिफ़ॉल्ट लोकेल का उपयोग करता है। कोई त्रुटि नहीं आती—स्ट्रिंग केवल अनुवाद के बिना दिखाई देती हैं।
3

अनुवाद के लिए स्ट्रिंग चिह्नित करें

Python कोड में हर यूज़र को दिखाई देने वाली स्ट्रिंग को gettext() और Jinja2 टेम्प्लेट में _() से रैप करें। मॉड्यूल लोड होने के समय निर्धारित की गई उन स्ट्रिंग के लिए lazy_gettext() का उपयोग करें जिन्हें बाद में रिक्वेस्ट के समय अनुवाद करना हो, जैसे फ़ॉर्म लेबल और कॉन्फ़िगरेशन।

app.py
from flask_babel import gettext, ngettext, lazy_gettext

# In views — gettext() for immediate translation
@app.route('/')
def index():
    flash(gettext('Your profile has been updated.'))
    return render_template('index.html',
        title=gettext('Home'))

# In forms/config — lazy_gettext() for deferred translation
class LoginForm(FlaskForm):
    username = StringField(lazy_gettext('Username'))
    password = PasswordField(lazy_gettext('Password'))
    submit = SubmitField(lazy_gettext('Sign In'))
templates/index.html
{# In Jinja2 templates, use _() shorthand for gettext #}
<h1>{{ _('Welcome to our app') }}</h1>

<p>{{ _('Hello, %(name)s!', name=user.name) }}</p>

<footer>
  {{ _('Copyright %(year)s Example Corp.', year=2026) }}
</footer>
Jinja2 टेम्प्लेट में gettext() के बजाय _() का उपयोग करें—यह gettext का मानक संक्षिप्त रूप है और आपके टेम्प्लेट को साफ़ रखता है। Flask-Babel, _() को अपने-आप Jinja2 ग्लोबल के रूप में रजिस्टर करता है।
4

संदेश एक्सट्रैक्ट करें

अनुवाद योग्य स्ट्रिंग खोजने के लिए अपने सोर्स कोड और टेम्प्लेट को स्कैन करने हेतु pybabel extract चलाएँ। इससे एक .pot (Portable Object Template) फ़ाइल बनती है। इसके बाद हर लक्ष्य भाषा के लिए कैटलॉग इनिशियलाइज़ करें या सोर्स स्ट्रिंग बदलने पर मौजूदा कैटलॉग अपडेट करें।

Terminal
# Extract translatable strings from source code
pybabel extract -F babel.cfg -k lazy_gettext -o messages.pot .

# Initialize a new language (first time only)
pybabel init -i messages.pot -d translations -l de
pybabel init -i messages.pot -d translations -l ja
pybabel init -i messages.pot -d translations -l es

# Update existing catalogs when source strings change
pybabel update -i messages.pot -d translations
पहली बार एक्सट्रैक्ट करने के बाद हमेशा pybabel update चलाएँ, init नहीं। किसी मौजूदा भाषा डायरेक्टरी पर init चलाने से सभी मौजूदा अनुवाद ओवरराइट हो जाते हैं। update कमांड मौजूदा अनुवादों को सुरक्षित रखते हुए नई स्ट्रिंग मर्ज करता है।
5

PO फ़ाइलों का अनुवाद करें

जनरेट की गई .po फ़ाइलें खोलें और हर msgid के लिए msgstr मान भरें। PO फ़ाइलें प्लेन टेक्स्ट होती हैं—आप उन्हें सीधे एडिट कर सकते हैं, Poedit जैसे PO एडिटर का उपयोग कर सकते हैं या AI टूल से अनुवाद स्वचालित कर सकते हैं।

translations/de/LC_MESSAGES/messages.po
# translations/de/LC_MESSAGES/messages.po
msgid "Welcome to our app"
msgstr "Willkommen in unserer App"

msgid "Hello, %(name)s!"
msgstr "Hallo, %(name)s!"

msgid "Your profile has been updated."
msgstr "Ihr Profil wurde aktualisiert."

msgid "Username"
msgstr "Benutzername"

msgid "Password"
msgstr "Passwort"

msgid "Sign In"
msgstr "Anmelden"
PO फ़ाइलों में कॉन्टेक्स्ट कमेंट (उन पंक्तियों में जो #: से शुरू होती हैं) शामिल होते हैं, जो दिखाते हैं कि हर स्ट्रिंग आपके सोर्स कोड में कहाँ उपयोग हुई है। अनुवादक कॉन्टेक्स्ट समझने के लिए इनका उपयोग करते हैं। इन्हें बनाए रखें—ये pybabel extract से अपने-आप जनरेट होते हैं।
6

अनुवाद कंपाइल करें

pybabel compile का उपयोग करके अपनी .po फ़ाइलों को बाइनरी .mo फ़ाइलों में कंपाइल करें। Flask-Babel रनटाइम पर .mo फ़ाइलें पढ़ता है—यह .po फ़ाइलें सीधे नहीं पढ़ सकता। हर अनुवाद अपडेट के बाद आपको दोबारा कंपाइल करना होगा।

Terminal
# Compile .po files to binary .mo files (required at runtime)
pybabel compile -d translations

# Flask-Babel reads .mo files, not .po files.
# You MUST compile after every translation update.
यदि .po फ़ाइल एडिट करने के बाद अनुवाद दिखाई नहीं देते, तो लगभग निश्चित रूप से आप pybabel compile चलाना भूल गए हैं। यह Flask-Babel से जुड़ी सबसे आम समस्या है। प्रोडक्शन में इससे बचने के लिए अपने डिप्लॉयमेंट स्क्रिप्ट में कंपाइल चरण जोड़ें।
7

बहुवचन और वेरिएबल संभालें

बहुवचन के अनुसार बदलने वाली स्ट्रिंग के लिए ngettext() का उपयोग करें। यह एकवचन रूप, बहुवचन रूप और संख्या लेता है। Babel हर भाषा के लिए सही बहुवचन नियम अपने-आप लागू करता है—अंग्रेज़ी में 2 रूप हैं, लेकिन रूसी में 3, अरबी में 6 और जापानी में 1।

app.py
from flask_babel import ngettext

@app.route('/cart')
def cart():
    count = len(session.get('cart_items', []))
    message = ngettext(
        '%(num)d item in your cart',     # singular
        '%(num)d items in your cart',    # plural
        count                             # determines which form
    )
    return render_template('cart.html', message=message)
Plural forms in .po files
# English: 2 forms (nplurals=2)
msgid "%(num)d item in your cart"
msgid_plural "%(num)d items in your cart"
msgstr[0] "%(num)d item in your cart"
msgstr[1] "%(num)d items in your cart"

# German: 2 forms (nplurals=2)
msgid "%(num)d item in your cart"
msgid_plural "%(num)d items in your cart"
msgstr[0] "%(num)d Artikel in Ihrem Warenkorb"
msgstr[1] "%(num)d Artikel in Ihrem Warenkorb"

# Japanese: 1 form (nplurals=1)
msgid "%(num)d item in your cart"
msgid_plural "%(num)d items in your cart"
msgstr[0] "カートに%(num)d個の商品があります"

# Russian: 3 forms (nplurals=3)
msgid "%(num)d item in your cart"
msgid_plural "%(num)d items in your cart"
msgstr[0] "%(num)d товар в вашей корзине"
msgstr[1] "%(num)d товара в вашей корзине"
msgstr[2] "%(num)d товаров в вашей корзине"
बहुवचन लॉजिक के लिए कभी भी if count == 1 का उपयोग न करें। फ़्रेंच जैसी भाषाएँ 0 को एकवचन मानती हैं। रूसी और अरबी में ऐसे रूप हैं जो अंग्रेज़ी में नहीं होते। चयन का काम ngettext() और Babel के CLDR बहुवचन नियमों पर छोड़ें।
8

लोकेल बदलने की सुविधा जोड़ें

ऐसा भाषा चयनकर्ता बनाएँ जो यूज़र की पसंद को Flask सेशन में सेव करे। अपने locale_selector फ़ंक्शन को इस तरह अपडेट करें कि वह पहले सेशन जाँचे और फिर ब्राउज़र की पहचान का उपयोग करे।

app.py
from flask import session, redirect, url_for, request
from flask_babel import refresh

@app.route('/set-language/<lang>')
def set_language(lang):
    session['lang'] = lang
    refresh()  # Force Flask-Babel to re-read the locale
    return redirect(request.referrer or url_for('index'))

# Update get_locale to check session first
def get_locale():
    # 1. Explicit user choice (stored in session)
    if 'lang' in session:
        return session['lang']
    # 2. Browser Accept-Language header
    return request.accept_languages.best_match(
        ['en', 'de', 'ja', 'es', 'fr']
    )
templates/components/language_switcher.html
{# Language switcher component #}
<nav class="language-switcher">
  {% for lang, name in [('en','English'),('de','Deutsch'),
                         ('ja','日本語'),('es','Español'),
                         ('fr','Français')] %}
    <a href="{{ url_for('set_language', lang=lang) }}"
       class="{{ 'active' if get_locale() == lang }}">
      {{ name }}
    </a>
  {% endfor %}
</nav>
सेशन लोकेल बदलने के बाद, मौजूदा रिक्वेस्ट के लिए Flask-Babel को लोकेल दोबारा पढ़ने हेतु बाध्य करने के लिए flask_babel.refresh() कॉल करें। refresh() के बिना पुराना लोकेल अगली रिक्वेस्ट तक बना रहता है।
9

अनुवाद स्वचालित करें

Flask-Babel सेटअप पूरा होने के बाद AI का उपयोग करके अपनी PO फ़ाइलों का अनुवाद करें। अनुवादों को सोर्स कोड के अनुरूप बनाए रखने के लिए अपनी CI/CD पाइपलाइन में एक्सट्रैक्ट-अनुवाद-कंपाइल चक्र स्वचालित करें।

Terminal
# Translate your PO files with AI directly from your IDE
# or use the CLI in CI/CD:
npx i18n-agent translate translations/de/LC_MESSAGES/messages.po \
  --source-lang en --target-lang de

# Bulk translate all languages at once:
npx i18n-agent translate messages.pot --lang de,ja,es,fr

# Then compile:
pybabel compile -d translations
क्रमिक रूप से अनुवाद करें—नई स्ट्रिंग जोड़कर pybabel update चलाने के बाद सब कुछ दोबारा जनरेट करने के बजाय केवल नई, अनूदित न हुई एंट्रीज़ (खाली msgstr मान वाली) का अनुवाद करें। इससे मानव द्वारा समीक्षित अनुवाद सुरक्षित रहते हैं।

बोनस: flask-babel-locale-chain के साथ स्मार्ट लोकेल फ़ॉलबैक

डिफ़ॉल्ट रूप से, यूज़र का पसंदीदा लोकेल उपलब्ध न होने पर Flask-Babel सीधे डिफ़ॉल्ट लोकेल का उपयोग करता है। केवल pt-PT अनुवाद उपलब्ध होने पर pt-BR यूज़र को पुर्तगाली के बजाय अंग्रेज़ी दिखाई देती है। flask-babel-locale-chain कॉन्फ़िगर करने योग्य फ़ॉलबैक चेन जोड़ता है, ताकि संबंधित लोकेल स्वाभाविक क्रम में इस्तेमाल किए जाएँ।

app.py
# pip install flask-babel-locale-chain
from flask_babel_locale_chain import LocaleChain

# Define fallback chains: pt-BR falls back to pt before en
locale_chain = LocaleChain({
    'pt-BR': ['pt-BR', 'pt', 'en'],
    'pt-PT': ['pt-PT', 'pt', 'en'],
    'zh-Hant': ['zh-Hant', 'zh-Hans', 'en'],
    'en-GB': ['en-GB', 'en', 'en-US'],
})

def get_locale():
    requested = request.accept_languages.best_match(
        ['en', 'pt-BR', 'pt', 'zh-Hant', 'zh-Hans']
    )
    # Returns the best available locale from the chain
    return locale_chain.resolve(requested)
flask-babel-locale-chain एक ओपन-सोर्स Python पैकेज है। इसे GitHub पर github.com/i18n-agent/flask-babel-locale-chain पर देखें।

अनुवाद की गुणवत्ता स्वचालित करें

i18n-validate की मदद से गुम कुंजियों और खराब प्लेसहोल्डर को रिलीज़ होने से पहले पहचानें। वास्तविक अनुवाद आने से पहले i18n-pseudo का उपयोग करके छद्म-अनुवादों के साथ अपने UI का परीक्षण करें।

आम समस्याएँ

.po को .mo में कंपाइल करना भूलना

Flask-Babel कंपाइल की गई .mo फ़ाइलें पढ़ता है, .po फ़ाइलें नहीं। यदि .po फ़ाइलें एडिट करने के बाद अनुवाद दिखाई नहीं देते, तो pybabel compile -d translations चलाएँ। इस चरण को अपनी डिप्लॉयमेंट स्क्रिप्ट में जोड़ें।

मॉड्यूल स्तर पर gettext() का उपयोग

gettext() के लिए रिक्वेस्ट कॉन्टेक्स्ट आवश्यक है। यदि आप मॉड्यूल स्तर पर अनूदित स्ट्रिंग निर्धारित करते हैं (क्लास एट्रिब्यूट, कॉन्स्टेंट), तो इसके बजाय lazy_gettext() का उपयोग करें। यह अनुवाद को तब तक टालता है, जब तक स्ट्रिंग वास्तव में किसी रिक्वेस्ट में रेंडर नहीं होती।

एक्सट्रैक्शन में स्ट्रिंग छूटना

pybabel extract केवल babel.cfg के पैटर्न से मेल खाने वाली फ़ाइलें स्कैन करता है। यदि स्ट्रिंग एक्सट्रैक्ट नहीं होती हैं: जाँचें कि babel.cfg के पैटर्न आपकी फ़ाइल संरचना से मेल खाते हैं, लेज़ी कॉल एक्सट्रैक्ट करने के लिए -k lazy_gettext जोड़ें और सुनिश्चित करें कि Jinja2 टेम्प्लेट सही एक्सटेंशन (.html, .jinja2) का उपयोग करते हैं।

PO फ़ाइल एन्कोडिंग त्रुटियाँ

PO फ़ाइलें UTF-8 में एन्कोड होनी चाहिए। यदि आपको UnicodeDecodeError दिखाई देता है, तो अपनी .po फ़ाइल में Content-Type हेडर जाँचें: उसमें charset=UTF-8 होना चाहिए। कुछ एडिटर फ़ाइलों को अलग एन्कोडिंग में सेव करते हैं—एडिट करने के बाद हमेशा सत्यापित करें।

अनुशंसित फ़ाइल संरचना

Project Structure
my-flask-app/
├── app.py                          # Flask app with Babel config
├── babel.cfg                       # Extraction config
├── messages.pot                    # Template (extracted strings)
├── translations/
│   ├── de/
│   │   └── LC_MESSAGES/
│   │       ├── messages.po         # German translations (editable)
│   │       └── messages.mo         # Compiled binary (generated)
│   ├── ja/
│   │   └── LC_MESSAGES/
│   │       ├── messages.po
│   │       └── messages.mo
│   └── es/
│       └── LC_MESSAGES/
│           ├── messages.po
│           └── messages.mo
├── templates/
│   ├── base.html
│   ├── index.html
│   └── components/
│       └── language_switcher.html
├── requirements.txt
└── venv/

i18n Agent अभी आज़माएँ

अपनी अनुवाद फ़ाइल यहाँ छोड़ें

JSON, YAML, PO, XML, CSV, Markdown, Properties

या ब्राउज़ करने के लिए क्लिक करें

लक्षित भाषाएँ

साइन अप की ज़रूरत नहींतुरंत अनुमान

Flask i18n से जुड़े सामान्य प्रश्न