一、整体思路
实现多语言支持的核心流程其实很简单:
- 识别用户语言 ------ 从
Accept-Languageheader 或 URL 参数中获取; - 加载对应语言的翻译文件 (
.po/.mo); - 在代码中动态翻译文本。
简单来说,就是让接口返回不同语言的内容。
二、安装依赖
我们主要用到 Babel 来提取和编译翻译文件:
pip install Babel
三、项目结构
建议的目录结构如下:
bash
app/
├─ main.py
├─ i18n/
│ ├─ locales/
│ │ ├─ en/LC_MESSAGES/messages.po
│ │ └─ zh_CN/LC_MESSAGES/messages.po
│ └─ babel.cfg
babel.cfg 文件内容如下:
ini
[python: **.py]
encoding = utf-8
四、编写中间件自动切换语言
我们可以编写一个中间件,在请求到来时自动根据 Accept-Language 选择语言环境:
python
from fastapi import FastAPI, Request
from starlette.middleware.base import BaseHTTPMiddleware
import gettext
class I18nMiddleware(BaseHTTPMiddleware):
async def dispatch(self, request: Request, call_next):
lang = request.headers.get("Accept-Language", "en").split(",")[0]
try:
translation = gettext.translation(
domain="messages",
localedir="app/i18n/locales",
languages=[lang],
)
translation.install()
request.state._ = translation.gettext
except FileNotFoundError:
gettext.install("messages", localedir="app/i18n/locales")
request.state._ = gettext.gettext
return await call_next(request)
app = FastAPI()
app.add_middleware(I18nMiddleware)
@app.get("/")
async def read_root(request: Request):
_ = request.state._
return {"message": _("Hello, world!")}
上面的中间件会自动根据请求头里的语言加载对应翻译文件,比如:
arduino
curl -H "Accept-Language: zh_CN" http://127.0.0.1:8000/
就会返回中文翻译。
五、提取和编译翻译文件
接下来生成翻译模板并创建不同语言的 .po 文件。
bash
# 提取字符串
pybabel extract -F app/i18n/babel.cfg -o app/i18n/messages.pot app
# 初始化中文翻译
pybabel init -i app/i18n/messages.pot -d app/i18n/locales -l zh_CN
# 编辑 po 文件后编译
pybabel compile -d app/i18n/locales
编辑
messages.po时,只需要翻译字符串,例如:
arduinomsgid "Hello, world!" msgstr "你好,世界!"