
Flask i18n: creați o aplicație multilingvă cu Flask-Babel
De la noțiunile de bază gettext până la implementarea în producție: internaționalizați aplicația Flask cu Flask-Babel, fișiere PO și traducere automată cu IA.
Instalați Flask-Babel
Flask-Babel este extensia standard de internaționalizare pentru Flask. Aceasta integrează GNU gettext cu Flask și șabloanele Jinja2, oferind din start funcții de traducere, selectarea setărilor regionale și compatibilitate cu fusurile orare.
pip install Flask-BabelConfigurați Babel
Creați un fișier babel.cfg pentru a-i indica lui pybabel unde să caute șirurile traductibile, apoi inițializați Flask-Babel cu o funcție de selectare a setării regionale care stabilește limba furnizată pentru fiecare solicitare.
# babel.cfg — tells pybabel where to find translatable strings
[python: **.py]
[jinja2: **/templates/**.html]
extensions=jinja2.ext.autoescape,jinja2.ext.with_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)Marcați șirurile pentru traducere
Încadrați fiecare șir destinat utilizatorilor cu gettext() în codul Python și cu _() în șabloanele Jinja2. Utilizați lazy_gettext() pentru șirurile definite la încărcarea modulului (precum etichetele formularelor și configurările) care trebuie traduse ulterior, la prelucrarea solicitării.
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')){# 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>Extrageți mesajele
Executați pybabel extract pentru a scana codul sursă și șabloanele după șiruri traductibile. Comanda creează un fișier .pot (Portable Object Template). Apoi inițializați cataloagele pentru fiecare limbă-țintă sau actualizați-le pe cele existente când se modifică șirurile sursă.
# 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 translationsTraduceți fișierele PO
Deschideți fișierele .po generate și completați valorile msgstr pentru fiecare msgid. Fișierele PO sunt text simplu — le puteți edita direct, puteți utiliza un editor PO precum Poedit sau puteți automatiza traducerea cu instrumente bazate pe IA.
# 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"Compilați traducerile
Compilați fișierele .po în fișiere binare .mo utilizând pybabel compile. Flask-Babel citește fișiere .mo în timpul execuției — nu poate citi direct fișiere .po. Trebuie să recompilați după fiecare actualizare a traducerilor.
# 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.Gestionați formele de plural și variabilele
Utilizați ngettext() pentru șirurile care depind de plural. Funcția primește o formă de singular, una de plural și numărul. Babel utilizează automat regula de plural corectă pentru fiecare limbă — engleza are 2 forme, rusa 3, araba 6, iar japoneza una singură.
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)# 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 товаров в вашей корзине"Adăugați schimbarea setării regionale
Creați un selector de limbă care stochează alegerea utilizatorului în sesiunea Flask. Actualizați funcția locale_selector pentru a verifica mai întâi sesiunea, apoi pentru a reveni la detectarea din browser.
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']
){# 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>Automatizați traducerile
După finalizarea configurării Flask-Babel, traduceți fișierele PO cu IA. Automatizați ciclul extragere-traducere-compilare în fluxul CI/CD pentru a păstra traducerile sincronizate cu codul sursă.
# 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 translationsBonus: mecanisme inteligente de rezervă cu flask-babel-locale-chain
În mod implicit, Flask-Babel revine direct la setarea regională implicită când setarea regională preferată a utilizatorului nu este disponibilă. Un utilizator pt-BR care are disponibile numai traduceri pt-PT vede engleză în loc de portugheză. flask-babel-locale-chain adaugă lanțuri de rezervă configurabile, astfel încât setările regionale înrudite să fie parcurse firesc.
# 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)Automatizați verificarea calității traducerilor
Capcane frecvente
Ați uitat să compilați .po în .mo
Utilizarea gettext() la nivel de modul
La extragere lipsesc șiruri
Erori de codificare în fișierele PO
Structura recomandată a fișierelor
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/Încercați acum i18n Agent
Plasați aici fișierul de traducere
JSON, YAML, PO, XML, CSV, Markdown, Properties
sau faceți clic pentru a-l selecta
Limbi țintă