Skip to main content

Flask i18n: többnyelvű alkalmazás készítése Flask-Babel használatával

A gettext alapjaitól az éles telepítésig: tegye nemzetközivé Flask-alkalmazását Flask-Babel, PO-fájlok és automatizált MI-fordítás használatával.

1

A Flask-Babel telepítése

A Flask-Babel a Flask szabványos nemzetköziesítési bővítménye. A GNU gettext rendszert Flask- és Jinja2-sablonokkal integrálja, és azonnal használható fordítási függvényeket, területválasztást és időzóna-támogatást biztosít.

A Flask-Babel a Babelt (a Python i18n-könyvtárát) burkolja, és a Flask kérés-életciklusába integrálja. gettext(), ngettext() és lazy_gettext() függvényt, továbbá a böngészőfejlécekből automatikus területészlelést biztosít.
Terminal
pip install Flask-Babel
2

A Babel beállítása

Hozzon létre babel.cfg fájlt, amely megadja a pybabel számára a fordítható karakterláncok keresési helyét, majd inicializálja a Flask-Babelt egy területválasztó függvénnyel, amely meghatározza az egyes kérésekhez kiszolgált nyelvet.

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)
A locale_selector függvény minden kérésnél meghívódik. Ha olyan területet ad vissza, amelyhez nincs lefordított .mo fájl, a Flask-Babel csendben az alapértelmezett területre vált. Nem keletkezik hiba — a karakterláncok egyszerűen lefordítatlannak tűnnek.
3

Karakterláncok megjelölése fordításhoz

A Python-kódban minden felhasználóknak szánt karakterláncot csomagoljon gettext(), Jinja2-sablonokban pedig _() hívásba. A modul betöltésekor meghatározott, de később, kéréskor fordítandó karakterláncokhoz (például űrlapcímkékhez és konfigurációhoz) használjon lazy_gettext() függvényt.

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>
Jinja2-sablonokban gettext() helyett használjon _() függvényt — ez a gettext szabványos rövidítése, és tisztán tartja a sablonokat. A Flask-Babel automatikusan globális Jinja2-függvényként regisztrálja az _() függvényt.
4

Üzenetek kinyerése

Futtassa a pybabel extract parancsot a forráskód és sablonok fordítható karakterláncainak átvizsgálásához. Ez .pot (Portable Object Template) fájlt hoz létre. Ezután inicializáljon katalógust minden célnyelvhez, vagy a forrásszöveg változásakor frissítse a meglévőket.

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
Az első kinyerés után mindig pybabel update parancsot futtasson (ne init parancsot). Meglévő nyelvi könyvtáron az init minden meglévő fordítást felülír. Az update az új karakterláncokat a meglévő fordítások megőrzésével egyesíti.
5

PO-fájlok fordítása

Nyissa meg a létrehozott .po fájlokat, és töltse ki minden msgid elem msgstr értékét. A PO-fájlok egyszerű szövegfájlok — közvetlenül szerkesztheti, használhat PO-szerkesztőt, például Poeditet, vagy automatizálhatja a fordítást MI-eszközökkel.

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"
A PO-fájlok kontextusmegjegyzései (#: kezdetű sorok) megmutatják, hol használják az egyes karakterláncokat a forráskódban. A fordítók ezekből értik meg a kontextust. Tartsa meg őket — a pybabel extract automatikusan hozza létre őket.
6

Fordítások lefordítása

A pybabel compile segítségével fordítsa a .po fájlokat bináris .mo fájlokká. A Flask-Babel futásidőben .mo fájlokat olvas — közvetlenül nem tud .po fájlokat olvasni. Minden fordításfrissítés után újra kell fordítania őket.

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.
Ha egy .po fájl szerkesztése után nem jelennek meg a fordítások, szinte biztosan elfelejtette futtatni a pybabel compile parancsot. Ez a leggyakoribb Flask-Babel-probléma. Éles környezetben a megelőzéséhez adja a fordítási lépést a telepítési szkripthez.
7

Többes számok és változók kezelése

Többes számra érzékeny karakterláncokhoz használjon ngettext() függvényt. Egyes számú alakot, többes számú alakot és számot fogad. A Babel automatikusan a megfelelő nyelvi szabályt használja — az angolnak 2, az orosznak 3, az arabnak 6, a japánnak 1 alakja van.

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 товаров в вашей корзине"
Soha ne használjon if count == 1 feltételt többesszám-logikához. A francia a 0 értéket egyes számként kezeli, az orosznak és arabnak pedig az angolban nem létező alakjai vannak. Bízza a kiválasztást az ngettext() függvényre és a Babel CLDR-szabályaira.
8

Területváltás hozzáadása

Készítsen nyelvválasztót, amely a Flask-munkamenetben tárolja a felhasználó választását. Frissítse a locale_selector függvényt úgy, hogy előbb a munkamenetet ellenőrizze, majd a böngészőészlelésre váltson.

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>
A munkamenet területének módosítása után hívja meg a flask_babel.refresh() függvényt, hogy a Flask-Babel az aktuális kéréshez újra beolvassa a területet. refresh() nélkül a régi terület a következő kérésig megmarad.
9

Fordítások automatizálása

A Flask-Babel beállítása után fordítsa le PO-fájljait mesterséges intelligenciával. Automatizálja a kinyerés–fordítás–lefordítás ciklust a CI/CD-folyamatban, hogy a fordítások szinkronban maradjanak a forráskóddal.

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
Fordítson fokozatosan — új karakterláncok hozzáadása és pybabel update futtatása után csak az új, lefordítatlan bejegyzéseket (üres msgstr értékeket) fordítsa le, ne generáljon újra mindent. Így megmaradnak az ember által ellenőrzött fordítások.

Bónusz: intelligens területi tartalék flask-babel-locale-chain használatával

Alapértelmezés szerint a Flask-Babel közvetlenül az alapértelmezett területre vált, ha a felhasználó előnyben részesített területe nem érhető el. A csak pt-PT fordítással rendelkező pt-BR felhasználó portugál helyett angol szöveget lát. A flask-babel-locale-chain beállítható tartalékláncokat ad hozzá, hogy a kapcsolódó területek természetesen kövessék egymást.

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)
A flask-babel-locale-chain nyílt forráskódú Python-csomag. Megtekinthető a GitHubon: github.com/i18n-agent/flask-babel-locale-chain.

A fordítási minőség automatizálása

Az i18n-validate segítségével még kiadás előtt találja meg a hiányzó kulcsokat és hibás helyőrzőket. Az i18n-pseudo használatával valódi fordítások beérkezése előtt tesztelje a felületet pszeudofordításokkal.

Gyakori buktatók

A .po fájl .mo fájllá fordításának elfelejtése

A Flask-Babel lefordított .mo, nem .po fájlokat olvas. Ha a .po fájlok szerkesztése után nem jelennek meg a fordítások, futtassa a pybabel compile -d translations parancsot. Adja ezt a lépést a telepítési szkripthez.

gettext() használata modulszinten

A gettext() kérési kontextust igényel. Ha modulszinten határoz meg lefordított karakterláncokat (osztályattribútumokat, konstansokat), használjon helyette lazy_gettext() függvényt. Ez a tényleges kérésbeli renderelésig halasztja a fordítást.

A kinyerés kihagy karakterláncokat

A pybabel extract csak a babel.cfg mintáira illeszkedő fájlokat vizsgálja. Ha nem nyeri ki a karakterláncokat: ellenőrizze, hogy a babel.cfg mintái megfelelnek-e a fájlszerkezetnek, adja hozzá a -k lazy_gettext kapcsolót a lusta hívásokhoz, és gondoskodjon a Jinja2-sablonok megfelelő kiterjesztéséről (.html, .jinja2).

PO-fájlkódolási hibák

A PO-fájloknak UTF-8 kódolásúaknak kell lenniük. UnicodeDecodeError esetén ellenőrizze a .po fájl Content-Type fejlécét: charset=UTF-8 értéket kell tartalmaznia. Egyes szerkesztők más kódolással mentenek — szerkesztés után mindig ellenőrizze.

Ajánlott fájlszerkezet

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/

Try i18n Agent Now

Drop your translation file here

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

or click to browse

Target languages

No signup requiredInstant estimate

Flask i18n – gyakori kérdések