Flask实现国际化(填坑)

420 阅读3分钟

项目背景:

web项目中,无论是给端上API还是服务API,往往都会设置统一格式返回,全局异常拦截等等功能。 统一格式例如

{  
    "code": 100010,  
    "message": "tenant is not exist",  
    "data": ""  
}

国际化主要针对的是messages参数实现多语言化,下面我们将手把手的实现这个功能。

网上的坑

主要是随着包的升级出现的不兼容问题。

填坑一:

flask国际化实现是通过插件flask-babel包,flask-babel包从2.0.0 到3.0.0大版本升级

去掉了localeselector方法

优化成了在初始化Babel的时候传入select_locale参数

如果你使用的最新的flask-babel,

# 设置语言选择逻辑
@babel.localeselector
def get_locale():
    # 从 URL 参数获取语言选择,如果没有提供则使用浏览器默认语言
    return request.args.get('lang', request.accept_languages.best_match(app.config['LANGUAGES']))

上面方法localeselector方法提示不存在。

实现国际化完整流程

1、创建Flask项目

项目结构

babel-demo/
│
├── app.py          # Flask 应用主文件
├── config.py       # 配置文件
└── templates/
    └── index.html  # 模板文件

2. 安装依赖

首先,确保你安装了 Flask 和最新版的 Flask-Babel:

pip install Flask Flask-Babel

3. 配置 Flask 和 Flask-Babel

在 config.py 中设置配置参数:

# config.py

class Config:
    LANGUAGES = ['en', 'zh']  # 支持的语言列表
    BABEL_DEFAULT_LOCALE = 'en'  # 默认语言
    BABEL_TRANSLATION_DIRECTORIES = 'translations'  # 翻译文件目录

app.py启动文件

import json
 
from flask import Flask, render_template, request, jsonify
from flask_babel import Babel, _
 
app = Flask(__name__)
app.config.from_object('config.Config')
 
babel = Babel(app)
 
 
# 选择语言的函数
def select_locale():
    lang = request.args.get('lang', request.accept_languages.best_match(app.config['LANGUAGES']))
    print(f"Selected language: {lang}") 
    return lang
 
 
babel.init_app(app, locale_selector=select_locale)
 
 
# 上下文处理器,用于在模板中获取当前语言
@app.context_processor
def inject_locale():
    return {'get_locale': select_locale}
 
 
@app.route('/')
def index():
    return render_template('index.html')
 
 
if __name__ == "__main__":
    app.run()

创建页面模板templates下面index.html

<!DOCTYPE html>
<html lang="{{ get_locale() }}">
<head>
    <meta charset="UTF-8">
    <title>{{ _("Hello World") }}</title>
</head>
<body>
    <h1>{{ _("Hello World") }}</h1>
    <p>{{ _("Welcome to our website.") }}</p>
</body>
</html>

4、创建翻译文件

为了支持多语言,你需要生成翻译文件。首先,创建 babel.cfg 文件,指定要提取翻译的文件类型:

# babel.cfg

[python: babel-demo/**.py]   # 扫描的文件
[jinja2: **/templates/**.html]

然后,使用以下命令提取项目中的可翻译字符串:

pybabel extract -F babel.cfg -o messages.pot .

接下来,为每种语言初始化翻译文件(例如英语和中文):

pybabel init -i messages.pot -d translations -l en
pybabel init -i messages.pot -d translations -l zh

然后,编辑生成的 .po 文件,添加翻译文本。例如,translations/zh/LC_MESSAGES/messages.po 文件:

msgid "Hello World"
msgstr "你好,世界"

msgid "Welcome to our website."
msgstr "欢迎来到我们的网站。"

最后,编译翻译文件:

pybabel compile -d translations

测试效果

现在,你可以运行 Flask 应用程序,并通过 URL 参数来切换语言。例如:

默认语言(英语):http://localhost:5000/ 中文:http://localhost:5000/?lang=zh

项目中实践

项目全局统一格式

web项目中我们对所有的api接口都统一格式返回。通过flask注解@app.after_request装饰器,用于注册一个函数,该函数将在每次请求后被调用。

@app.after_request
def after_request(response):
    print(f"Response status code: {response.status_code}")
    if response.is_json:
        data = response.get_json()
        if 'message' in data and isinstance(data['message'], str):
            data['message'] = _(data['message'])
        response.set_data(json.dumps(data))
    return response

获取全局返回结果,并查看是否包含message参数,如果包含,通过_()方式实现多语言。

全局捕捉异常

@app.errorhandler(Exception)
def handle_error(e):
    print(f"Handling error: {e}")
    error_message = str(e)
    response = {
        "status": "error",
        "message": error_message,
    }
    return jsonify(response), 400

这样就可以实现flask项目实现国际化。