
Flask i18n: Δημιουργήστε μια πολύγλωσση εφαρμογή με Flask-Babel
Από τις βασικές αρχές του gettext έως την ανάπτυξη στην παραγωγή: διεθνοποιήστε την εφαρμογή Flask με το Flask-Babel, αρχεία PO και αυτοματοποιημένη μετάφραση με AI.
Εγκατάσταση του Flask-Babel
Το Flask-Babel είναι η τυπική επέκταση διεθνοποίησης για το Flask. Ενσωματώνει το GNU gettext στο Flask και στα πρότυπα Jinja2, παρέχοντας εξαρχής συναρτήσεις μετάφρασης, επιλογή locale και υποστήριξη ζώνης ώρας.
pip install Flask-BabelΡύθμιση του Babel
Δημιουργήστε ένα αρχείο babel.cfg για να υποδείξετε στο pybabel πού θα αναζητήσει μεταφράσιμες συμβολοσειρές και, στη συνέχεια, αρχικοποιήστε το Flask-Babel με μια συνάρτηση επιλογής locale που καθορίζει ποια γλώσσα θα παρέχεται σε κάθε αίτημα.
# babel.cfg — tells pybabel where to find translatable strings
[python: **.py]
[jinja2: **/templates/**.html]
extensions=jinja2.ext.autoescape,jinja2.ext.with_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)Επισήμανση συμβολοσειρών για μετάφραση
Περικλείστε κάθε συμβολοσειρά που προορίζεται για τον χρήστη με gettext() στον κώδικα Python και με _() στα πρότυπα Jinja2. Χρησιμοποιήστε τη lazy_gettext() για συμβολοσειρές που ορίζονται κατά τη φόρτωση της μονάδας, όπως ετικέτες φορμών και ρυθμίσεις, και πρέπει να μεταφραστούν αργότερα κατά την επεξεργασία ενός αιτήματος.
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')){# 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>Εξαγωγή μηνυμάτων
Εκτελέστε το pybabel extract για να σαρώσετε τον πηγαίο κώδικα και τα πρότυπά σας για μεταφράσιμες συμβολοσειρές. Έτσι δημιουργείται ένα αρχείο .pot (Portable Object Template). Στη συνέχεια, αρχικοποιήστε καταλόγους για κάθε γλώσσα-στόχο ή ενημερώστε τους υπάρχοντες όταν αλλάζουν οι συμβολοσειρές προέλευσης.
# 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
Ανοίξτε τα αρχεία .po που δημιουργήθηκαν και συμπληρώστε τις τιμές msgstr για κάθε msgid. Τα αρχεία PO είναι απλό κείμενο — μπορείτε να τα επεξεργαστείτε απευθείας, να χρησιμοποιήσετε ένα πρόγραμμα επεξεργασίας PO όπως το Poedit ή να αυτοματοποιήσετε τη μετάφραση με εργαλεία AI.
# 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 σε δυαδικά αρχεία .mo χρησιμοποιώντας το pybabel compile. Το Flask-Babel διαβάζει αρχεία .mo κατά την εκτέλεση — δεν μπορεί να διαβάσει απευθείας αρχεία .po. Πρέπει να επαναλαμβάνετε τη μεταγλώττιση μετά από κάθε ενημέρωση μετάφρασης.
# 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.Διαχείριση πληθυντικών και μεταβλητών
Χρησιμοποιήστε τη ngettext() για συμβολοσειρές που μεταβάλλονται ανάλογα με τον αριθμό. Δέχεται έναν ενικό τύπο, έναν πληθυντικό τύπο και το πλήθος. Το Babel χρησιμοποιεί αυτόματα τον σωστό κανόνα πληθυντικού για κάθε γλώσσα — τα Αγγλικά έχουν 2 τύπους, τα Ρωσικά 3, τα Αραβικά 6 και τα Ιαπωνικά 1.
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)# 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 товаров в вашей корзине"Προσθήκη επιλογής locale
Δημιουργήστε έναν επιλογέα γλώσσας που αποθηκεύει την επιλογή του χρήστη στη συνεδρία Flask. Ενημερώστε τη συνάρτηση locale_selector, ώστε να ελέγχει πρώτα τη συνεδρία και, στη συνέχεια, να χρησιμοποιεί εναλλακτικά την ανίχνευση του προγράμματος περιήγησης.
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']
){# 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>Αυτοματοποίηση μεταφράσεων
Αφού ολοκληρώσετε τη ρύθμιση του Flask-Babel, μεταφράστε τα αρχεία PO με AI. Αυτοματοποιήστε τον κύκλο εξαγωγής, μετάφρασης και μεταγλώττισης στο pipeline CI/CD σας, ώστε οι μεταφράσεις να παραμένουν συγχρονισμένες με τον πηγαίο κώδικα.
# 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Μπόνους: Έξυπνη εναλλακτική επιλογή γλώσσας με το flask-babel-locale-chain
Από προεπιλογή, το Flask-Babel χρησιμοποιεί απευθείας την προεπιλεγμένη γλώσσα όταν η προτιμώμενη γλώσσα του χρήστη δεν είναι διαθέσιμη. Ένας χρήστης με γλώσσα pt-BR που έχει διαθέσιμες μόνο μεταφράσεις pt-PT βλέπει Αγγλικά αντί για Πορτογαλικά. Το flask-babel-locale-chain προσθέτει προσαρμόσιμες αλυσίδες εναλλακτικής επιλογής, ώστε οι συγγενικές γλώσσες να διαδέχονται φυσικά η μία την άλλη.
# 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)Αυτοματοποιήστε τον έλεγχο ποιότητας των μεταφράσεων
Συνηθισμένες παγίδες
Παράλειψη μεταγλώττισης από .po σε .mo
Χρήση της gettext() σε επίπεδο μονάδας
Η εξαγωγή παραλείπει συμβολοσειρές
Σφάλματα κωδικοποίησης αρχείων PO
Προτεινόμενη δομή αρχείων
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/Δοκιμάστε τώρα το i18n Agent
Αφήστε εδώ το αρχείο μετάφρασής σας
JSON, YAML, PO, XML, CSV, Markdown, Properties
ή κάντε κλικ για να επιλέξετε αρχείο
Γλώσσες-στόχοι