清理冗余路由代码,修复首页标题与模板安全

- 简化 http-api/http-tcp/web-toolkit 的 router.py,抽取重复代码
- 修复 ws-api middleware 中间件返回值传递问题
- 修复 web-toolkit template.py 安全漏洞 (eval → AST 验证)
- 将首页标题从 "OSS Runtime" 改为 "Future OSS"
- 更新 README.md 与 static/banner.svg
- 新增 i18n 国际化插件 (骨架)
- 新增 oss/shared/ 共享模块
This commit is contained in:
Falck
2026-04-06 12:40:49 +08:00
parent c881b1b8d1
commit f894e55602
29 changed files with 890 additions and 201 deletions

View File

@@ -0,0 +1,156 @@
"""i18n 核心引擎"""
import json
import re
from pathlib import Path
from typing import Any, Optional
class I18nEngine:
"""国际化引擎"""
def __init__(self):
self._translations: dict[str, dict[str, Any]] = {} # {locale: {key: value}}
self._current_locale: str = "zh-CN"
self._fallback_locale: str = "en-US"
self._supported_locales: list[str] = []
self._locales_dir: str = ""
def load_locales(self, locales_dir: str, locales: list[str]):
"""加载语言文件
Args:
locales_dir: 语言文件目录路径
locales: 支持的语言列表
"""
self._locales_dir = locales_dir
self._supported_locales = locales
locales_path = Path(locales_dir)
if not locales_path.exists():
locales_path.mkdir(parents=True, exist_ok=True)
return
for locale in locales:
locale_file = locales_path / f"{locale}.json"
if locale_file.exists():
try:
content = locale_file.read_text(encoding="utf-8")
self._translations[locale] = json.loads(content)
except (json.JSONDecodeError, Exception) as e:
print(f"[i18n] 加载语言文件失败 {locale_file}: {e}")
self._translations[locale] = {}
def set_locale(self, locale: str):
"""设置当前语言"""
if locale in self._supported_locales:
self._current_locale = locale
def get_locale(self) -> str:
"""获取当前语言"""
return self._current_locale
def set_fallback(self, locale: str):
"""设置回退语言"""
self._fallback_locale = locale
def t(self, key: str, locale: Optional[str] = None, **kwargs) -> str:
"""翻译文本
Args:
key: 翻译键 (支持点号分隔的嵌套路径,如 "user.greeting")
locale: 指定语言 (默认使用当前语言)
**kwargs: 插值参数
Returns:
翻译后的文本
"""
target_locale = locale or self._current_locale
# 尝试从指定语言获取
value = self._get_nested(key, self._translations.get(target_locale, {}))
# 如果未找到,尝试从回退语言获取
if value is None and target_locale != self._fallback_locale:
value = self._get_nested(key, self._translations.get(self._fallback_locale, {}))
# 仍未找到,返回键名
if value is None:
return key
# 插值处理: {{name}} 或 {name}
return self._interpolate(value, kwargs)
def _get_nested(self, key: str, data: dict) -> Any:
"""获取嵌套字典值"""
keys = key.split(".")
current = data
for k in keys:
if isinstance(current, dict) and k in current:
current = current[k]
else:
return None
return current
def _interpolate(self, text: str, kwargs: dict) -> str:
"""插值替换: {{name}} 或 {name}"""
# 支持 {{name}} 格式
result = re.sub(r'\{\{(\w+)\}\}', lambda m: str(kwargs.get(m.group(1), m.group(0))), text)
# 支持 {name} 格式 (如果未被 {{}} 替换)
result = re.sub(r'\{(\w+)\}', lambda m: str(kwargs.get(m.group(1), m.group(0))), result)
return result
def get_supported_locales(self) -> list[str]:
"""获取支持的语言列表"""
return self._supported_locales
def is_valid_locale(self, locale: str) -> bool:
"""检查语言是否有效"""
return locale in self._supported_locales
def detect_locale(self, accept_language: Optional[str] = None,
query_lang: Optional[str] = None,
cookie_lang: Optional[str] = None) -> str:
"""检测语言优先级
Args:
accept_language: HTTP Accept-Language 头
query_lang: URL 查询参数 ?lang=xx
cookie_lang: Cookie 中的语言
Returns:
检测到的语言代码
"""
# 1. 查询参数优先级最高
if query_lang and self.is_valid_locale(query_lang):
return query_lang
# 2. Cookie 次之
if cookie_lang and self.is_valid_locale(cookie_lang):
return cookie_lang
# 3. Accept-Language 头
if accept_language:
# 解析 "zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7"
languages = []
for part in accept_language.split(","):
part = part.strip()
if ";q=" in part:
lang, q = part.split(";q=")
languages.append((lang.strip(), float(q)))
else:
languages.append((part, 1.0))
# 按权重排序
languages.sort(key=lambda x: x[1], reverse=True)
for lang, _ in languages:
# 精确匹配
if self.is_valid_locale(lang):
return lang
# 前缀匹配 (zh 匹配 zh-CN, zh-TW)
for supported in self._supported_locales:
if supported.startswith(lang + "-") or lang.startswith(supported.split("-")[0] + "-"):
return supported
# 4. 默认语言
return self._current_locale