Flask API 如何接入 i18n 实现国际化多语言

techhub 2024-07-09 16:39:00 阅读 60

Flask API 如何接入 i18n 实现国际化多语言

如何在现有的 Flask API 项目中,引入 i18n 实现国际化多语言,同时与前端 Vue3 页面联动。

1. 介绍

上一篇文章分享了 Vue3 如何如何接入 i18n实现国际化多语言,这里继续和大家分享 Flask 后端如何接入 i18n 实现国际化多语言。

用户请求 API 的多语言化其实有两种解决方案:

  1. 后端返回:"USER_ERROR" => 前端渲染:"用户错误"
  1. 后端接收请求中 "Accept-Language" 信息为 "zh-CN" => 后端返回:"用户错误" =>前端渲染:"用户错误"

这里我们采用的是第二种方案,也就是后端直接处理 i18n 逻辑。

对于 Flask 我们常用 flask-babel,这个包对于将原本单语言的程序转为国际化多语言非常友好,我们只要用 gettext() 包裹我们原来的文本:

<code>@api.route("/", methods=["GET"])

def info():

return jsonify({"msg": gettext("欢迎访问 Githubstar API 服务器.")}), 200

然后工具就可以自动生成翻译文件,我们只要编辑不同语言的翻译文件就可以了:

#: githubstar_api/api.py:39

msgid "欢迎访问 Githubstar API 服务器."

msgstr "Welcome to the Githubstar API server."

2. 基本实现

本文以 GithubStar.Pro后端的实现为例进行介绍。

要将 flask-babel 引入项目,这里首先安装flask-babel:

pip install flask-babel

如果你开发包的话,这个依赖也要加入到项目依赖中。

然后,在 Flask 初始化时安装 Babel 插件:

from flask import Flask

from flask_babel import Babel

app = Flask('githubstar_api')

babel = Babel(app)

如果你需要使用工厂模式初始化你的 Flask 实例,可以用:

from flask import Flask

from flask_babel import Babel

app = Flask('githubstar_api')

babel = Babel()

def init_app():

babel.init_app(app)

然后,将你的所有业务相关的文字都包裹上 gettext():

return (

jsonify(

{"errors": [gettext('用户 "%(username)s" 已被封禁.', username=user.username)]}

),

400,

)

句子中的变量,可以用 %()s 包裹,其中 s 代表字符串。

更多的使用方法详见:文档

然后,在项目根目录新建一个 babel.cfg:

[python: githubstar_api/**.py]

​这里的路径应该指向你的所有需要国际化的代码文件。

然后,运行命令,将这些文件中被 gettext() 包裹的文字都提取到模板文件中:

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

这会在项目根目录生成 messages.pot 文件,可以看到包含了所有需要翻译的文本:

#: githubstar_api/api.py:39

msgid "欢迎访问 Githubstar API 服务器."

msgstr ""

随后,我们需要开始进行一个新语言的翻译,例如英文,运行命令:

pybabel init -i messages.pot -d ./githubstar_api/res/locales -l en

我们就可以在 ./githubstar_api/res/locales 中看到生成了一个 en 文件夹, 里面有 messages.po 文件,这就是一个空的全新的翻译文件了。

这里我们可以将文本内容全部发送给 OpenAI GPT4 或者是 Github Copilot,告诉他:

这是一个 babel 翻译文件,请根据中文翻译为英文并填入msgstr中,以下是文件内容:

...

AI 可以很好地完成翻译任务,只需要检查并稍微调整即可。

完成翻译后,需要将翻译文件编译为二进制文件:

pybabel compile -d ./githubstar_api/res/locales

这样,locale 文件夹中的所有语言都被翻译,生产了 messages.po 文件。

现在,文件目录应该是这样的:

./githubstar

├── githubstar_api

│ ├── __init__.py

│ ├── res

│ │ ├── __init__.py

│ │ └── locales

│ │ └── en

│ │ └── LC_MESSAGES

│ │ ├── messages.mo

│ │ └── messages.po

│ ├── api.py

│ ├── app.py

│ └── cli.py

├── messages.pot

└── pyproject.toml

所以,用加载包数据的方式导入:

import importlib.resources as pkg_resources

from . import res

traversable = pkg_resources.files(res)

with pkg_resources.as_file(traversable) as path:

babel.init_app(

app,

default_translation_directories=str(path / "locales"),

)

接下来,我们需要设定,需要检测请求的 Accept-Language,以下就是完整的 app.py 文件:

from flask import Flask, request

from flask_babel import Babel

app = Flask("githubstar_api")

babel = Babel()

def get_locale():

return request.accept_languages.best_match(["zh_CN", "en"])

def init_app():

traversable = pkg_resources.files(res)

with pkg_resources.as_file(traversable) as path:

babel.init_app(

app,

default_translation_directories=str(path / "locales"),

locale_selector=get_locale,

default_locale="zh_CN",code>

)

这样,就实现了 Flask API 后端根据请求的Accept-Language 自动调整返回值的语言了。

注意:如果你要将翻译文件包含在输出的 Python 包中,你需要调整你的 pyproject.toml:

[tool.setuptools]

zip-safe = false

include-package-data = true

[tool.setuptools.packages]

find = {namespaces = false}

[tool.setuptools.package-data]

"githubstar_api.res" = ["**/*.mo"]

3. 与 Vue3 前端联动

接下来,需要让前端发送的请求以当前语言作为Accept-Language。

这里,我们以用户操作相关 API 为例,这里我们使用一个 Pinia Store来管理所有的用户状态和相关请求。API 请求用 axios发送,详见开源仓库:Github: GithubStarPro。

export const useUserStore = defineStore('user', {

state: () => {

const { locale } = useI18n({ inheritLocale: true, useScope: 'local' });

const user = useStorage<User | null>('user', null, undefined, { serializer: StorageSerializers.object });

const api = axios.create({ baseURL: import.meta.env.VITE_API_URL });

api.interceptors.request.use((config) => {

config.headers['Accept-Language'] = locale.value;

if (user.value && user.value.token) {

config.headers.Authorization = `Bearer ${user.value.token.token}`;

}

return config;

});

},

actions: {

login(username: string, password: string) {

const payload = {

username: username,

password: password,

};

this.api.post('/user/login', payload)

.then((response) => {

this.user = response.data;

});

}

},

});

​我们重点关注的是:

api.interceptors.request.use((config) => {

config.headers['Accept-Language'] = locale.value;

if (user.value && user.value.token) {

config.headers.Authorization = `Bearer ${user.value.token.token}`;

}

return config;

});

这一块是在 axios 对象上定义了一个预处理器,也就是在每个发送的请求上加入当前的 locale,如果用户已登录,还需要加入用户的 Token,这里的 locale 参见我的上一篇文章:Vue3 如何如何接入 i18n实现国际化多语言。

这样,就实现了在每次发送请求时候自动发送当前的 locale。

这样我们就实现了前后端的国际化,如果这篇文章对您有帮助的话,欢迎关注我,我会分享更多全栈网页开发的实用经验。

您也可以关注 Github 互赞平台GithubStar.Pro,快速提升您的项目关注度。

感谢阅读!



声明

本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。