Skip to main content

Flask i18n: vytvorte viacjazyčnú aplikáciu pomocou Flask-Babel

Od základov gettext po produkčné nasadenie: internacionalizujte svoju aplikáciu Flask pomocou Flask-Babel, súborov PO a automatizovaného prekladu pomocou AI.

1

Nainštalujte Flask-Babel

Flask-Babel je štandardné rozšírenie na internacionalizáciu pre Flask. Integruje GNU gettext s Flask a šablónami Jinja2 a hneď po inštalácii ponúka prekladové funkcie, výber lokalizácie a podporu časových pásiem.

Flask-Babel obaľuje Babel (knižnicu i18n pre Python) a integruje ho so životným cyklom požiadaviek Flask. Poskytuje funkcie gettext(), ngettext() a lazy_gettext() aj automatické rozpoznávanie lokalizácie z hlavičiek prehliadača.
Terminal
pip install Flask-Babel
2

Nakonfigurujte Babel

Vytvorte súbor babel.cfg, ktorý nástroju pybabel určí, kde má hľadať preložiteľné reťazce, a potom inicializujte Flask-Babel funkciou na výber lokalizácie, ktorá určí jazyk každej požiadavky.

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)
Funkcia locale_selector sa volá pri každej požiadavke. Ak vráti lokalizáciu bez skompilovaného súboru .mo, Flask-Babel bez hlásenia prejde na predvolenú lokalizáciu. Nevyvolá sa žiadna chyba – reťazce sa iba zobrazia nepreložené.
3

Označte reťazce na preklad

Každý reťazec určený používateľom obaľte funkciou gettext() v kóde Python a _() v šablónach Jinja2. lazy_gettext() používajte pre reťazce definované pri načítaní modulu (napríklad štítky formulárov a konfiguráciu), ktoré sa majú preložiť až neskôr pri požiadavke.

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>
V šablónach Jinja2 používajte _() namiesto gettext() – ide o štandardnú skratku gettext, ktorá udržiava šablóny čisté. Flask-Babel automaticky zaregistruje _() ako globálnu funkciu Jinja2.
4

Extrahujte správy

Spustením pybabel extract vyhľadajte v zdrojovom kóde a šablónach preložiteľné reťazce. Vytvorí sa súbor .pot (Portable Object Template). Potom inicializujte katalógy pre jednotlivé cieľové jazyky alebo pri zmene zdrojových reťazcov aktualizujte existujúce.

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
Po prvej extrakcii vždy spúšťajte pybabel update, nie init. Spustenie init v existujúcom jazykovom adresári prepíše všetky existujúce preklady. Príkaz update zlúči nové reťazce a zachová existujúce preklady.
5

Preložte súbory PO

Otvorte vygenerované súbory .po a vyplňte hodnoty msgstr pre každý msgid. Súbory PO sú obyčajný text – môžete ich upravovať priamo, použiť editor PO, ako je Poedit, alebo preklad automatizovať pomocou nástrojov 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"
Súbory PO obsahujú kontextové komentáre (riadky začínajúce znakmi #:) s miestami použitia jednotlivých reťazcov v zdrojovom kóde. Prekladateľom pomáhajú pochopiť kontext. Zachovajte ich – automaticky ich generuje pybabel extract.
6

Skompilujte preklady

Pomocou pybabel compile skompilujte svoje súbory .po do binárnych súborov .mo. Flask-Babel za behu číta súbory .mo – súbory .po nedokáže čítať priamo. Po každej aktualizácii prekladov ich musíte znova skompilovať.

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.
Ak sa po úprave súboru .po preklady nezobrazia, takmer určite ste zabudli spustiť pybabel compile. Ide o najbežnejší problém Flask-Babel. Pridajte krok kompilácie do svojho nasadzovacieho skriptu, aby ste mu v produkcii predišli.
7

Spracujte tvary množného čísla a premenné

Pre reťazce závislé od množného čísla používajte ngettext(). Prijíma tvar jednotného čísla, tvar množného čísla a počet. Babel automaticky použije správne pravidlo pre každý jazyk – angličtina má 2 tvary, ruština 3, arabčina 6 a japončina 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 товаров в вашей корзине"
Pre logiku množného čísla nikdy nepoužívajte if count == 1. Jazyky ako francúzština považujú 0 za jednotné číslo. Ruština a arabčina majú tvary, ktoré angličtina nemá. Výber nechajte na ngettext() a pravidlá množného čísla CLDR v Babel.
8

Pridajte prepínanie lokalizácií

Vytvorte výber jazyka, ktorý uloží voľbu používateľa do relácie Flask. Aktualizujte funkciu locale_selector tak, aby najprv skontrolovala reláciu a potom použila rozpoznanie prehliadača.

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>
Po zmene lokalizácie relácie zavolajte flask_babel.refresh(), aby Flask-Babel znova načítal lokalizáciu aktuálnej požiadavky. Bez refresh() zostane stará lokalizácia až do ďalšej požiadavky.
9

Automatizujte preklady

Po dokončení nastavenia Flask-Babel preložte svoje súbory PO pomocou AI. Automatizujte cyklus extrakcie, prekladu a kompilácie vo svojej pipeline CI/CD, aby preklady zostali synchronizované so zdrojovým kódom.

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
Prekladajte prírastkovo – po pridaní nových reťazcov a spustení pybabel update preložte iba nové nepreložené položky (prázdne hodnoty msgstr) namiesto opätovného generovania všetkého. Zachováte tak preklady skontrolované človekom.

Bonus: inteligentná náhradná lokalizácia pomocou flask-babel-locale-chain

Keď preferovaná lokalizácia používateľa nie je dostupná, Flask-Babel predvolene prejde priamo na predvolenú lokalizáciu. Používateľ pt-BR tak pri dostupnosti iba prekladov pt-PT uvidí angličtinu namiesto portugalčiny. flask-babel-locale-chain pridáva konfigurovateľné reťazce náhrad, aby súvisiace lokalizácie prirodzene nadväzovali.

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 je open-source balík Python. Nájdete ho na GitHube na github.com/i18n-agent/flask-babel-locale-chain.

Automatizujte kvalitu prekladu

Pomocou i18n-validate odhaľte chýbajúce kľúče a poškodené zástupné symboly ešte pred vydaním. Kým dorazia skutočné preklady, otestujte svoje rozhranie pseudoprekladmi pomocou i18n-pseudo.

Bežné nástrahy

Zabudnutá kompilácia .po do .mo

Flask-Babel číta skompilované súbory .mo, nie súbory .po. Ak sa po úprave súborov .po preklady nezobrazia, spustite pybabel compile -d translations. Tento krok pridajte do svojho nasadzovacieho skriptu.

Používanie gettext() na úrovni modulu

gettext() vyžaduje kontext požiadavky. Ak preložené reťazce definujete na úrovni modulu (atribúty triedy, konštanty), použite namiesto neho lazy_gettext(). Odloží preklad až do skutočného vykreslenia reťazca v požiadavke.

Extrakcia vynecháva reťazce

pybabel extract prehľadáva iba súbory zodpovedajúce vzorom v babel.cfg. Ak sa reťazce neextrahujú, skontrolujte, či vzory babel.cfg zodpovedajú Vašej štruktúre súborov, pridajte -k lazy_gettext na extrakciu lenivých volaní a overte správnu príponu šablón Jinja2 (.html, .jinja2).

Chyby kódovania súborov PO

Súbory PO musia používať kódovanie UTF-8. Ak vidíte UnicodeDecodeError, skontrolujte hlavičku Content-Type vo svojom súbore .po: mala by obsahovať charset=UTF-8. Niektoré editory ukladajú v inom kódovaní – po úprave ho vždy overte.

Odporúčaná štruktúra súborov

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/

Vyskúšajte i18n Agent teraz

Potiahnite súbor na preklad sem

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

alebo kliknite a vyberte súbor

Cieľové jazyky

Bez registrácieOkamžitý odhad

Časté otázky k Flask i18n