处理I18N时,最常见的方法是添加中间件以检测输入请求中的特定语言环境。幸运的是,Fastapi支持中间件,使其非常简单。
- i18n_middleware.py
from starlette.middleware.base import BaseHTTPMiddleware, RequestResponseEndpoint
from starlette.requests import Request
class I18nMiddleware(BaseHTTPMiddleware):
WHITE_LIST = ['en', 'ja', 'zh-TW']
async def dispatch( # type: ignore
self, request: Request, call_next: RequestResponseEndpoint):
# 1. headers 2. path 3. query string
locale = request.headers.get('locale', None) or \
request.path_params.get('locale', None) or \
request.query_params.get('locale', None) or \
'zh-TW'
if locale not in self.WHITE_LIST:
locale = 'zh-TW'
request.state.locale = locale
return await call_next(request)
您可以在main.py中添加中间件:
- main.py
app = FastAPI()
app.add_middleware(I18nMiddleware)
然后您可以在路由器中使用它:
@router.get('/my-resource')
def get_my_resource(request: Request):
print(request.state.locale)
但是,没有像 laravel 的__
或 ror 的I18n.t
这样的全球助手,因此我们需要创建自己的。
这个想法非常简单:将翻译脚本放在Python中,然后使用importlib
编写自己的进口商。您可以做到这一点:
- 写您的翻译脚本
locale = {
'greeting': 'Hi, {user_name}',
'title': 'hello world',
}
- 将您的翻译脚本放在以下结构中
app/lang
├── en
│ └── messages.py
├── ja
│ └── messages.py
└── zh-TW
└── messages.py
- 写一个班级来处理翻译
import importlib
from typing import Any, Dict
class Translator:
_instances: Dict[str, 'Translator'] = {}
def __new__(cls, lang: str) -> 'Translator':
if lang not in cls._instances:
cls._instances[lang] = super(Translator, cls).__new__(cls)
return cls._instances[lang]
def __init__(self, lang: str):
self.lang = lang
def t(self, key: str, **kwargs: Dict[str, Any]) -> str:
file_key, *translation_keys = key.split('.')
locale_module = importlib.import_module(f'app.lang.{self.lang}.{file_key}')
translation = locale_module.locale
for translation_key in translation_keys:
translation = translation.get(translation_key, None)
if translation is None:
return f'Key {key} not found in {self.lang} locale'
if kwargs.keys():
translation = translation.format(**kwargs)
return translation
然后您可以在路由器中使用它
@router.get('/my-resource')
def get_my_resource(request: Request):
translator = Translator(request.state.locale)
# 'hello world'
print(translator.t('messages.title'))
# 'Hi, Jon Doe'
print(translator.t('messages.greeting'), user_name='Jon Doe')
也很容易。