- 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>
69 lines
2.5 KiB
Python
69 lines
2.5 KiB
Python
from fastapi import Request
|
|
from typing import Dict, Any, Optional
|
|
|
|
# Translation dictionaries
|
|
TRANSLATIONS = {
|
|
"en": {
|
|
"job_not_found": "Job not found",
|
|
"task_not_found": "Task not found",
|
|
"invalid_extension": "Invalid file extension: {ext}. Allowed: {allowed}",
|
|
"single_file_only": "Only one file allowed per task",
|
|
"job_not_completed": "Job not completed. Current status: {status}",
|
|
"results_not_found": "Results not found on disk",
|
|
"job_deleted": "Job {job_id} deleted successfully",
|
|
"task_not_in_queue": "Task is not in queue",
|
|
"use_create_endpoint": "Use POST /api/v1/jobs/create for now",
|
|
"upload_endpoint": "Upload endpoint",
|
|
"queue_update_triggered": "Queue update triggered"
|
|
},
|
|
"zh": {
|
|
"job_not_found": "未找到任务",
|
|
"task_not_found": "未找到任务",
|
|
"invalid_extension": "文件后缀无效: {ext}。允许: {allowed}",
|
|
"single_file_only": "每个任务仅允许上传一个文件",
|
|
"job_not_completed": "任务未完成。当前状态: {status}",
|
|
"results_not_found": "未在磁盘上找到结果文件",
|
|
"job_deleted": "任务 {job_id} 已成功删除",
|
|
"task_not_in_queue": "任务不在队列中",
|
|
"use_create_endpoint": "请使用 POST /api/v1/jobs/create 接口",
|
|
"upload_endpoint": "上传接口",
|
|
"queue_update_triggered": "已触发队列更新"
|
|
}
|
|
}
|
|
|
|
DEFAULT_LOCALE = "en"
|
|
|
|
def get_locale(request: Request) -> str:
|
|
"""
|
|
Get locale from Accept-Language header.
|
|
Simple implementation: checks if 'zh' is in the header.
|
|
"""
|
|
accept_language = request.headers.get("accept-language", "")
|
|
if "zh" in accept_language.lower():
|
|
return "zh"
|
|
return "en"
|
|
|
|
class I18n:
|
|
def __init__(self, request: Request):
|
|
self.locale = get_locale(request)
|
|
|
|
def t(self, key: str, **kwargs) -> str:
|
|
"""
|
|
Translate a key.
|
|
If key not found, return key.
|
|
Supports string formatting with kwargs.
|
|
"""
|
|
messages = TRANSLATIONS.get(self.locale, TRANSLATIONS[DEFAULT_LOCALE])
|
|
message = messages.get(key, TRANSLATIONS[DEFAULT_LOCALE].get(key, key))
|
|
|
|
if kwargs:
|
|
try:
|
|
return message.format(**kwargs)
|
|
except KeyError:
|
|
return message
|
|
return message
|
|
|
|
async def get_i18n(request: Request) -> I18n:
|
|
"""Dependency for getting I18n instance"""
|
|
return I18n(request)
|