
Flask i18n : สร้างแอปหลายภาษาด้วย Flask-Babel
ตั้งแต่พื้นฐาน gettext จนถึงการดีพลอยระบบจริง ทำให้แอป Flask รองรับหลายภาษาด้วย Flask-Babel ไฟล์ PO และการแปลอัตโนมัติด้วย AI
ติดตั้ง Flask-Babel
Flask-Babel เป็นส่วนขยายมาตรฐานสำหรับทำให้ Flask รองรับหลายภาษา เชื่อม GNU gettext กับเทมเพลต Flask และ Jinja2 พร้อมฟังก์ชันแปล การเลือกภาษา และการรองรับเขตเวลาให้ทันที
pip install Flask-Babelกำหนดค่า Babel
สร้างไฟล์ babel.cfg เพื่อบอก pybabel ว่าต้องสแกนข้อความที่แปลได้จากที่ใด แล้วเริ่มต้น Flask-Babel ด้วยฟังก์ชันเลือกภาษาที่กำหนดว่าจะให้บริการภาษาใดในแต่ละคำขอ
# 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 товаров в вашей корзине"เพิ่มการสลับภาษา
สร้างตัวเลือกภาษาที่เก็บตัวเลือกผู้ใช้ในเซสชัน 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 ทำให้วงจรแยก-แปล-คอมไพล์ในไปป์ไลน์ 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
หรือคลิกเพื่อเลือกไฟล์
ภาษาเป้าหมาย