
Flask i18n: Byg en flersproget app med Flask-Babel
Fra det grundlæggende i gettext til udrulning i produktion: Internationaliser din Flask-app med Flask-Babel, PO-filer og automatiseret AI-oversættelse.
Installer Flask-Babel
Flask-Babel er standardudvidelsen til internationalisering i Flask. Den integrerer GNU gettext med Flask- og Jinja2-skabeloner og leverer oversættelsesfunktioner, locale-valg og understøttelse af tidszoner fra starten.
pip install Flask-BabelKonfigurer Babel
Opret en babel.cfg-fil for at fortælle pybabel, hvor der skal søges efter strenge, som kan oversættes. Initialiser derefter Flask-Babel med en locale-vælgerfunktion, der bestemmer, hvilket sprog der skal vises ved hver request.
# 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)Markér strenge til oversættelse
Omgiv alle brugervendte strenge med gettext() i Python-kode og _() i Jinja2-skabeloner. Brug lazy_gettext() til strenge, der defineres, når modulet indlæses (f.eks. formularetiketter og konfiguration) og som først skal oversættes senere ved en request.
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>Udtræk meddelelser
Kør pybabel extract for at gennemgå din kildekode og dine skabeloner for strenge, der kan oversættes. Det opretter en .pot-fil (Portable Object Template). Initialiser derefter kataloger for hvert målsprog eller opdater eksisterende kataloger, når kildestrengene ændres.
# 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 translationsOversæt PO-filer
Åbn de genererede .po-filer og udfyld msgstr-værdierne for hver msgid. PO-filer er almindelig tekst — du kan redigere dem direkte, bruge en PO-editor som Poedit eller automatisere oversættelsen med AI-værktøjer.
# 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"Kompilér oversættelser
Kompilér dine .po-filer til binære .mo-filer med pybabel compile. Flask-Babel læser .mo-filer under kørsel — den kan ikke læse .po-filer direkte. Du skal kompilere igen efter hver opdatering af oversættelserne.
# 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.Håndter flertalsformer og variabler
Brug ngettext() til strenge, der afhænger af flertal. Funktionen modtager en entalsform, en flertalsform og antallet. Babel bruger automatisk den korrekte flertalsregel for hvert sprog — engelsk har 2 former, mens russisk har 3, arabisk har 6 og japansk har 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 товаров в вашей корзине"Tilføj skift af locale
Byg en sprogvælger, der gemmer brugerens valg i Flask-sessionen. Opdater din locale_selector-funktion, så den først kontrollerer sessionen og derefter går tilbage til browserregistrering.
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>Automatiser oversættelser
Når din Flask-Babel-opsætning er klar, kan du oversætte dine PO-filer med AI. Automatiser cyklussen udtræk-oversæt-kompilér i din CI/CD-pipeline for at holde oversættelserne synkroniseret med kildekoden.
# 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 translationsEkstra: Intelligent locale-fallback med flask-babel-locale-chain
Som standard går Flask-Babel direkte tilbage til standardlocale, når brugerens foretrukne locale ikke er tilgængelig. En pt-BR-bruger med kun pt-PT-oversættelser ser engelsk i stedet for portugisisk. flask-babel-locale-chain tilføjer konfigurerbare fallbackkæder, så beslægtede locales bruges i en naturlig rækkefølge.
# 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)Automatiser oversættelseskvaliteten
Almindelige faldgruber
Glemte at kompilere .po til .mo
Brug af gettext() på modulniveau
Strenge mangler ved udtrækning
Kodningsfejl i PO-filer
Anbefalet filstruktur
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/Prøv i18n Agent nu
Slip din oversættelsesfil her
JSON, YAML, PO, XML, CSV, Markdown, Properties
eller klik for at vælge en fil
Målsprog