
Flask i18n: skapa en flerspråkig app med Flask-Babel
Från grunderna i gettext till driftsättning i produktion: internationalisera Flask-appen med Flask-Babel, PO-filer och automatiserad AI-översättning.
Installera Flask-Babel
Flask-Babel är standardtillägget för internationalisering i Flask. Det integrerar GNU gettext med Flask och Jinja2-mallar och ger direkt tillgång till översättningsfunktioner, val av språkvariant och stöd för tidszoner.
pip install Flask-BabelKonfigurera Babel
Skapa filen babel.cfg för att ange var pybabel ska söka efter översättningsbara strängar och initiera sedan Flask-Babel med en funktion som väljer vilken språkvariant som ska användas för varje begäran.
# 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)Markera strängar för översättning
Omslut alla användarsynliga strängar med gettext() i Python-kod och _() i Jinja2-mallar. Använd lazy_gettext() för exempelvis formuläretiketter och konfiguration som definieras när modulen läses in och ska översättas senare under en begäran.
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>Extrahera meddelanden
Kör pybabel extract för att söka igenom källkoden och mallarna efter översättningsbara strängar. Det skapar en .pot-fil (Portable Object Template). Initiera sedan kataloger för varje målspråk eller uppdatera befintliga kataloger när källsträngarna ändras.
# 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Översätt PO-filer
Öppna de genererade .po-filerna och fyll i msgstr-värdena för varje msgid. PO-filer är vanliga textfiler – du kan redigera dem direkt, använda en PO-redigerare som Poedit eller automatisera översättningen med AI-verktyg.
# 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"Kompilera översättningar
Kompilera .po-filerna till binära .mo-filer med pybabel compile. Flask-Babel läser .mo-filer under körning och kan inte läsa .po-filer direkt. Du måste kompilera om efter varje översättningsuppdatering.
# 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.Hantera pluralformer och variabler
Använd ngettext() för strängar som påverkas av pluralformer. Funktionen tar en singularform, en pluralform och antalet. Babel använder automatiskt rätt pluralregel för varje språk – engelska har 2 former, medan ryska har 3, arabiska 6 och japanska 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 товаров в вашей корзине"Lägg till språkbyte
Skapa en språkväljare som lagrar användarens val i Flask-sessionen. Uppdatera funktionen locale_selector så att den först kontrollerar sessionen och därefter går vidare till webbläsaridentifiering.
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>Automatisera översättningar
När Flask-Babel-konfigurationen är klar kan du översätta PO-filerna med AI. Automatisera cykeln extrahera–översätt–kompilera i CI/CD-pipelinen så att översättningarna hålls synkroniserade med källkoden.
# 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: smarta reservspråk med flask-babel-locale-chain
Som standard går Flask-Babel direkt till den förvalda språkvarianten när användarens föredragna variant inte är tillgänglig. En användare med pt-BR och enbart pt-PT-översättningar ser engelska i stället för portugisiska. flask-babel-locale-chain lägger till konfigurerbara reservkedjor så att närliggande språkvarianter används i en naturlig ordning.
# 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)Automatisera kvalitetskontrollen av översättningar
Vanliga fallgropar
.po har inte kompilerats till .mo
gettext() används på modulnivå
Strängar missas vid extraheringen
Kodningsfel i PO-filer
Rekommenderad 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/Prova i18n Agent nu
Släpp din översättningsfil här
JSON, YAML, PO, XML, CSV, Markdown, Properties
eller klicka för att välja en fil
Målspråk