在 FastAPI 中配置多语言支持并使用 fastapi-babel
库,以下步骤为操作示例:
1. 安装依赖
首先,需要安装 fastapi-babel
和 Babel
库:
pip install fastapi-babel Babel
2. 创建配置文件
在项目中创建一个 babel.py
文件,用于配置 Babel。配置示例:
from fastapi_babel import Babel, BabelConfigs
configs = BabelConfigs(
ROOT_DIR=__file__,
BABEL_DEFAULT_LOCALE="en", # 默认语言
BABEL_TRANSLATION_DIRECTORY="lang", # 翻译文件存放的目录
)
babel = Babel(configs=configs)
if __name__ == "__main__":
babel.run_cli()
3. 提取可翻译的消息
创建 babel.cfg
文件,指定要提取的 Python 文件类型:
[python: **.py]
然后使用以下命令提取可翻译的字符串并生成 messages.pot
文件:
pybabel extract -F babel.cfg -o messages.pot .
4. 初始化翻译文件
使用以下命令初始化特定语言的翻译文件(例如,法语 fa
):
pybabel init -i messages.pot -d lang -l fa
执行后会在 lang/fa/LC_MESSAGES/
目录下生成一个 messages.po
文件。
如果已经存在翻译好的文件,根目录下的messages.pot文件有产生新的数据执行下面的命令进行更新
pybabel update -i messages.pot -d lang
-i messages.pot:指定输入文件为已经生成的 .pot 文件。
-d translations:指定翻译目录,通常这个目录下包含各个语言的 .po 文件
-l zh:指定语言代码
5. 添加翻译内容
打开生成的 messages.po
文件,添加对应的翻译内容。每一条可翻译的消息都会有一个 msgid
和一个 msgstr
,需要在 msgstr
中填写对应的翻译。
6. 编译翻译文件
在添加完翻译内容后,使用以下命令编译这些翻译文件:
pybabel compile -d lang -l fa
这会生成二进制的 messages.mo
文件,供应用程序在运行时使用。
7. 在 FastAPI 中使用 Babel
在 FastAPI 应用中,引入 Babel 中间件,并配置应用使用翻译:
from fastapi import FastAPI, Request
from fastapi_babel import BabelMiddleware, _
app = FastAPI()
# 加载配置
configs = BabelConfigs(
ROOT_DIR=__file__,
BABEL_DEFAULT_LOCALE="en",
BABEL_TRANSLATION_DIRECTORY="lang",
)
app.add_middleware(BabelMiddleware, babel_configs=configs)
def get_locale(request: Request) -> str:
return request.headers.get("accept-language", "en")
def get_translator(request: Request):
locale = get_locale(request)
log.info(f'当前语言环境为:{locale}')
babel.locale = locale # 临时设置当前请求的语言环境
return babel.gettext
@app.get("/")
async def index(request: Request):
return {"message": _("Hello, World!")}
if __name__ == "__main__":
babel.run_cli()
8. 通过请求头控制语言
在运行时,可以通过设置 HTTP 请求的 Accept-Language
头来控制返回的语言。例如,设置 Accept-Language: fa
会返回法语的翻译内容。
注意事项
- 不要将
fastapi-babel
与main.py
或run.py
直接一起使用,因为这可能会导致uvicorn
的运行问题。 - 如果
BABEL_DEFAULT_LOCALE
设置为zh
,而代码中的字符串(如"hello"
)也是用中文环境下的内容,FastAPI Babel 会认为这已经是翻译后的文本,因此不会再从本地的翻译文件中获取对应的翻译内容。这是因为默认语言和请求语言相同时,Babel 会直接返回代码中的原始字符串,而不再进行翻译查找。 - 目前上下文传递有问题github有issue暂未解决!!!
将语言环境处理逻辑从中间件中分离出来,单独处理的方法是一个更优雅且避免并发问题的解决方案。通过将语言环境的处理集中在一个独立的方法中,可以确保每个请求都能正确解析和应用语言环境,而不会受到其他请求的干扰。
具体实现方法:
-
创建独立的语言环境解析方法:
可以创建一个独立的函数,用于解析并返回当前请求的语言环境。这样可以避免使用全局变量,并确保每次请求处理时都能正确获取语言环境。
from fastapi import FastAPI, Request
from fastapi_babel import Babel, BabelConfigs
app = FastAPI()
configs = BabelConfigs(
ROOT_DIR=__file__,
BABEL_DEFAULT_LOCALE="en",
BABEL_TRANSLATION_DIRECTORY="lang"
)
babel = Babel(configs=configs)
def get_locale(request: Request) -> str:
return request.headers.get("accept-language", "en")
def get_translator(request: Request):
locale = get_locale(request)
babel.locale = locale # 临时设置当前请求的语言环境
return babel.gettext
@app.get("/")
async def index(request: Request):
_ = get_translator(request)
return {"message": _("Hello, World!")}
-
函数的职责分离:
在这个实现中,
get_locale
函数负责解析请求中的语言环境,get_translator
函数则负责根据当前请求的语言环境获取对应的gettext
翻译函数。每个请求都会调用这些函数,因此语言环境的处理是完全独立和请求特定的,不会与其他请求产生冲突。 -
优势:
- 避免共享状态:这种方法避免了使用全局状态或变量,因此在高并发环境中不会出现竞争条件或数据污染。
- 更清晰的结构:将语言处理逻辑从中间件中分离出来,使得代码结构更加清晰易懂,职责分离明确。
- 可测试性:独立的方法更易于测试和维护,可以单独测试语言环境的解析和翻译逻辑,而不依赖于整个请求处理流程。
通过这种方法,可以在保持应用灵活性的同时,确保在任何并发条件下语言环境都能正确处理,从而避免潜在的问题。
服务器常用状态码和英文描述以及中文翻译如下:
状态码 | 英文描述 | 中文翻译 |
---|---|---|
200 | OK | 请求成功 |
201 | Created | 已创建 |
202 | Accepted | 已接受 |
204 | No Content | 无内容 |
301 | Moved Permanently | 永久移动 |
302 | Found | 临时移动 |
304 | Not Modified | 未修改 |
400 | Bad Request | 错误请求 |
401 | Unauthorized | 未授权 |
403 | Forbidden | 禁止访问 |
404 | Not Found | 未找到 |
405 | Method Not Allowed | 方法不被允许 |
500 | Internal Server Error | 服务器内部错误 |
502 | Bad Gateway | 错误网关 |
503 | Service Unavailable | 服务不可用 |
504 | Gateway Timeout | 网关超时 |