更新配置文件,重构工作流管理逻辑,调整国际化文件文职,优化图像生成和文本转语音服务的工作流解析,确保默认工作流配置必填,调整前端工作流选择逻辑。
This commit is contained in:
117
web/i18n/__init__.py
Normal file
117
web/i18n/__init__.py
Normal file
@@ -0,0 +1,117 @@
|
||||
"""
|
||||
International language support for ReelForge Web UI
|
||||
"""
|
||||
|
||||
import json
|
||||
from pathlib import Path
|
||||
from typing import Dict, Optional
|
||||
|
||||
from loguru import logger
|
||||
|
||||
_locales: Dict[str, dict] = {}
|
||||
_current_language: str = "zh_CN"
|
||||
|
||||
|
||||
def load_locales() -> Dict[str, dict]:
|
||||
"""Load all locale files from locales directory"""
|
||||
global _locales
|
||||
|
||||
locales_dir = Path(__file__).parent / "locales"
|
||||
|
||||
if not locales_dir.exists():
|
||||
logger.warning(f"Locales directory not found: {locales_dir}")
|
||||
return _locales
|
||||
|
||||
for json_file in locales_dir.glob("*.json"):
|
||||
lang_code = json_file.stem
|
||||
try:
|
||||
with open(json_file, "r", encoding="utf-8") as f:
|
||||
_locales[lang_code] = json.load(f)
|
||||
logger.debug(f"Loaded locale: {lang_code}")
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to load locale {lang_code}: {e}")
|
||||
|
||||
logger.info(f"Loaded {len(_locales)} locales: {list(_locales.keys())}")
|
||||
return _locales
|
||||
|
||||
|
||||
def set_language(lang_code: str):
|
||||
"""Set current language"""
|
||||
global _current_language
|
||||
if lang_code in _locales:
|
||||
_current_language = lang_code
|
||||
logger.debug(f"Language set to: {lang_code}")
|
||||
else:
|
||||
logger.warning(f"Language {lang_code} not found, keeping {_current_language}")
|
||||
|
||||
|
||||
def get_language() -> str:
|
||||
"""Get current language"""
|
||||
return _current_language
|
||||
|
||||
|
||||
def tr(key: str, fallback: Optional[str] = None, **kwargs) -> str:
|
||||
"""
|
||||
Translate a key to current language
|
||||
|
||||
Args:
|
||||
key: Translation key (e.g., "app.title")
|
||||
fallback: Fallback text if key not found
|
||||
**kwargs: Format parameters for string interpolation
|
||||
|
||||
Returns:
|
||||
Translated text
|
||||
|
||||
Example:
|
||||
tr("app.title") # => "ReelForge"
|
||||
tr("error.missing_field", field="API Key") # => "请填写 API Key"
|
||||
"""
|
||||
locale = _locales.get(_current_language, {})
|
||||
translations = locale.get("t", {})
|
||||
|
||||
result = translations.get(key)
|
||||
|
||||
if result is None:
|
||||
# Try fallback parameter
|
||||
if fallback is not None:
|
||||
result = fallback
|
||||
# Try English fallback
|
||||
elif _current_language != "en_US" and "en_US" in _locales:
|
||||
en_locale = _locales["en_US"]
|
||||
result = en_locale.get("t", {}).get(key)
|
||||
|
||||
# Last resort: return the key itself
|
||||
if result is None:
|
||||
result = key
|
||||
logger.debug(f"Translation missing: {key}")
|
||||
|
||||
# Apply string interpolation if kwargs provided
|
||||
if kwargs:
|
||||
try:
|
||||
result = result.format(**kwargs)
|
||||
except (KeyError, ValueError) as e:
|
||||
logger.warning(f"Failed to format translation '{key}': {e}")
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def get_language_name(lang_code: Optional[str] = None) -> str:
|
||||
"""Get display name of a language"""
|
||||
if lang_code is None:
|
||||
lang_code = _current_language
|
||||
|
||||
locale = _locales.get(lang_code, {})
|
||||
return locale.get("language_name", lang_code)
|
||||
|
||||
|
||||
def get_available_languages() -> Dict[str, str]:
|
||||
"""Get all available languages with their display names"""
|
||||
return {
|
||||
code: locale.get("language_name", code)
|
||||
for code, locale in _locales.items()
|
||||
}
|
||||
|
||||
|
||||
# Auto-load locales on import
|
||||
load_locales()
|
||||
|
||||
Reference in New Issue
Block a user