feat(deploy): fix docker deployment and add backend i18n
- Docker Deployment Fixes: - Switch base images to docker.m.daocloud.io to resolve registry 401 errors - Add Postgres and Redis services to docker-compose.traefik.yml - Fix frontend build: replace missing icons (Globe->Location, Chart->TrendCharts) - Fix frontend build: resolve pnpm CI/TTY issues and frozen lockfile errors - Add missing backend dependencies (sqlalchemy, psycopg2, redis-py, celery, docker-py) in pixi.toml - Ensure database tables are created on startup (lifespan event) - Backend Internationalization (i18n): - Add backend/app/core/i18n.py for locale handling - Update API endpoints (jobs, tasks, uploads, results) to return localized messages - Support 'Accept-Language' header (en/zh) - Documentation: - Update DOCKER_DEPLOYMENT.md with new architecture and troubleshooting - Update AGENTS.md with latest stack details and deployment steps - Update @fix_plan.md status Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
71
backend/app/utils/i18n.py
Normal file
71
backend/app/utils/i18n.py
Normal file
@@ -0,0 +1,71 @@
|
||||
from typing import Dict, Optional
|
||||
from fastapi import Header
|
||||
|
||||
# Translation dictionaries
|
||||
TRANSLATIONS = {
|
||||
"en": {
|
||||
"job_not_found": "Job not found",
|
||||
"invalid_extension": "Invalid file extension: {ext}. Allowed: {allowed}",
|
||||
"single_file_only": "Only one file allowed per task",
|
||||
"queue_update_triggered": "Queue update triggered",
|
||||
"task_created": "Task created successfully",
|
||||
"server_error": "Internal server error",
|
||||
"job_not_completed": "Job not completed. Current status: {status}",
|
||||
"results_not_found": "Results not found on disk",
|
||||
"job_deleted": "Job {job_id} deleted successfully",
|
||||
"use_post_jobs": "Use POST /api/v1/jobs/create for now",
|
||||
"task_not_found": "Task not found",
|
||||
"task_not_in_queue": "Task is not in queue",
|
||||
},
|
||||
"zh": {
|
||||
"job_not_found": "任务不存在",
|
||||
"invalid_extension": "文件后缀无效: {ext}。允许: {allowed}",
|
||||
"single_file_only": "每次任务只能上传一个文件",
|
||||
"queue_update_triggered": "已触发队列更新",
|
||||
"task_created": "任务创建成功",
|
||||
"server_error": "服务器内部错误",
|
||||
"job_not_completed": "任务未完成。当前状态: {status}",
|
||||
"results_not_found": "未找到结果文件",
|
||||
"job_deleted": "任务 {job_id} 已删除",
|
||||
"use_post_jobs": "请使用 POST /api/v1/jobs/create 接口",
|
||||
"task_not_found": "任务不存在",
|
||||
"task_not_in_queue": "任务不在队列中",
|
||||
}
|
||||
}
|
||||
|
||||
DEFAULT_LANG = "en"
|
||||
|
||||
def get_language(accept_language: Optional[str] = Header(None)) -> str:
|
||||
"""
|
||||
Determine the preferred language from the Accept-Language header.
|
||||
Defaults to 'en' if not specified or not supported.
|
||||
"""
|
||||
if not accept_language:
|
||||
return DEFAULT_LANG
|
||||
|
||||
# Simple parsing: check if 'zh' is in the header
|
||||
# A more robust parser could be added if needed
|
||||
if "zh" in accept_language.lower():
|
||||
return "zh"
|
||||
|
||||
return DEFAULT_LANG
|
||||
|
||||
def get_text(key: str, lang: str = DEFAULT_LANG, **kwargs) -> str:
|
||||
"""
|
||||
Get translated text for a given key and language.
|
||||
Supports string formatting with kwargs.
|
||||
"""
|
||||
# Fallback to default language if lang not supported
|
||||
if lang not in TRANSLATIONS:
|
||||
lang = DEFAULT_LANG
|
||||
|
||||
# Fallback to key if message not found in language
|
||||
message = TRANSLATIONS[lang].get(key)
|
||||
if not message:
|
||||
# Try default language
|
||||
message = TRANSLATIONS[DEFAULT_LANG].get(key, key)
|
||||
|
||||
try:
|
||||
return message.format(**kwargs)
|
||||
except KeyError:
|
||||
return message
|
||||
Reference in New Issue
Block a user