Skip to main content

Flask i18n: napravite višejezičnu aplikaciju pomoću Flask-Babel

Od osnova gettext sistema do postavljanja u produkciju: internacionalizujte Flask aplikaciju pomoću Flask-Babel, PO datoteka i automatizovanog AI prevođenja.

1

Instalirajte Flask-Babel

Flask-Babel je standardni dodatak za Flask internacionalizaciju. Integriše GNU gettext sa Flask i Jinja2 šablonima i odmah pruža funkcije za prevođenje, izbor lokala i podršku za vremenske zone.

Flask-Babel obuhvata Babel (Python i18n biblioteku) i integriše ga sa životnim ciklusom Flask zahteva. Pruža funkcije gettext(), ngettext() i lazy_gettext(), kao i automatsko otkrivanje lokala iz zaglavlja pregledača.
Terminal
pip install Flask-Babel
2

Podesite Babel

Napravite datoteku babel.cfg da alatki pybabel navedete gde da traži prevodive tekstove, a zatim inicijalizujte Flask-Babel funkcijom za izbor lokala koja određuje jezik za svaki zahtev.

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 poziva se pri svakom zahtevu. Ako vrati lokal koji nema kompajliranu .mo datoteku, Flask-Babel neprimetno prelazi na podrazumevani lokal. Ne baca se greška — tekstovi samo izgledaju neprevedeno.
3

Označite tekstove za prevođenje

Obuhvatite svaki tekst namenjen korisniku funkcijom gettext() u Python kodu i _() u Jinja2 šablonima. Koristite lazy_gettext() za tekstove definisane tokom učitavanja modula (kao što su oznake obrazaca i konfiguracija) koji treba da se prevedu kasnije, tokom zahteva.

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>
U Jinja2 šablonima koristite _() umesto gettext() — to je standardna gettext skraćenica koja održava šablone čistim. Flask-Babel automatski registruje _() kao Jinja2 globalnu funkciju.
4

Izdvojte poruke

Pokrenite pybabel extract da skenirate izvorni kod i šablone u potrazi za prevodivim tekstovima. Time se pravi .pot (Portable Object Template) datoteka. Zatim inicijalizujte kataloge za svaki ciljni jezik ili ažurirajte postojeće kada se izvorni tekstovi promene.

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
Posle prvog izdvajanja uvek pokrenite pybabel update (ne init). Pokretanje init komande nad postojećim direktorijumom jezika zamenjuje sve postojeće prevode. Komanda update spaja nove tekstove uz očuvanje postojećih prevoda.
5

Prevedite PO datoteke

Otvorite generisane .po datoteke i popunite vrednosti msgstr za svaki msgid. PO datoteke su običan tekst — možete direktno da ih uređujete, koristite PO uređivač kao što je Poedit ili automatizujete prevođenje pomoću AI alatki.

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 datoteke sadrže komentare konteksta (redove koji počinju sa #:) koji pokazuju gde se svaki tekst koristi u izvornom kodu. Prevodioci ih koriste da razumeju kontekst. Sačuvajte ih — pybabel extract ih generiše automatski.
6

Kompajlirajte prevode

Kompajlirajte .po datoteke u binarne .mo datoteke pomoću pybabel compile komande. Flask-Babel tokom izvršavanja čita .mo datoteke — ne može direktno da čita .po datoteke. Morate ponovo da ih kompajlirate posle svakog ažuriranja prevoda.

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.
Ako se prevodi ne pojave nakon uređivanja .po datoteke, gotovo sigurno ste zaboravili da pokrenete pybabel compile. To je najčešći problem sa Flask-Babel sistemom. Dodajte korak kompajliranja u skriptu za postavljanje da ga izbegnete u produkciji.
7

Obradite množinu i promenljive

Koristite ngettext() za tekstove osetljive na množinu. Funkcija prima oblik jednine, oblik množine i broj. Babel automatski koristi ispravno pravilo množine za svaki jezik — engleski ima 2 oblika, ruski 3, arapski 6, a japanski 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 товаров в вашей корзине"
Nikada ne koristite if count == 1 za logiku množine. Jezici poput francuskog tretiraju 0 kao jedninu. Ruski i arapski imaju oblike koje engleski nema. Prepustite izbor funkciji ngettext() i CLDR pravilima množine biblioteke Babel.
8

Dodajte promenu lokala

Napravite birač jezika koji čuva izbor korisnika u Flask sesiji. Ažurirajte funkciju locale_selector tako da prvo proveri sesiju, pa pređe na otkrivanje iz pregledač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>
Nakon promene lokala sesije pozovite flask_babel.refresh() da primorate Flask-Babel da ponovo pročita lokal za trenutni zahtev. Bez refresh(), stari lokal ostaje do sledećeg zahteva.
9

Automatizujte prevode

Kada završite podešavanje Flask-Babel sistema, prevedite PO datoteke pomoću AI tehnologije. Automatizujte ciklus izdvajanja, prevođenja i kompajliranja u CI/CD pipeline sistemu da prevodi ostanu usklađeni sa izvornim kodom.

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
Prevodite postepeno — kada dodate nove tekstove i pokrenete pybabel update, prevedite samo nove neprevedene stavke (prazne vrednosti msgstr) umesto ponovnog generisanja svega. Time se čuvaju prevodi koje su ljudi pregledali.

Dodatno: pametni rezervni lokali uz flask-babel-locale-chain

Flask-Babel podrazumevano odmah prelazi na podrazumevani lokal kada željeni lokal korisnika nije dostupan. Korisnik lokala pt-BR koji ima samo prevode za pt-PT vidi engleski umesto portugalskog. flask-babel-locale-chain dodaje podesive lance rezervnih lokala kako bi se srodni lokali prirodno nadovezivali.

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 Python paket otvorenog koda. Pogledajte ga na GitHub platformi na adresi github.com/i18n-agent/flask-babel-locale-chain.

Automatizujte kvalitet prevoda

Pomoću i18n-validate alatke otkrijte nedostajuće ključeve i neispravne čuvare mesta pre isporuke. Testirajte korisnički interfejs pseudoprevodima pomoću i18n-pseudo alatke pre nego što stignu pravi prevodi.

Uobičajene zamke

Zaboravljeno kompajliranje .po u .mo

Flask-Babel čita kompajlirane .mo datoteke, a ne .po datoteke. Ako se prevodi ne pojave nakon uređivanja .po datoteka, pokrenite pybabel compile -d translations. Dodajte ovaj korak u skriptu za postavljanje.

Upotreba gettext() na nivou modula

gettext() zahteva kontekst zahteva. Ako definišete prevedene tekstove na nivou modula (atribute klasa, konstante), koristite lazy_gettext(). On odlaže prevođenje dok se tekst zaista ne prikaže u zahtevu.

Izdvajanje propušta tekstove

pybabel extract skenira samo datoteke koje odgovaraju obrascima u babel.cfg. Ako tekstovi nisu izdvojeni: proverite da li babel.cfg obrasci odgovaraju strukturi datoteka, dodajte -k lazy_gettext da izdvojite lenje pozive i proverite da li Jinja2 šabloni koriste ispravan nastavak (.html, .jinja2).

Greške kodiranja PO datoteke

PO datoteke moraju da budu kodirane kao UTF-8. Ako vidite UnicodeDecodeError, proverite Content-Type zaglavlje u .po datoteci: treba da sadrži charset=UTF-8. Neki uređivači čuvaju datoteke u drugom kodiranju — uvek proverite nakon uređivanja.

Preporučena struktura datoteka

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/

Isprobajte i18n Agent sada

Pustite datoteku za prevođenje ovde

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

ili kliknite za izbor

Ciljni jezici

Registracija nije potrebnaTrenutna procena

Česta pitanja o Flask i18n sistemu