Update i18n language storage and loading (#1008)

This commit is contained in:
Wu Clan
2026-01-13 19:10:41 +08:00
committed by GitHub
parent ee849f0854
commit 8ae1a43581
7 changed files with 52 additions and 39 deletions

View File

@@ -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)

View File

@@ -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'

View File

44
backend/locale/loader.py Normal file
View 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()

View File

@@ -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()