在 Flask 中实现多语言,最成熟、最主流的方式是使用 Flask-Babel 扩展。它基于 GNU gettext,功能强大,能很好地处理文本翻译、日期和数字格式化等。
下面是使用 Flask-Babel 进行多语言配置的完整步骤和示例。
第一步:安装与初始化
首先,安装 Flask-Babel:
pip install flask-babel
第二步:配置应用
在 Flask 应用代码中(如 app.py 或 __init__.py),进行如下配置:
from flask import Flask, request, session
from flask_babel import Babel, gettext as _
app = Flask(__name__)
# 1. 配置默认语言和支持的语言列表
app.config['BABEL_DEFAULT_LOCALE'] = 'en' # 默认语言为英语
app.config['BABEL_SUPPORTED_LOCALES'] = ['en', 'zh', 'es'] # 支持英语、中文、西班牙语
# 2. 初始化 Babel 实例
babel = Babel(app)
第三步:定义语言选择器
你需要告诉应用如何为每个用户决定使用哪种语言。最常用的是根据用户的浏览器语言设置,或让用户自己选择并存储在 Session 中。
@babel.localeselector
def get_locale():
# 优先使用 Session 中存储的语言
if 'language' in session:
return session['language']
# 其次,从请求头的 Accept-Language 中自动匹配最佳语言
return request.accept_languages.best_match(app.config['BABEL_SUPPORTED_LOCALES'])
你也可以让用户主动切换语言,通过一个视图函数来实现:
@app.route('/language/<lang_code>')
def set_language(lang_code):
if lang_code in app.config['BABEL_SUPPORTED_LOCALES']:
session['language'] = lang_code
return redirect(request.referrer or url_for('index'))
第四步:标记需要翻译的文本
在 Python 代码和 Jinja2 模板中,使用 gettext (通常别名为 _) 和 ngettext 函数来标记所有需要翻译的字符串。
在 Python 视图函数中:
from flask_babel import gettext as _
@app.route('/')
def index():
welcome_msg = _('Hello, World!') # 标记待翻译字符串
return render_template('index.html', message=welcome_msg)
在 Jinja2 模板中 (index.html):
<!DOCTYPE html>
<html>
<head>
<title>{{ _('Home Page') }}</title> <!-- 标记待翻译标题 -->
</head>
<body>
<h1>{{ message }}</h1>
<p>{{ _('Welcome to our multi-language site.') }}</p> <!-- 标记待翻译段落 -->
<a href="{{ url_for('set_language', lang_code='zh') }}">{{ _('中文') }}</a> |
<a href="{{ url_for('set_language', lang_code='en') }}">{{ _('English') }}</a>
</body>
</html>
第五步:生成和管理翻译文件
这是最关键的一步,需要使用 pybabel 命令行工具。
创建
babel.cfg配置文件:告诉pybabel哪些文件需要扫描。# babel.cfg [python: **.py] [jinja2: **/templates/**.html] extensions=jinja2.ext.autoescape,jinja2.ext.with_提取所有待翻译字符串,生成
.pot模板文件:pybabel extract -F babel.cfg -o messages.pot .为每种语言创建翻译目录和
.po文件:# 为中文 (zh) 创建翻译文件 pybabel init -i messages.pot -d translations -l zh # 为西班牙语 (es) 创建翻译文件 pybabel init -i messages.pot -d translations -l es执行后,会在
translations/目录下生成zh/LC_MESSAGES/messages.po和es/LC_MESSAGES/messages.po文件。编辑
.po文件进行翻译:打开messages.po文件,你会看到类似下面的内容:#: app.py:15 msgid "Hello, World!" msgstr "你好,世界!"你需要将
msgstr后面的内容翻译成对应的语言。编译
.po文件为.mo二进制文件:pybabel compile -d translations应用会读取编译后的
.mo文件来提供翻译。
第六步:更新翻译
当你的代码中新增或修改了待翻译文本后,需要更新翻译文件:
# 1. 重新提取所有字符串,更新 messages.pot
pybabel extract -F babel.cfg -o messages.pot .
# 2. 更新所有语言的 .po 文件,合并新的更改
pybabel update -i messages.pot -d translations
# 3. 再次编辑 .po 文件完成新文本的翻译
# 4. 重新编译
pybabel compile -d translations
其他方式:基于 URL 路径的多语言
除了 Flask-Babel,另一种常见的方式是将语言代码直接放在 URL 中,例如 /en/about 和 /zh/about。
这可以通过 Flask 的 url_value_preprocessor 和 url_defaults 来实现。这种方式的好处是 URL 本身包含了语言信息,更利于 SEO,但通常也需要和 Flask-Babel 结合使用来管理翻译文本。
@app.url_value_preprocessor
def pull_lang_code(endpoint, values):
# 从URL中提取语言代码并存储
g.lang_code = values.pop('lang_code', None) # type: ignore
@app.url_defaults
def add_language_code(endpoint, values):
# 生成URL时自动添加语言代码
if 'lang_code' in values or not g.get('lang_code'): # type: ignore
return
if app.url_map.is_endpoint_expecting(endpoint, 'lang_code'): # type: ignore
values['lang_code'] = g.lang_code # type: ignore
总结
总的来说,Flask-Babel 是处理多语言的标准方案,通过标记文本、生成和管理翻译文件,可以系统性地实现应用的国际化。而 URL 路径方式 则是一种补充,用于在 URL 层面体现语言选择。在实际项目中,这两种方法常常结合使用,以获得最佳的用户体验和可维护性。