Skip to main content

Flask i18n: izdelajte večjezično aplikacijo s Flask-Babelom

Od osnov gettext do uvedbe v produkcijo: internacionalizirajte svojo aplikacijo Flask s Flask-Babelom, datotekami PO in avtomatiziranim prevajanjem z umetno inteligenco.

1

Namestite Flask-Babel

Flask-Babel je standardna razširitev za internacionalizacijo Flaska. GNU gettext poveže s Flaskom in predlogami Jinja2 ter že ob namestitvi zagotovi funkcije za prevajanje, izbiro področnih nastavitev in podporo časovnim pasovom.

Flask-Babel ovije Babel (Pythonovo knjižnico za internacionalizacijo) in ga poveže z življenjskim ciklom zahtevkov v Flasku. Zagotovi funkcije gettext(), ngettext() in lazy_gettext() ter samodejno zaznavanje področnih nastavitev iz glav brskalnika.
Terminal
pip install Flask-Babel
2

Nastavite Babel

Ustvarite datoteko babel.cfg, s katero določite, kje naj pybabel poišče prevedljive nize, nato pa inicializirajte Flask-Babel s funkcijo za izbiro področnih nastavitev, ki za vsak zahtevek določi jezik vsebine.

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)
Funkcija locale_selector se pokliče ob vsakem zahtevku. Če vrne področne nastavitve, za katere ni prevedene datoteke .mo, Flask-Babel brez opozorila uporabi privzete področne nastavitve. Ne prikaže se nobena napaka — nizi preprosto ostanejo neprevedeni.
3

Označite nize za prevajanje

Vsak niz, ki ga vidi uporabnik, v kodi Python ovijte z gettext(), v predlogah Jinja2 pa z _(). Za nize, opredeljene ob nalaganju modula (na primer oznake obrazcev in nastavitve), ki morajo biti prevedeni pozneje med obdelavo zahtevka, uporabite 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>
V predlogah Jinja2 namesto gettext() uporabite _() — to je standardna okrajšava za gettext, zaradi katere so predloge preglednejše. Flask-Babel funkcijo _() samodejno registrira kot globalno funkcijo Jinja2.
4

Izvlecite sporočila

Zaženite pybabel extract, da v izvorni kodi in predlogah poiščete prevedljive nize. S tem ustvarite datoteko .pot (Portable Object Template). Nato inicializirajte kataloge za vsak ciljni jezik oziroma posodobite obstoječe, ko se izvorni nizi spremenijo.

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 prvem izvlečenju vedno zaženite pybabel update (in ne init). Če init zaženete za obstoječo jezikovno mapo, prepišete vse obstoječe prevode. Ukaz update združi nove nize in ohrani obstoječe prevode.
5

Prevedite datoteke PO

Odprite ustvarjene datoteke .po in za vsak msgid izpolnite vrednost msgstr. Datoteke PO so navadno besedilo — urejate jih lahko neposredno, uporabite urejevalnik PO (na primer Poedit) ali pa prevajanje avtomatizirate z orodji umetne inteligence.

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"
Datoteke PO vsebujejo komentarje s kontekstom (vrstice, ki se začnejo z #:), ki kažejo, kje se posamezni niz uporablja v izvorni kodi. Prevajalci si z njimi pomagajo razumeti kontekst. Ohranite jih — pybabel extract jih ustvari samodejno.
6

Prevedite prevode v strojno obliko

Datoteke .po prevedite v binarne datoteke .mo z ukazom pybabel compile. Flask-Babel med izvajanjem bere datoteke .mo — datotek .po ne more brati neposredno. Po vsaki posodobitvi prevodov jih morate znova prevesti v strojno obliko.

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.
Če se prevodi po urejanju datoteke .po ne prikažejo, ste skoraj zagotovo pozabili zagnati pybabel compile. To je najpogostejša težava pri uporabi Flask-Babela. Korak prevajanja v strojno obliko dodajte v skript za uvedbo, da se težavi izognete v produkciji.
7

Obravnavajte množinske oblike in spremenljivke

Za nize, katerih oblika je odvisna od števila, uporabite ngettext(). Funkcija sprejme edninsko obliko, množinsko obliko in število. Babel samodejno uporabi ustrezno pravilo za množinske oblike posameznega jezika — angleščina ima 2 obliki, ruščina 3, arabščina 6, japonščina pa 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 товаров в вашей корзине"
Za določanje množinske oblike nikoli ne uporabite if count == 1. Jeziki, kot je francoščina, število 0 obravnavajo kot ednino. Ruščina in arabščina imata oblike, ki jih angleščina nima. Izbiro prepustite funkciji ngettext() in Babelovim pravilom CLDR za množinske oblike.
8

Dodajte preklapljanje področnih nastavitev

Izdelajte izbirnik jezika, ki uporabnikovo izbiro shrani v sejo Flask. Funkcijo locale_selector posodobite tako, da najprej preveri sejo in šele nato uporabi zaznavanje brskalnika.

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 spremembi področnih nastavitev seje pokličite flask_babel.refresh(), da Flask-Babel prisilite k ponovnemu branju področnih nastavitev za trenutni zahtevek. Brez refresh() se stare področne nastavitve ohranijo do naslednjega zahtevka.
9

Avtomatizirajte prevajanje

Ko je nastavitev Flask-Babela končana, svoje datoteke PO prevedite z umetno inteligenco. Cikel izvlečenja, prevajanja in prevajanja v strojno obliko avtomatizirajte v cevovodu CI/CD, da bodo prevodi usklajeni z izvorno kodo.

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
Prevajajte postopoma — ko dodate nove nize in zaženete pybabel update, prevedite samo nove neprevedene vnose (prazne vrednosti msgstr), namesto da bi znova ustvarili vse prevode. Tako ohranite prevode, ki so jih pregledali ljudje.

Dodatek: pametno nadomestno izbiranje področnih nastavitev s flask-babel-locale-chain

Flask-Babel privzeto uporabi neposredno privzete področne nastavitve, kadar uporabnikove želene področne nastavitve niso na voljo. Uporabnik pt-BR, za katerega so na voljo samo prevodi pt-PT, zato namesto portugalščine vidi angleščino. flask-babel-locale-chain doda nastavljive verige nadomestnih področnih nastavitev, da se sorodne različice jezika uporabijo v naravnem zaporedju.

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 odprtokodni paket Python. Oglejte si ga na GitHubu na naslovu github.com/i18n-agent/flask-babel-locale-chain.

Avtomatizirajte preverjanje kakovosti prevodov

Z orodjem i18n-validate odkrijte manjkajoče ključe in poškodovane označbe mest, preden pridejo v izdajo. Preden prispejo pravi prevodi, svoj uporabniški vmesnik preizkusite s psevdoprevodi z orodjem i18n-pseudo.

Pogoste pasti

Datoteke .po niste prevedli v .mo

Flask-Babel bere prevedene datoteke .mo, ne datotek .po. Če se prevodi po urejanju datotek .po ne prikažejo, zaženite pybabel compile -d translations. Ta korak dodajte v skript za uvedbo.

Uporaba gettext() na ravni modula

gettext() potrebuje kontekst zahtevka. Če prevedene nize določite na ravni modula (atributi razredov, konstante), namesto tega uporabite lazy_gettext(). Ta odloži prevajanje, dokler se niz dejansko ne izriše v zahtevku.

Nizi med izvlečenjem niso zajeti

pybabel extract pregleda samo datoteke, ki se ujemajo z vzorci v babel.cfg. Če nizi niso izvlečeni: preverite, ali se vzorci v babel.cfg ujemajo s strukturo Vaših datotek, dodajte -k lazy_gettext za izvlečenje lenih klicev in poskrbite, da predloge Jinja2 uporabljajo pravilno končnico (.html, .jinja2).

Napake kodiranja datotek PO

Datoteke PO morajo biti kodirane v UTF-8. Če se prikaže UnicodeDecodeError, preverite glavo Content-Type v datoteki .po: vsebovati mora charset=UTF-8. Nekateri urejevalniki shranjujejo datoteke v drugih kodiranjih — po urejanju to vedno preverite.

Priporočena struktura datotek

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/

Preizkusite i18n Agent zdaj

Spustite prevajalsko datoteko sem

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

ali kliknite za izbiro

Ciljni jeziki

Registracija ni potrebnaTakojšnja ocena

Pogosta vprašanja o Flask i18n