
Flask i18n: kurkite daugiakalbę programą su Flask-Babel
Nuo gettext pagrindų iki diegimo gamybinėje aplinkoje: internacionalizuokite Flask programą naudodami Flask-Babel, PO failus ir automatizuotą DI vertimą.
Įdiegti Flask-Babel
Flask-Babel yra standartinis Flask internacionalizavimo plėtinys. Jis integruoja GNU gettext su Flask ir Jinja2 šablonais, iškart suteikia vertimo funkcijas, lokalių parinkimą ir laiko juostų palaikymą.
pip install Flask-BabelSukonfigūruoti Babel
Sukurkite babel.cfg failą, kuris nurodo pybabel, kur ieškoti verstinų eilučių, tada inicializuokite Flask-Babel su lokalės parinkimo funkcija, nustatančia kiekvienai užklausai pateikiamą kalbą.
# 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)Pažymėti verstinas eilutes
Kiekvieną naudotojams skirtą eilutę Python kode apgaubkite gettext(), o Jinja2 šablonuose – _(). Modulio įkėlimo metu apibrėžtoms eilutėms (pvz., formų etiketėms ir konfigūracijai), kurios turi būti išverstos vėliau užklausos metu, naudokite lazy_gettext().
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>Išskirti pranešimus
Paleiskite pybabel extract, kad nuskaitytumėte pirminį kodą ir šablonus, ieškodami verstinų eilučių. Taip sukuriamas .pot (Portable Object Template) failas. Tada inicializuokite kiekvienos tikslinės kalbos katalogus arba atnaujinkite esamus, kai pasikeičia šaltinio eilutės.
# 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 translationsVersti PO failus
Atidarykite sugeneruotus .po failus ir užpildykite kiekvieno msgid reikšmes msgstr. PO failai yra paprastas tekstas: galite juos redaguoti tiesiogiai, naudoti tokį PO redaktorių kaip Poedit arba automatizuoti vertimą DI įrankiais.
# 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"Sukompiliuoti vertimus
Sukompiliuokite .po failus į dvejetainius .mo failus naudodami pybabel compile. Vykdymo metu Flask-Babel nuskaito .mo failus – jis negali tiesiogiai nuskaityti .po failų. Po kiekvieno vertimo naujinio turite sukompiliuoti iš naujo.
# 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.Apdoroti daugiskaitą ir kintamuosius
Daugiskaitai jautrioms eilutėms naudokite ngettext(). Ji priima vienaskaitos formą, daugiskaitos formą ir skaičių. Babel automatiškai naudoja tinkamą kiekvienos kalbos daugiskaitos taisyklę: anglų kalboje yra 2 formos, rusų – 3, arabų – 6, japonų – 1.
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 товаров в вашей корзине"Pridėti lokalės keitimą
Sukurkite kalbos parinkiklį, kuris saugo naudotojo pasirinkimą Flask seanse. Atnaujinkite funkciją locale_selector, kad ji pirmiausia tikrintų seansą, o tada grįžtų prie naršyklės aptikimo.
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>Automatizuoti vertimus
Baigę Flask-Babel sąranką išverskite PO failus naudodami DI. Automatizuokite išskyrimo, vertimo ir kompiliavimo ciklą CI/CD konvejeryje, kad vertimai liktų sinchronizuoti su pirminiu kodu.
# 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 translationsPapildomai: išmani atsarginė lokalė su flask-babel-locale-chain
Pagal numatytąją nuostatą Flask-Babel iškart grįžta prie numatytosios lokalės, kai pageidaujamos naudotojo lokalės nėra. pt-BR naudotojas, turintis tik pt-PT vertimus, mato anglų, o ne portugalų kalbą. flask-babel-locale-chain prideda konfigūruojamas atsargines grandines, kad susijusios lokalės natūraliai pereitų viena į kitą.
# 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)Automatizuoti vertimo kokybę
Dažnos klaidos
Pamiršta sukompiliuoti .po į .mo
gettext() naudojamas modulio lygiu
Išskyrimas praleidžia eilutes
PO failo koduotės klaidos
Rekomenduojama failų struktūra
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/Išbandykite i18n Agent dabar
Nuvilkite vertimo failą čia
JSON, YAML, PO, XML, CSV, Markdown, Properties
arba spustelėkite norėdami pasirinkti
Tikslinės kalbos