mirror of
https://github.com/fastapi-practices/fastapi_best_architecture.git
synced 2026-03-13 09:31:31 +08:00
Update i18n language storage and loading (#1008)
This commit is contained in:
@@ -1,25 +1,15 @@
|
||||
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
|
||||
from backend.locale.loader import locale_loader
|
||||
|
||||
|
||||
class I18n:
|
||||
"""国际化管理器"""
|
||||
|
||||
def __init__(self) -> None:
|
||||
self.locales: dict[str, dict[str, Any]] = {}
|
||||
self.load_locales()
|
||||
|
||||
@property
|
||||
def current_language(self) -> str:
|
||||
"""获取当前请求的语言"""
|
||||
@@ -33,29 +23,6 @@ class I18n:
|
||||
"""设置当前请求的语言"""
|
||||
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:
|
||||
"""
|
||||
翻译函数
|
||||
@@ -68,10 +35,10 @@ class I18n:
|
||||
keys = key.split('.')
|
||||
|
||||
try:
|
||||
translation = self.locales[self.current_language]
|
||||
translation = locale_loader.locales[self.current_language]
|
||||
except KeyError:
|
||||
keys = 'error.language_not_found'
|
||||
translation = self.locales[settings.I18N_DEFAULT_LANGUAGE]
|
||||
keys = 'error.language_not_found'.split('.')
|
||||
translation = locale_loader.locales[settings.I18N_DEFAULT_LANGUAGE]
|
||||
|
||||
for k in keys:
|
||||
if isinstance(translation, dict) and k in list(translation.keys()):
|
||||
@@ -79,6 +46,7 @@ class I18n:
|
||||
else:
|
||||
# Pydantic 兼容
|
||||
translation = None if keys[0] == 'pydantic' else key
|
||||
break
|
||||
|
||||
if translation and kwargs:
|
||||
translation = translation.format(**kwargs)
|
||||
|
||||
@@ -25,7 +25,7 @@ UPLOAD_DIR = STATIC_DIR / 'upload'
|
||||
PLUGIN_DIR = BASE_PATH / 'plugin'
|
||||
|
||||
# 国际化文件目录
|
||||
LOCALE_DIR = BASE_PATH / 'locale'
|
||||
LOCALE_DIR = BASE_PATH / 'locale' / 'langs'
|
||||
|
||||
# MySQL 脚本目录
|
||||
MYSQL_SCRIPT_DIR = BASE_PATH / 'sql' / 'mysql'
|
||||
|
||||
0
backend/locale/__init__.py
Normal file
0
backend/locale/__init__.py
Normal file
44
backend/locale/loader.py
Normal file
44
backend/locale/loader.py
Normal file
@@ -0,0 +1,44 @@
|
||||
import glob
|
||||
import json
|
||||
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
import yaml
|
||||
|
||||
from backend.core.path_conf import LOCALE_DIR
|
||||
|
||||
|
||||
class LocaleLoader:
|
||||
"""语言文件加载器"""
|
||||
|
||||
def __init__(self) -> None:
|
||||
self.locales: dict[str, dict[str, Any]] = {}
|
||||
self.load_locales()
|
||||
|
||||
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())
|
||||
|
||||
|
||||
# 创建语言加载器单例
|
||||
locale_loader = LocaleLoader()
|
||||
@@ -4,6 +4,7 @@ from fastapi import Request, Response
|
||||
from starlette.middleware.base import BaseHTTPMiddleware
|
||||
|
||||
from backend.common.i18n import i18n
|
||||
from backend.core.conf import settings
|
||||
|
||||
|
||||
def get_current_language(request: Request) -> str | None:
|
||||
@@ -15,7 +16,7 @@ def get_current_language(request: Request) -> str | None:
|
||||
"""
|
||||
accept_language = request.headers.get('Accept-Language', '')
|
||||
if not accept_language:
|
||||
return None
|
||||
return settings.I18N_DEFAULT_LANGUAGE
|
||||
|
||||
languages = [lang.split(';')[0] for lang in accept_language.split(',')]
|
||||
lang = languages[0].lower().strip()
|
||||
|
||||
Reference in New Issue
Block a user