翼度科技»论坛 编程开发 python 查看内容

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

8

主题

8

帖子

24

积分

新手上路

Rank: 1

积分
24

1. 介绍

上一篇文章分享了 Vue3 如何如何接入 i18n 实现国际化多语言,这里继续和大家分享 Flask 后端如何接入 i18n 实现国际化多语言。
用户请求 API 的多语言化其实有两种解决方案:

  • 后端返回:"USER_ERROR"  => 前端渲染:"用户错误"

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

这里我们采用的是第二种方案,也就是后端直接处理 i18n 逻辑。
对于 Flask 我们常用 flask-babel,这个包对于将原本单语言的程序转为国际化多语言非常友好,我们只要用 gettext() 包裹我们原来的文本:
  1. @api.route("/", methods=["GET"])
  2. def info():
  3.     return jsonify({"msg": gettext("欢迎访问 Githubstar API 服务器.")}), 200
复制代码
然后工具就可以自动生成翻译文件,我们只要编辑不同语言的翻译文件就可以了:
  1. #: githubstar_api/api.py:39
  2. msgid "欢迎访问 Githubstar API 服务器."
  3. msgstr "Welcome to the Githubstar API server."
复制代码
2. 基本实现


本文以 GithubStar.Pro 后端的实现为例进行介绍。
要将 flask-babel 引入项目,这里首先安装 flask-babel:
  1. pip install flask-babel
复制代码
如果你开发包的话,这个依赖也要加入到项目依赖中。
然后,在 Flask 初始化时安装 Babel 插件:
  1. from flask import Flask
  2. from flask_babel import Babel
  3. app = Flask('githubstar_api')
  4. babel = Babel(app)
复制代码
如果你需要使用工厂模式初始化你的 Flask 实例,可以用:
  1. from flask import Flask
  2. from flask_babel import Babel
  3. app = Flask('githubstar_api')
  4. babel = Babel()
  5. def init_app():
  6.     babel.init_app(app)
复制代码
然后,将你的所有业务相关的文字都包裹上 gettext():
  1. return (
  2.     jsonify(
  3.         {"errors": [gettext('用户 "%(username)s" 已被封禁.', username=user.username)]}
  4.     ),
  5.     400,
  6. )
复制代码
句子中的变量,可以用 %()s 包裹,其中 s 代表字符串。
更多的使用方法详见:文档
然后,在项目根目录新建一个 babel.cfg:
  1. [python: githubstar_api/**.py]
复制代码
​这里的路径应该指向你的所有需要国际化的代码文件。
然后,运行命令,将这些文件中被 gettext() 包裹的文字都提取到模板文件中:
  1. pybabel extract -F babel.cfg -o messages.pot .
复制代码
这会在项目根目录生成 messages.pot 文件,可以看到包含了所有需要翻译的文本:
  1. #: githubstar_api/api.py:39
  2. msgid "欢迎访问 Githubstar API 服务器."
  3. msgstr ""
复制代码
随后,我们需要开始进行一个新语言的翻译,例如英文,运行命令:
  1. 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 可以很好地完成翻译任务,只需要检查并稍微调整即可。
完成翻译后,需要将翻译文件编译为二进制文件:
  1. pybabel compile -d ./githubstar_api/res/locales
复制代码
这样,locale 文件夹中的所有语言都被翻译,生产了 messages.po 文件。
现在,文件目录应该是这样的:
  1. ./githubstar
  2. ├── githubstar_api
  3. │   ├── __init__.py
  4. │   ├── res
  5. │   │   ├── __init__.py
  6. │   │   └── locales
  7. │   │       └── en
  8. │   │           └── LC_MESSAGES
  9. │   │               ├── messages.mo
  10. │   │               └── messages.po
  11. │   ├── api.py
  12. │   ├── app.py
  13. │   └── cli.py
  14. ├── messages.pot
  15. └── pyproject.toml
复制代码
所以,用加载包数据的方式导入:
  1. import importlib.resources as pkg_resources
  2. from . import res
  3. traversable = pkg_resources.files(res)
  4. with pkg_resources.as_file(traversable) as path:
  5.     babel.init_app(
  6.         app,
  7.         default_translation_directories=str(path / "locales"),
  8.     )
复制代码
接下来,我们需要设定,需要检测请求的 Accept-Language,以下就是完整的 app.py 文件:
  1. from flask import Flask, request
  2. from flask_babel import Babel
  3. app = Flask("githubstar_api")
  4. babel = Babel()
  5. def get_locale():
  6.     return request.accept_languages.best_match(["zh_CN", "en"])
  7. def init_app():
  8.     traversable = pkg_resources.files(res)
  9.     with pkg_resources.as_file(traversable) as path:
  10.         babel.init_app(
  11.             app,
  12.             default_translation_directories=str(path / "locales"),
  13.             locale_selector=get_locale,
  14.             default_locale="zh_CN",
  15.         )
复制代码
这样,就实现了 Flask API 后端根据请求的 Accept-Language 自动调整返回值的语言了。
注意:如果你要将翻译文件包含在输出的 Python 包中,你需要调整你的 pyproject.toml:
  1. [tool.setuptools]
  2. zip-safe = false
  3. include-package-data = true
  4. [tool.setuptools.packages]
  5. find = {namespaces = false}
  6. [tool.setuptools.package-data]
  7. "githubstar_api.res" = ["**/*.mo"]
复制代码
3. 与 Vue3 前端联动

接下来,需要让前端发送的请求以当前语言作为 Accept-Language。
这里,我们以用户操作相关 API 为例,这里我们使用一个 Pinia Store 来管理所有的用户状态和相关请求。API 请求用 axios 发送,详见开源仓库:Github: GithubStarPro
  1. export const useUserStore = defineStore('user', {
  2.   state: () => {
  3.     const { locale } = useI18n({ inheritLocale: true, useScope: 'local' });
  4.     const user = useStorage<User | null>('user', null, undefined, { serializer: StorageSerializers.object });
  5.     const api = axios.create({ baseURL: import.meta.env.VITE_API_URL });
  6.     api.interceptors.request.use((config) => {
  7.       config.headers['Accept-Language'] = locale.value;
  8.       if (user.value && user.value.token) {
  9.         config.headers.Authorization = `Bearer ${user.value.token.token}`;
  10.       }
  11.       return config;
  12.     });
  13.   },
  14.   actions: {
  15.     login(username: string, password: string) {
  16.       const payload = {
  17.         username: username,
  18.         password: password,
  19.       };
  20.       this.api.post('/user/login', payload)
  21.         .then((response) => {
  22.           this.user = response.data;
  23.         });
  24.     }
  25.   },
  26. });
复制代码
​我们重点关注的是:
  1. api.interceptors.request.use((config) => {
  2.   config.headers['Accept-Language'] = locale.value;
  3.   if (user.value && user.value.token) {
  4.     config.headers.Authorization = `Bearer ${user.value.token.token}`;
  5.   }
  6.   return config;
  7. });
复制代码

这一块是在 axios 对象上定义了一个预处理器,也就是在每个发送的请求上加入当前的 locale,如果用户已登录,还需要加入用户的 Token,这里的 locale 参见我的上一篇文章:Vue3 如何如何接入 i18n 实现国际化多语言
这样,就实现了在每次发送请求时候自动发送当前的 locale。
这样我们就实现了前后端的国际化,如果这篇文章对您有帮助的话,欢迎关注我,我会分享更多全栈网页开发的实用经验。
您也可以关注 Github 互赞平台 GithubStar.Pro,快速提升您的项目关注度。
感谢阅读!

来源:https://www.cnblogs.com/techhub/p/18292178/python-flask-i18n
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作!
来自手机

举报 回复 使用道具