mirror of
https://github.com/fastapi-practices/fastapi_best_architecture.git
synced 2026-03-13 09:31:31 +08:00
95 lines
2.6 KiB
Python
95 lines
2.6 KiB
Python
import glob
|
|
import json
|
|
|
|
from pathlib import Path
|
|
from typing import Any
|
|
|
|
import yaml
|
|
|
|
from starlette_context.errors import ContextDoesNotExistError
|
|
|
|
from backend.common.context import ctx
|
|
from backend.core.conf import settings
|
|
from backend.core.path_conf import LOCALE_DIR
|
|
|
|
|
|
class I18n:
|
|
"""国际化管理器"""
|
|
|
|
def __init__(self) -> None:
|
|
self.locales: dict[str, dict[str, Any]] = {}
|
|
self.load_locales()
|
|
|
|
@property
|
|
def current_language(self) -> str:
|
|
"""获取当前请求的语言"""
|
|
try:
|
|
return ctx.language
|
|
except (AttributeError, LookupError, ContextDoesNotExistError):
|
|
return settings.I18N_DEFAULT_LANGUAGE
|
|
|
|
@current_language.setter
|
|
def current_language(self, language: str) -> None:
|
|
"""设置当前请求的语言"""
|
|
ctx.language = language
|
|
|
|
def load_locales(self) -> None:
|
|
"""加载语言文本"""
|
|
patterns = [
|
|
LOCALE_DIR / '*.json',
|
|
LOCALE_DIR / '*.yaml',
|
|
LOCALE_DIR / '*.yml',
|
|
]
|
|
|
|
lang_files = []
|
|
|
|
for pattern in patterns:
|
|
lang_files.extend(glob.glob(str(pattern)))
|
|
|
|
for lang_file in lang_files:
|
|
with open(lang_file, encoding='utf-8') as f:
|
|
lang = Path(lang_file).stem
|
|
file_type = Path(lang_file).suffix[1:]
|
|
match file_type:
|
|
case 'json':
|
|
self.locales[lang] = json.loads(f.read())
|
|
case 'yaml' | 'yml':
|
|
self.locales[lang] = yaml.full_load(f.read())
|
|
|
|
def t(self, key: str, default: Any | None = None, **kwargs) -> str:
|
|
"""
|
|
翻译函数
|
|
|
|
:param key: 目标文本键,支持点分隔,例如 'response.success'
|
|
:param default: 目标语言文本不存在时的默认文本
|
|
:param kwargs: 目标文本中的变量参数
|
|
:return:
|
|
"""
|
|
keys = key.split('.')
|
|
|
|
try:
|
|
translation = self.locales[self.current_language]
|
|
except KeyError:
|
|
keys = 'error.language_not_found'.split('.')
|
|
translation = self.locales[settings.I18N_DEFAULT_LANGUAGE]
|
|
|
|
for k in keys:
|
|
if isinstance(translation, dict) and k in list(translation.keys()):
|
|
translation = translation[k]
|
|
else:
|
|
# Pydantic 兼容
|
|
translation = None if keys[0] == 'pydantic' else key
|
|
break
|
|
|
|
if translation and kwargs:
|
|
translation = translation.format(**kwargs)
|
|
|
|
return translation or default
|
|
|
|
|
|
# 创建 i18n 单例
|
|
i18n = I18n()
|
|
|
|
# 创建翻译函数实例
|
|
t = i18n.t
|