Skip to main content

Flask i18n: loo Flask-Babel'iga mitmekeelne rakendus

gettexti põhitõdedest tootmisjuurutuseni: internatsionaliseeri Flask'i rakendus Flask-Babel'i, PO-failide ja automaatse tehisintellekti tõlkega.

1

Paigalda Flask-Babel

Flask-Babel on Flask'i standardne internatsionaliseerimislaiend. See lõimib GNU gettexti Flask'i ja Jinja2 mallidega ning pakub kohe tõlkefunktsioone, lokaadivalikut ja ajavööndite tuge.

Flask-Babel mähib Babel'i (Python'i i18n-teegi) ja lõimib selle Flask'i päringu elutsükliga. See annab funktsioonid gettext(), ngettext() ja lazy_gettext() ning automaatse lokaadituvastuse veebilehitseja päistest.
Terminal
pip install Flask-Babel
2

Seadista Babel

Loo fail babel.cfg, et öelda pybabelile, kust tõlgitavaid stringe otsida, ja lähtesta Flask-Babel seejärel lokaadi valimise funktsiooniga, mis määrab iga päringu jaoks pakutava keele.

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)
Funktsiooni locale_selector kutsutakse igal päringul. Kui see tagastab lokaadi, millel puudub kompileeritud .mo-fail, taandub Flask-Babel märkamatult vaikelokaadile. Tõrget ei visata — stringid näivad lihtsalt tõlkimata.
3

Märgi stringid tõlgitavaks

Mähi iga kasutajale nähtav string Python'i koodis funktsiooniga gettext() ja Jinja2 mallides funktsiooniga _(). Mooduli laadimise ajal määratletud, kuid hiljem päringu ajal tõlgitavate stringide, näiteks vormisiltide ja seadistuse jaoks kasuta lazy_gettext().

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>
Kasuta Jinja2 mallides gettext() asemel _() — see on gettexti standardne lühend ja hoiab mallid puhtana. Flask-Babel registreerib _() automaatselt Jinja2 globaalse funktsioonina.
4

Eralda sõnumid

Käivita pybabel extract, et skannida lähtekoodist ja mallidest tõlgitavaid stringe. See loob .pot (Portable Object Template) faili. Seejärel lähtesta iga sihtkeele kataloogid või värskenda olemasolevaid, kui lähtestringid muutuvad.

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
Pärast esimest eraldamist käivita alati pybabel update, mitte init. Initi käitamine olemasolevas keelekataloogis kirjutab kõik olemasolevad tõlked üle. Update ühendab uued stringid, säilitades olemasolevad tõlked.
5

Tõlgi PO-faile

Ava loodud .po-failid ja täida iga msgid jaoks msgstr-väärtus. PO-failid on lihttekst — saad neid otse muuta, kasutada PO-redaktorit nagu Poedit või automatiseerida tõlkimise tehisintellekti tööriistadega.

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"
PO-failide kontekstikommentaarid (read algusega #:) näitavad, kus iga stringi lähtekoodis kasutatakse. Tõlkijad kasutavad neid konteksti mõistmiseks. Säilita need — pybabel extract loob need automaatselt.
6

Kompileeri tõlked

Kompileeri .po-failid binaarseteks .mo-failideks käsuga pybabel compile. Flask-Babel loeb käitusajal .mo-faile ega saa .po-faile otse lugeda. Pärast iga tõlkevärskendust tuleb need uuesti kompileerida.

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.
Kui tõlked ei ilmu pärast .po-faili muutmist, unustasid peaaegu kindlasti käivitada pybabel compile. See on Flask-Babel'i kõige levinum probleem. Selle vältimiseks tootmiskeskkonnas lisa kompileerimisetapp juurutusskripti.
7

Töötle mitmusevorme ja muutujaid

Kasuta kogusest sõltuvate stringide jaoks ngettext(). See võtab ainsuse, mitmuse ja koguse. Babel kasutab iga keele jaoks automaatselt õiget mitmusereeglit — inglise keeles on kaks vormi, vene keeles kolm, araabia keeles kuus ja jaapani keeles üks.

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 товаров в вашей корзине"
Ära kunagi kasuta mitmuseloogikaks tingimust if count == 1. Sellised keeled nagu prantsuse keel käsitlevad arvu 0 ainsusena. Vene ja araabia keeles on vorme, mida inglise keeles pole. Lase ngettext() funktsioonil ja Babel'i CLDR-i mitmusereeglitel valik teha.
8

Lisa lokaadi vahetamine

Loo keelevalija, mis talletab kasutaja valiku Flask'i seanssi. Värskenda funktsiooni locale_selector, et see kontrolliks esmalt seanssi ja taanduks seejärel veebilehitseja tuvastusele.

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>
Pärast seansi lokaadi muutmist kutsu flask_babel.refresh(), et sundida Flask-Babel'it praeguse päringu lokaati uuesti lugema. Ilma refresh()-ita säilib vana lokaat järgmise päringuni.
9

Automatiseeri tõlked

Kui Flask-Babel on seadistatud, tõlgi PO-failid tehisintellektiga. Automatiseeri eraldamise, tõlkimise ja kompileerimise tsükkel CI/CD-konveieris, et hoida tõlked lähtekoodiga sünkroonis.

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
Tõlgi järk-järgult — kui lisad uusi stringe ja käivitad pybabel update'i, tõlgi kõige uuesti loomise asemel ainult uued tõlkimata kirjed ehk tühjad msgstr-väärtused. Nii säilivad inimeste ülevaadatud tõlked.

Lisavõimalus: nutikas varulokaat flask-babel-locale-chain'iga

Vaikimisi taandub Flask-Babel otse vaikelokaadile, kui kasutaja eelistatud lokaat pole saadaval. pt-BR kasutaja, kellele on olemas ainult pt-PT tõlked, näeb portugali keele asemel inglise keelt. flask-babel-locale-chain lisab seadistatavad varulokaadiahelad, et seotud lokaadid taanduksid loomulikult üksteisele.

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 on avatud lähtekoodiga Python'i pakett. Vaata seda GitHub'is aadressil github.com/i18n-agent/flask-babel-locale-chain.

Automatiseeri tõlkekvaliteet

Leia i18n-validate'i abil puuduvad võtmed ja katkised kohatäitjad enne avaldamist. Testi kasutajaliidest i18n-pseudo abil pseudotõlgetega enne päris tõlgete saabumist.

Levinud komistuskivid

.po-fail jäi .mo-vormingusse kompileerimata

Flask-Babel loeb kompileeritud .mo-faile, mitte .po-faile. Kui tõlked ei ilmu pärast .po-failide muutmist, käivita pybabel compile -d translations. Lisa see etapp juurutusskripti.

gettext() kasutamine moodulitasemel

gettext() nõuab päringukonteksti. Kui määratled tõlgitud stringid moodulitasemel (klassi atribuudid, konstandid), kasuta selle asemel lazy_gettext(). See lükkab tõlkimise edasi ajani, mil string päringus tegelikult renderdatakse.

Eraldamisel jäävad stringid vahele

pybabel extract skannib ainult faili babel.cfg mustritega sobivaid faile. Kui stringe ei eraldata, kontrolli, et babel.cfg mustrid vastaksid failistruktuurile, lisa laiskade kutsete eraldamiseks -k lazy_gettext ning veendu, et Jinja2 mallid kasutaksid õiget faililaiendit (.html, .jinja2).

PO-failide kodeeringuvead

PO-failid peavad olema UTF-8 kodeeringus. Kui näed UnicodeDecodeErrorit, kontrolli .po-faili Content-Type'i päist: seal peab olema charset=UTF-8. Mõned redaktorid salvestavad teise kodeeringuga — kontrolli pärast muutmist alati üle.

Soovituslik failistruktuur

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/

Proovi i18n Agent'i kohe

Kukuta tõlkefail siia

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

või klõpsa faili valimiseks

Sihtkeeled

Registreerumine pole vajalikKohene hinnang

Flask i18n-i KKK