補充多語系文本

This commit is contained in:
Minidoracat 2025-06-13 10:33:24 +08:00
parent 01acf5ee62
commit 82a7473f85
12 changed files with 558 additions and 136 deletions

View File

@ -2,7 +2,8 @@
"app": { "app": {
"title": "MCP Interactive Feedback System", "title": "MCP Interactive Feedback System",
"subtitle": "AI Assistant Interactive Feedback Platform", "subtitle": "AI Assistant Interactive Feedback Platform",
"projectDirectory": "Project Directory" "projectDirectory": "Project Directory",
"updateFailed": "Failed to update content, please manually refresh the page to view new AI work summary"
}, },
"tabs": { "tabs": {
"feedback": "💬 Feedback", "feedback": "💬 Feedback",
@ -32,7 +33,15 @@
"submit": "Ctrl+Enter to submit (Cmd+Enter on Mac, numpad supported)", "submit": "Ctrl+Enter to submit (Cmd+Enter on Mac, numpad supported)",
"clear": "Ctrl+Delete to clear (Cmd+Delete on Mac)", "clear": "Ctrl+Delete to clear (Cmd+Delete on Mac)",
"paste": "Ctrl+V to paste images (Cmd+V on Mac)" "paste": "Ctrl+V to paste images (Cmd+V on Mac)"
} },
"submitSuccess": "Feedback submitted successfully!",
"submittedWaiting": "Feedback submitted, waiting for next MCP call...",
"waitingForUser": "Waiting for user feedback...",
"alreadySubmitted": "Feedback already submitted, please wait for next MCP call",
"processingFeedback": "Processing, please wait",
"connectingMessage": "WebSocket connecting, feedback will be submitted automatically when connection is ready...",
"invalidState": "Current state does not allow submission",
"sendFailed": "Send failed, please retry"
}, },
"summary": { "summary": {
"title": "📋 AI Work Summary", "title": "📋 AI Work Summary",
@ -55,7 +64,11 @@
"running": "Running...", "running": "Running...",
"completed": "Completed", "completed": "Completed",
"error": "Execution Error", "error": "Execution Error",
"history": "Command History" "history": "Command History",
"notConnected": "WebSocket not connected, cannot execute command",
"emptyCommand": "Please enter a command",
"sendFailed": "Failed to send command",
"executing": "Executing..."
}, },
"command": { "command": {
"title": "⚡ Command Execution", "title": "⚡ Command Execution",
@ -179,6 +192,69 @@
"detected": "Detected", "detected": "Detected",
"error": "Failed" "error": "Failed"
}, },
"sessionManagement": {
"title": "Session Management",
"currentSession": "Current Session",
"sessionHistory": "Session History",
"statistics": "Statistics",
"sessionId": "Session ID",
"status": "Status",
"activeTime": "Active Time",
"switchSession": "Switch Session",
"viewDetails": "View Details",
"refresh": "Refresh",
"noHistory": "No session history",
"todaySessions": "Today's Sessions",
"averageDuration": "Average Duration",
"createdTime": "Created Time",
"project": "Project",
"aiSummary": "AI Summary",
"noSummary": "No summary",
"loading": "Loading...",
"collapsePanel": "Collapse Panel",
"expandPanel": "Expand Panel",
"sessionPanel": "Session",
"sessionDetails": {
"title": "Session Details",
"close": "Close",
"duration": "Duration",
"projectDirectory": "Project Directory",
"summary": "Summary",
"noSummary": "No summary available",
"unknown": "Unknown"
}
},
"connectionMonitor": {
"connecting": "Connecting...",
"connected": "Connected",
"disconnected": "Disconnected",
"reconnecting": "Reconnecting... (attempt {attempt})",
"connectionFailed": "Connection failed",
"connectionError": "Connection error",
"noActiveSession": "No active session",
"maxReconnectReached": "WebSocket connection failed, please refresh the page to retry",
"latency": "Latency",
"connectionTime": "Connection Time",
"reconnectCount": "Reconnects",
"messageCount": "Messages",
"sessionCount": "Sessions",
"statusText": "Status",
"waiting": "Waiting",
"times": "times",
"quality": {
"excellent": "Excellent",
"good": "Good",
"fair": "Fair",
"poor": "Poor",
"unknown": "Unknown"
},
"metrics": {
"messages": "Messages",
"latencyMs": "Latency",
"sessions": "Sessions",
"reconnects": "Reconnects"
}
},
"dynamic": { "dynamic": {
"aiSummary": "Test Web UI Functionality\n\n🎯 **Test Items:**\n- Web UI server startup and operation\n- WebSocket real-time communication\n- Feedback submission functionality\n- Image upload and preview\n- Command execution functionality\n- Smart Ctrl+V image pasting\n- Multi-language interface functionality\n\n📋 **Test Steps:**\n1. Test image upload (drag-drop, file selection, clipboard)\n2. Press Ctrl+V in text box to test smart pasting\n3. Try switching languages (Traditional Chinese/Simplified Chinese/English)\n4. Test command execution functionality\n5. Submit feedback and images\n\nPlease test these features and provide feedback!", "aiSummary": "Test Web UI Functionality\n\n🎯 **Test Items:**\n- Web UI server startup and operation\n- WebSocket real-time communication\n- Feedback submission functionality\n- Image upload and preview\n- Command execution functionality\n- Smart Ctrl+V image pasting\n- Multi-language interface functionality\n\n📋 **Test Steps:**\n1. Test image upload (drag-drop, file selection, clipboard)\n2. Press Ctrl+V in text box to test smart pasting\n3. Try switching languages (Traditional Chinese/Simplified Chinese/English)\n4. Test command execution functionality\n5. Submit feedback and images\n\nPlease test these features and provide feedback!",

View File

@ -2,7 +2,8 @@
"app": { "app": {
"title": "MCP 交互反馈系统", "title": "MCP 交互反馈系统",
"subtitle": "AI 助手交互反馈平台", "subtitle": "AI 助手交互反馈平台",
"projectDirectory": "项目目录" "projectDirectory": "项目目录",
"updateFailed": "更新内容失败,请手动刷新页面以查看新的 AI 工作摘要"
}, },
"tabs": { "tabs": {
"feedback": "💬 反馈", "feedback": "💬 反馈",
@ -32,7 +33,15 @@
"submit": "Ctrl+Enter 提交 (Mac 用 Cmd+Enter支持数字键盘)", "submit": "Ctrl+Enter 提交 (Mac 用 Cmd+Enter支持数字键盘)",
"clear": "Ctrl+Delete 清除 (Mac 用 Cmd+Delete)", "clear": "Ctrl+Delete 清除 (Mac 用 Cmd+Delete)",
"paste": "Ctrl+V 粘贴图片 (Mac 用 Cmd+V)" "paste": "Ctrl+V 粘贴图片 (Mac 用 Cmd+V)"
} },
"submitSuccess": "反馈提交成功!",
"submittedWaiting": "已送出反馈,等待下次 MCP 调用...",
"waitingForUser": "等待用户反馈...",
"alreadySubmitted": "反馈已提交,请等待下次 MCP 调用",
"processingFeedback": "正在处理中,请稍候",
"connectingMessage": "WebSocket 连接中,反馈将在连接就绪后自动提交...",
"invalidState": "当前状态不允许提交",
"sendFailed": "发送失败,请重试"
}, },
"summary": { "summary": {
"title": "📋 AI 工作摘要", "title": "📋 AI 工作摘要",
@ -55,7 +64,11 @@
"running": "执行中...", "running": "执行中...",
"completed": "执行完成", "completed": "执行完成",
"error": "执行错误", "error": "执行错误",
"history": "命令历史" "history": "命令历史",
"notConnected": "WebSocket 未连接,无法执行命令",
"emptyCommand": "请输入命令",
"sendFailed": "发送命令失败",
"executing": "正在执行..."
}, },
"command": { "command": {
"title": "⚡ 命令执行", "title": "⚡ 命令执行",
@ -179,6 +192,69 @@
"detected": "已检测", "detected": "已检测",
"error": "失败" "error": "失败"
}, },
"sessionManagement": {
"title": "会话管理",
"currentSession": "当前会话",
"sessionHistory": "会话历史",
"statistics": "统计信息",
"sessionId": "会话 ID",
"status": "状态",
"activeTime": "活跃时间",
"switchSession": "切换会话",
"viewDetails": "详细信息",
"refresh": "重新整理",
"noHistory": "暂无历史会话",
"todaySessions": "今日会话",
"averageDuration": "平均时长",
"createdTime": "建立时间",
"project": "项目",
"aiSummary": "AI 总结",
"noSummary": "无总结",
"loading": "加载中...",
"collapsePanel": "收合面板",
"expandPanel": "展开面板",
"sessionPanel": "会话",
"sessionDetails": {
"title": "会话详细信息",
"close": "关闭",
"duration": "持续时间",
"projectDirectory": "项目目录",
"summary": "总结",
"noSummary": "暂无总结",
"unknown": "未知"
}
},
"connectionMonitor": {
"connecting": "连接中...",
"connected": "已连接",
"disconnected": "已断线",
"reconnecting": "重连中... (第{attempt}次)",
"connectionFailed": "连接失败",
"connectionError": "连接错误",
"noActiveSession": "没有活跃会话",
"maxReconnectReached": "WebSocket 连接失败,请刷新页面重试",
"latency": "延迟",
"connectionTime": "连线时间",
"reconnectCount": "重连",
"messageCount": "消息",
"sessionCount": "会话",
"statusText": "状态",
"waiting": "等待中",
"times": "次",
"quality": {
"excellent": "优秀",
"good": "良好",
"fair": "一般",
"poor": "较差",
"unknown": "未知"
},
"metrics": {
"messages": "消息",
"latencyMs": "延迟",
"sessions": "会话",
"reconnects": "重连"
}
},
"dynamic": { "dynamic": {
"aiSummary": "测试 Web UI 功能\n\n🎯 **功能测试项目:**\n- Web UI 服务器启动和运行\n- WebSocket 实时通讯\n- 反馈提交功能\n- 图片上传和预览\n- 命令执行功能\n- 智能 Ctrl+V 图片粘贴\n- 多语言界面功能\n\n📋 **测试步骤:**\n1. 测试图片上传(拖拽、选择文件、剪贴板)\n2. 在文本框内按 Ctrl+V 测试智能粘贴\n3. 尝试切换语言(繁中/简中/英文)\n4. 测试命令执行功能\n5. 提交反馈和图片\n\n请测试这些功能并提供反馈", "aiSummary": "测试 Web UI 功能\n\n🎯 **功能测试项目:**\n- Web UI 服务器启动和运行\n- WebSocket 实时通讯\n- 反馈提交功能\n- 图片上传和预览\n- 命令执行功能\n- 智能 Ctrl+V 图片粘贴\n- 多语言界面功能\n\n📋 **测试步骤:**\n1. 测试图片上传(拖拽、选择文件、剪贴板)\n2. 在文本框内按 Ctrl+V 测试智能粘贴\n3. 尝试切换语言(繁中/简中/英文)\n4. 测试命令执行功能\n5. 提交反馈和图片\n\n请测试这些功能并提供反馈",

View File

@ -7,7 +7,8 @@
"author": "作者Fábio Ferreira (原作者) / Minidoracat (增強版)", "author": "作者Fábio Ferreira (原作者) / Minidoracat (增強版)",
"authorLink": "GitHub: Minidoracat", "authorLink": "GitHub: Minidoracat",
"credits": "⭐ 如果這個專案對您有幫助,請在 GitHub 上給我們一個星星!\n\n本增強版本由 Minidoracat 開發和維護,大幅擴展了專案功能,新增了 Web UI 介面、圖片支援、多語言能力以及許多其他改進功能。\n\n同時感謝 sanshao85 的 mcp-feedback-collector 專案提供的 UI 設計靈感。\n\n開源協作讓技術變得更美好", "credits": "⭐ 如果這個專案對您有幫助,請在 GitHub 上給我們一個星星!\n\n本增強版本由 Minidoracat 開發和維護,大幅擴展了專案功能,新增了 Web UI 介面、圖片支援、多語言能力以及許多其他改進功能。\n\n同時感謝 sanshao85 的 mcp-feedback-collector 專案提供的 UI 設計靈感。\n\n開源協作讓技術變得更美好",
"projectDirectory": "專案目錄" "projectDirectory": "專案目錄",
"updateFailed": "更新內容失敗,請手動刷新頁面以查看新的 AI 工作摘要"
}, },
"tabs": { "tabs": {
"feedback": "💬 回饋", "feedback": "💬 回饋",
@ -37,7 +38,15 @@
"submit": "Ctrl+Enter 提交 (Mac 用 Cmd+Enter支援數字鍵盤)", "submit": "Ctrl+Enter 提交 (Mac 用 Cmd+Enter支援數字鍵盤)",
"clear": "Ctrl+Delete 清除 (Mac 用 Cmd+Delete)", "clear": "Ctrl+Delete 清除 (Mac 用 Cmd+Delete)",
"paste": "Ctrl+V 貼上圖片 (Mac 用 Cmd+V)" "paste": "Ctrl+V 貼上圖片 (Mac 用 Cmd+V)"
} },
"submitSuccess": "回饋提交成功!",
"submittedWaiting": "已送出反饋,等待下次 MCP 調用...",
"waitingForUser": "等待用戶回饋...",
"alreadySubmitted": "回饋已提交,請等待下次 MCP 調用",
"processingFeedback": "正在處理中,請稍候",
"connectingMessage": "WebSocket 連接中,回饋將在連接就緒後自動提交...",
"invalidState": "當前狀態不允許提交",
"sendFailed": "發送失敗,請重試"
}, },
"summary": { "summary": {
"title": "📋 AI 工作摘要", "title": "📋 AI 工作摘要",
@ -60,7 +69,11 @@
"running": "執行中...", "running": "執行中...",
"completed": "執行完成", "completed": "執行完成",
"error": "執行錯誤", "error": "執行錯誤",
"history": "命令歷史" "history": "命令歷史",
"notConnected": "WebSocket 未連接,無法執行命令",
"emptyCommand": "請輸入命令",
"sendFailed": "發送命令失敗",
"executing": "正在執行..."
}, },
"command": { "command": {
"title": "⚡ 命令執行", "title": "⚡ 命令執行",
@ -184,6 +197,69 @@
"detected": "已檢測", "detected": "已檢測",
"error": "失敗" "error": "失敗"
}, },
"sessionManagement": {
"title": "會話管理",
"currentSession": "當前會話",
"sessionHistory": "會話歷史",
"statistics": "統計資訊",
"sessionId": "會話 ID",
"status": "狀態",
"activeTime": "活躍時間",
"switchSession": "切換會話",
"viewDetails": "詳細資訊",
"refresh": "重新整理",
"noHistory": "暫無歷史會話",
"todaySessions": "今日會話",
"averageDuration": "平均時長",
"createdTime": "建立時間",
"project": "專案",
"aiSummary": "AI 摘要",
"loading": "載入中...",
"collapsePanel": "收合面板",
"expandPanel": "展開面板",
"sessionPanel": "會話",
"sessionDetails": {
"title": "會話詳細資訊",
"close": "關閉",
"duration": "持續時間",
"projectDirectory": "專案目錄",
"summary": "摘要",
"noSummary": "暫無摘要",
"unknown": "未知"
},
"noSummary": "無摘要"
},
"connectionMonitor": {
"connecting": "連接中...",
"connected": "已連接",
"disconnected": "已斷線",
"reconnecting": "重連中... (第{attempt}次)",
"connectionFailed": "連接失敗",
"connectionError": "連接錯誤",
"noActiveSession": "沒有活躍會話",
"maxReconnectReached": "WebSocket 連接失敗,請刷新頁面重試",
"latency": "延遲",
"connectionTime": "連線時間",
"reconnectCount": "重連",
"messageCount": "訊息",
"sessionCount": "會話",
"statusText": "狀態",
"waiting": "等待中",
"times": "次",
"quality": {
"excellent": "優秀",
"good": "良好",
"fair": "一般",
"poor": "較差",
"unknown": "未知"
},
"metrics": {
"messages": "訊息",
"latencyMs": "延遲",
"sessions": "會話",
"reconnects": "重連"
}
},
"dynamic": { "dynamic": {
"aiSummary": "測試 Web UI 功能\n\n🎯 **功能測試項目:**\n- Web UI 服務器啟動和運行\n- WebSocket 即時通訊\n- 回饋提交功能\n- 圖片上傳和預覽\n- 命令執行功能\n- 智能 Ctrl+V 圖片貼上\n- 多語言介面功能\n\n📋 **測試步驟:**\n1. 測試圖片上傳(拖拽、選擇檔案、剪貼簿)\n2. 在文字框內按 Ctrl+V 測試智能貼上\n3. 嘗試切換語言(繁中/簡中/英文)\n4. 測試命令執行功能\n5. 提交回饋和圖片\n\n請測試這些功能並提供回饋", "aiSummary": "測試 Web UI 功能\n\n🎯 **功能測試項目:**\n- Web UI 服務器啟動和運行\n- WebSocket 即時通訊\n- 回饋提交功能\n- 圖片上傳和預覽\n- 命令執行功能\n- 智能 Ctrl+V 圖片貼上\n- 多語言介面功能\n\n📋 **測試步驟:**\n1. 測試圖片上傳(拖拽、選擇檔案、剪貼簿)\n2. 在文字框內按 Ctrl+V 測試智能貼上\n3. 嘗試切換語言(繁中/簡中/英文)\n4. 測試命令執行功能\n5. 提交回饋和圖片\n\n請測試這些功能並提供回饋",

View File

@ -434,10 +434,12 @@
this.uiManager.setLastSubmissionTime(Date.now()); this.uiManager.setLastSubmissionTime(Date.now());
// 顯示成功訊息 // 顯示成功訊息
window.MCPFeedback.Utils.showMessage(data.message || '回饋提交成功!', window.MCPFeedback.Utils.CONSTANTS.MESSAGE_SUCCESS); const successMessage = window.i18nManager ? window.i18nManager.t('feedback.submitSuccess') : '回饋提交成功!';
window.MCPFeedback.Utils.showMessage(data.message || successMessage, window.MCPFeedback.Utils.CONSTANTS.MESSAGE_SUCCESS);
// 更新 AI 摘要區域顯示「已送出反饋」狀態 // 更新 AI 摘要區域顯示「已送出反饋」狀態
this.updateSummaryStatus('已送出反饋,等待下次 MCP 調用...'); const submittedMessage = window.i18nManager ? window.i18nManager.t('feedback.submittedWaiting') : '已送出反饋,等待下次 MCP 調用...';
this.updateSummaryStatus(submittedMessage);
console.log('反饋已提交,頁面保持開啟狀態'); console.log('反饋已提交,頁面保持開啟狀態');
}; };
@ -562,7 +564,8 @@
switch (statusInfo.status) { switch (statusInfo.status) {
case 'feedback_submitted': case 'feedback_submitted':
this.uiManager.setFeedbackState(window.MCPFeedback.Utils.CONSTANTS.FEEDBACK_SUBMITTED, sessionId); this.uiManager.setFeedbackState(window.MCPFeedback.Utils.CONSTANTS.FEEDBACK_SUBMITTED, sessionId);
this.updateSummaryStatus('已送出反饋,等待下次 MCP 調用...'); const submittedMessage = window.i18nManager ? window.i18nManager.t('feedback.submittedWaiting') : '已送出反饋,等待下次 MCP 調用...';
this.updateSummaryStatus(submittedMessage);
break; break;
case 'active': case 'active':
@ -575,7 +578,8 @@
} }
if (statusInfo.status === 'waiting') { if (statusInfo.status === 'waiting') {
this.updateSummaryStatus('等待用戶回饋...'); const waitingMessage = window.i18nManager ? window.i18nManager.t('feedback.waitingForUser') : '等待用戶回饋...';
this.updateSummaryStatus(waitingMessage);
} }
break; break;
} }
@ -620,18 +624,22 @@
const feedbackState = this.uiManager ? this.uiManager.getFeedbackState() : null; const feedbackState = this.uiManager ? this.uiManager.getFeedbackState() : null;
if (feedbackState === window.MCPFeedback.Utils.CONSTANTS.FEEDBACK_SUBMITTED) { if (feedbackState === window.MCPFeedback.Utils.CONSTANTS.FEEDBACK_SUBMITTED) {
window.MCPFeedback.Utils.showMessage('回饋已提交,請等待下次 MCP 調用', window.MCPFeedback.Utils.CONSTANTS.MESSAGE_WARNING); const submittedWarning = window.i18nManager ? window.i18nManager.t('feedback.alreadySubmitted') : '回饋已提交,請等待下次 MCP 調用';
window.MCPFeedback.Utils.showMessage(submittedWarning, window.MCPFeedback.Utils.CONSTANTS.MESSAGE_WARNING);
} else if (feedbackState === window.MCPFeedback.Utils.CONSTANTS.FEEDBACK_PROCESSING) { } else if (feedbackState === window.MCPFeedback.Utils.CONSTANTS.FEEDBACK_PROCESSING) {
window.MCPFeedback.Utils.showMessage('正在處理中,請稍候', window.MCPFeedback.Utils.CONSTANTS.MESSAGE_WARNING); const processingWarning = window.i18nManager ? window.i18nManager.t('feedback.processingFeedback') : '正在處理中,請稍候';
window.MCPFeedback.Utils.showMessage(processingWarning, window.MCPFeedback.Utils.CONSTANTS.MESSAGE_WARNING);
} else if (!this.webSocketManager || !this.webSocketManager.isReady()) { } else if (!this.webSocketManager || !this.webSocketManager.isReady()) {
// 收集回饋數據,等待連接就緒後提交 // 收集回饋數據,等待連接就緒後提交
const feedbackData = this.collectFeedbackData(); const feedbackData = this.collectFeedbackData();
if (feedbackData) { if (feedbackData) {
this.pendingSubmission = feedbackData; this.pendingSubmission = feedbackData;
window.MCPFeedback.Utils.showMessage('WebSocket 連接中,回饋將在連接就緒後自動提交...', window.MCPFeedback.Utils.CONSTANTS.MESSAGE_INFO); const connectingMessage = window.i18nManager ? window.i18nManager.t('feedback.connectingMessage') : 'WebSocket 連接中,回饋將在連接就緒後自動提交...';
window.MCPFeedback.Utils.showMessage(connectingMessage, window.MCPFeedback.Utils.CONSTANTS.MESSAGE_INFO);
} }
} else { } else {
window.MCPFeedback.Utils.showMessage('當前狀態不允許提交: ' + feedbackState, window.MCPFeedback.Utils.CONSTANTS.MESSAGE_WARNING); const invalidStateMessage = window.i18nManager ? window.i18nManager.t('feedback.invalidState') : '當前狀態不允許提交';
window.MCPFeedback.Utils.showMessage(invalidStateMessage + ': ' + feedbackState, window.MCPFeedback.Utils.CONSTANTS.MESSAGE_WARNING);
} }
}; };
@ -698,7 +706,8 @@
} catch (error) { } catch (error) {
console.error('❌ 發送回饋失敗:', error); console.error('❌ 發送回饋失敗:', error);
window.MCPFeedback.Utils.showMessage('發送失敗,請重試', window.MCPFeedback.Utils.CONSTANTS.MESSAGE_ERROR); const sendFailedMessage = window.i18nManager ? window.i18nManager.t('feedback.sendFailed') : '發送失敗,請重試';
window.MCPFeedback.Utils.showMessage(sendFailedMessage, window.MCPFeedback.Utils.CONSTANTS.MESSAGE_ERROR);
// 恢復到等待狀態 // 恢復到等待狀態
if (this.uiManager) { if (this.uiManager) {
@ -742,12 +751,14 @@
const command = commandInput ? commandInput.value.trim() : ''; const command = commandInput ? commandInput.value.trim() : '';
if (!command) { if (!command) {
this.appendCommandOutput('⚠️ 請輸入命令\n'); const emptyCommandMessage = window.i18nManager ? window.i18nManager.t('commands.emptyCommand') : '請輸入命令';
this.appendCommandOutput('⚠️ ' + emptyCommandMessage + '\n');
return; return;
} }
if (!this.webSocketManager || !this.webSocketManager.isConnected) { if (!this.webSocketManager || !this.webSocketManager.isConnected) {
this.appendCommandOutput('❌ WebSocket 未連接,無法執行命令\n'); const notConnectedMessage = window.i18nManager ? window.i18nManager.t('commands.notConnected') : 'WebSocket 未連接,無法執行命令';
this.appendCommandOutput('❌ ' + notConnectedMessage + '\n');
return; return;
} }
@ -764,13 +775,16 @@
if (success) { if (success) {
// 清空輸入框 // 清空輸入框
commandInput.value = ''; commandInput.value = '';
this.appendCommandOutput('[正在執行...]\n'); const executingMessage = window.i18nManager ? window.i18nManager.t('commands.executing') : '正在執行...';
this.appendCommandOutput('[' + executingMessage + ']\n');
} else { } else {
this.appendCommandOutput('❌ 發送命令失敗\n'); const sendFailedMessage = window.i18nManager ? window.i18nManager.t('commands.sendFailed') : '發送命令失敗';
this.appendCommandOutput('❌ ' + sendFailedMessage + '\n');
} }
} catch (error) { } catch (error) {
this.appendCommandOutput('❌ 發送命令失敗: ' + error.message + '\n'); const sendFailedMessage = window.i18nManager ? window.i18nManager.t('commands.sendFailed') : '發送命令失敗';
this.appendCommandOutput('❌ ' + sendFailedMessage + ': ' + error.message + '\n');
} }
}; };
@ -867,7 +881,8 @@
}) })
.catch(function(error) { .catch(function(error) {
console.error('❌ 局部更新失敗:', error); console.error('❌ 局部更新失敗:', error);
window.MCPFeedback.Utils.showMessage('更新內容失敗,請手動刷新頁面以查看新的 AI 工作摘要', window.MCPFeedback.Utils.CONSTANTS.MESSAGE_WARNING); const updateFailedMessage = window.i18nManager ? window.i18nManager.t('app.updateFailed') : '更新內容失敗,請手動刷新頁面以查看新的 AI 工作摘要';
window.MCPFeedback.Utils.showMessage(updateFailedMessage, window.MCPFeedback.Utils.CONSTANTS.MESSAGE_WARNING);
}); });
}; };

View File

@ -171,6 +171,12 @@ class I18nManager {
// 只更新終端歡迎信息,不要覆蓋 AI 摘要 // 只更新終端歡迎信息,不要覆蓋 AI 摘要
this.updateTerminalWelcome(); this.updateTerminalWelcome();
// 更新會話管理相關的動態內容
this.updateSessionManagementContent();
// 更新連線監控相關的動態內容
this.updateConnectionMonitorContent();
// 更新應用程式中的動態狀態文字(使用新的模組化架構) // 更新應用程式中的動態狀態文字(使用新的模組化架構)
if (window.feedbackApp && window.feedbackApp.isInitialized) { if (window.feedbackApp && window.feedbackApp.isInitialized) {
// 更新 UI 狀態 // 更新 UI 狀態
@ -199,6 +205,52 @@ class I18nManager {
} }
} }
updateSessionManagementContent() {
// 更新會話管理面板中的動態文字
if (window.feedbackApp && window.feedbackApp.sessionManager) {
// 觸發會話管理器重新渲染,這會使用最新的翻譯
if (typeof window.feedbackApp.sessionManager.updateDisplay === 'function') {
window.feedbackApp.sessionManager.updateDisplay();
}
}
// 更新狀態徽章文字
const statusBadges = document.querySelectorAll('.status-badge');
statusBadges.forEach(badge => {
const statusClass = Array.from(badge.classList).find(cls =>
['waiting', 'active', 'completed', 'error', 'connecting', 'connected', 'disconnected'].includes(cls)
);
if (statusClass && window.MCPFeedback && window.MCPFeedback.Utils && window.MCPFeedback.Utils.Status) {
badge.textContent = window.MCPFeedback.Utils.Status.getStatusText(statusClass);
}
});
}
updateConnectionMonitorContent() {
// 更新連線監控器中的動態文字
if (window.feedbackApp && window.feedbackApp.connectionMonitor) {
// 觸發連線監控器重新更新顯示
if (typeof window.feedbackApp.connectionMonitor.updateDisplay === 'function') {
window.feedbackApp.connectionMonitor.updateDisplay();
}
}
// 更新連線狀態文字
const statusText = document.querySelector('.status-text');
if (statusText && window.MCPFeedback && window.MCPFeedback.Utils && window.MCPFeedback.Utils.Status) {
// 從元素的類名或數據屬性中獲取狀態
const indicator = statusText.closest('.connection-indicator');
if (indicator) {
const statusClass = Array.from(indicator.classList).find(cls =>
['connecting', 'connected', 'disconnected', 'reconnecting'].includes(cls)
);
if (statusClass) {
statusText.textContent = window.MCPFeedback.Utils.Status.getConnectionStatusText(statusClass);
}
}
}
}
setupLanguageSelectors() { setupLanguageSelectors() {
// 舊版下拉選擇器(兼容性保留) // 舊版下拉選擇器(兼容性保留)
const selector = document.getElementById('settingsLanguageSelect'); const selector = document.getElementById('settingsLanguageSelect');

View File

@ -101,16 +101,19 @@
*/ */
ConnectionMonitor.prototype.updateConnectionStatus = function(status, message) { ConnectionMonitor.prototype.updateConnectionStatus = function(status, message) {
console.log('🔍 連線狀態更新:', status, message); console.log('🔍 連線狀態更新:', status, message);
// 更新狀態顯示 // 更新狀態顯示
if (this.statusText) { if (this.statusText) {
this.statusText.textContent = message || status; // 使用 i18n 翻譯或提供的訊息
const displayText = message || (window.MCPFeedback && window.MCPFeedback.Utils && window.MCPFeedback.Utils.Status ?
window.MCPFeedback.Utils.Status.getConnectionStatusText(status) : status);
this.statusText.textContent = displayText;
} }
// 更新狀態圖示 // 更新狀態圖示
if (this.statusIcon) { if (this.statusIcon) {
this.statusIcon.className = 'status-icon'; this.statusIcon.className = 'status-icon';
switch (status) { switch (status) {
case 'connecting': case 'connecting':
case 'reconnecting': case 'reconnecting':
@ -123,7 +126,7 @@
this.statusIcon.classList.remove('pulse'); this.statusIcon.classList.remove('pulse');
} }
} }
// 更新連線指示器樣式 // 更新連線指示器樣式
const indicator = Utils.safeQuerySelector('.connection-indicator'); const indicator = Utils.safeQuerySelector('.connection-indicator');
if (indicator) { if (indicator) {
@ -263,10 +266,11 @@
ConnectionMonitor.prototype.updateDisplay = function() { ConnectionMonitor.prototype.updateDisplay = function() {
// 更新延遲顯示 // 更新延遲顯示
if (this.latencyDisplay) { if (this.latencyDisplay) {
const latencyLabel = window.i18nManager ? window.i18nManager.t('connectionMonitor.latency') : '延遲';
if (this.currentLatency > 0) { if (this.currentLatency > 0) {
this.latencyDisplay.textContent = '延遲: ' + this.currentLatency + 'ms'; this.latencyDisplay.textContent = latencyLabel + ': ' + this.currentLatency + 'ms';
} else { } else {
this.latencyDisplay.textContent = '延遲: --ms'; this.latencyDisplay.textContent = latencyLabel + ': --ms';
} }
} }
@ -283,14 +287,17 @@
const duration = Math.floor((Date.now() - this.connectionStartTime) / 1000); const duration = Math.floor((Date.now() - this.connectionStartTime) / 1000);
const minutes = Math.floor(duration / 60); const minutes = Math.floor(duration / 60);
const seconds = duration % 60; const seconds = duration % 60;
this.connectionTimeDisplay.textContent = '連線時間: ' + const connectionTimeLabel = window.i18nManager ? window.i18nManager.t('connectionMonitor.connectionTime') : '連線時間';
String(minutes).padStart(2, '0') + ':' + this.connectionTimeDisplay.textContent = connectionTimeLabel + ': ' +
String(minutes).padStart(2, '0') + ':' +
String(seconds).padStart(2, '0'); String(seconds).padStart(2, '0');
} }
// 更新重連次數 // 更新重連次數
if (this.reconnectCountDisplay) { if (this.reconnectCountDisplay) {
this.reconnectCountDisplay.textContent = '重連: ' + this.reconnectCount + ' 次'; const reconnectLabel = window.i18nManager ? window.i18nManager.t('connectionMonitor.reconnectCount') : '重連';
const timesLabel = window.i18nManager ? window.i18nManager.t('connectionMonitor.times') : '次';
this.reconnectCountDisplay.textContent = reconnectLabel + ': ' + this.reconnectCount + ' ' + timesLabel;
} }
// 更新訊息計數 // 更新訊息計數

View File

@ -96,8 +96,8 @@
statusColor: statusColor, statusColor: statusColor,
createdTime: createdTime, createdTime: createdTime,
duration: duration, duration: duration,
projectDirectory: sessionData.project_directory || '未知', projectDirectory: sessionData.project_directory || (window.i18nManager ? window.i18nManager.t('sessionManagement.sessionDetails.unknown') : '未知'),
summary: sessionData.summary || '暫無摘要' summary: sessionData.summary || (window.i18nManager ? window.i18nManager.t('sessionManagement.sessionDetails.noSummary') : '暫無摘要')
}; };
}; };
@ -125,42 +125,48 @@
* 創建彈窗 HTML * 創建彈窗 HTML
*/ */
SessionDetailsModal.prototype.createModalHTML = function(details) { SessionDetailsModal.prototype.createModalHTML = function(details) {
const i18n = window.i18nManager;
const title = i18n ? i18n.t('sessionManagement.sessionDetails.title') : '會話詳細資訊';
const closeLabel = i18n ? i18n.t('sessionManagement.sessionDetails.close') : '關閉';
const sessionIdLabel = i18n ? i18n.t('sessionManagement.sessionId') : '會話 ID';
const statusLabel = i18n ? i18n.t('sessionManagement.status') : '狀態';
return ` return `
<div class="session-details-modal" id="sessionDetailsModal"> <div class="session-details-modal" id="sessionDetailsModal">
<div class="modal-backdrop"></div> <div class="modal-backdrop"></div>
<div class="modal-content"> <div class="modal-content">
<div class="modal-header"> <div class="modal-header">
<h3>會話詳細資訊</h3> <h3>${title}</h3>
<button class="modal-close" id="closeSessionDetails" aria-label="關閉">&times;</button> <button class="modal-close" id="closeSessionDetails" aria-label="${closeLabel}">&times;</button>
</div> </div>
<div class="modal-body"> <div class="modal-body">
<div class="detail-row"> <div class="detail-row">
<span class="detail-label">會話 ID:</span> <span class="detail-label">${sessionIdLabel}:</span>
<span class="detail-value session-id" title="${details.sessionId}">${details.sessionId}</span> <span class="detail-value session-id" title="${details.sessionId}">${details.sessionId}</span>
</div> </div>
<div class="detail-row"> <div class="detail-row">
<span class="detail-label">狀態:</span> <span class="detail-label">${statusLabel}:</span>
<span class="detail-value" style="color: ${details.statusColor};">${details.status}</span> <span class="detail-value" style="color: ${details.statusColor};">${details.status}</span>
</div> </div>
<div class="detail-row"> <div class="detail-row">
<span class="detail-label">建立時間:</span> <span class="detail-label">${i18n ? i18n.t('sessionManagement.createdTime') : '建立時間'}:</span>
<span class="detail-value">${details.createdTime}</span> <span class="detail-value">${details.createdTime}</span>
</div> </div>
<div class="detail-row"> <div class="detail-row">
<span class="detail-label">持續時間:</span> <span class="detail-label">${i18n ? i18n.t('sessionManagement.sessionDetails.duration') : '持續時間'}:</span>
<span class="detail-value">${details.duration}</span> <span class="detail-value">${details.duration}</span>
</div> </div>
<div class="detail-row"> <div class="detail-row">
<span class="detail-label">專案目錄:</span> <span class="detail-label">${i18n ? i18n.t('sessionManagement.sessionDetails.projectDirectory') : '專案目錄'}:</span>
<span class="detail-value project-path" title="${details.projectDirectory}">${details.projectDirectory}</span> <span class="detail-value project-path" title="${details.projectDirectory}">${details.projectDirectory}</span>
</div> </div>
<div class="detail-row"> <div class="detail-row">
<span class="detail-label">AI 摘要:</span> <span class="detail-label">${i18n ? i18n.t('sessionManagement.aiSummary') : 'AI 摘要'}:</span>
<div class="detail-value summary">${this.escapeHtml(details.summary)}</div> <div class="detail-value summary">${this.escapeHtml(details.summary)}</div>
</div> </div>
</div> </div>
<div class="modal-footer"> <div class="modal-footer">
<button class="btn-secondary" id="closeSessionDetailsBtn">關閉</button> <button class="btn-secondary" id="closeSessionDetailsBtn">${closeLabel}</button>
</div> </div>
</div> </div>
</div> </div>

View File

@ -102,10 +102,11 @@
SessionUIRenderer.prototype.updateSessionId = function(sessionData) { SessionUIRenderer.prototype.updateSessionId = function(sessionData) {
const sessionIdElement = this.currentSessionCard.querySelector('.session-id'); const sessionIdElement = this.currentSessionCard.querySelector('.session-id');
if (sessionIdElement && sessionData.session_id) { if (sessionIdElement && sessionData.session_id) {
const displayId = this.showFullSessionId ? const displayId = this.showFullSessionId ?
sessionData.session_id : sessionData.session_id :
sessionData.session_id.substring(0, 8) + '...'; sessionData.session_id.substring(0, 8) + '...';
DOMUtils.safeSetTextContent(sessionIdElement, '會話 ID: ' + displayId); const sessionIdLabel = window.i18nManager ? window.i18nManager.t('sessionManagement.sessionId') : '會話 ID';
DOMUtils.safeSetTextContent(sessionIdElement, sessionIdLabel + ': ' + displayId);
} }
}; };
@ -130,7 +131,8 @@
const timeElement = this.currentSessionCard.querySelector('.session-time'); const timeElement = this.currentSessionCard.querySelector('.session-time');
if (timeElement && sessionData.created_at) { if (timeElement && sessionData.created_at) {
const timeText = TimeUtils.formatTimestamp(sessionData.created_at, { format: 'time' }); const timeText = TimeUtils.formatTimestamp(sessionData.created_at, { format: 'time' });
DOMUtils.safeSetTextContent(timeElement, '建立時間: ' + timeText); const createdTimeLabel = window.i18nManager ? window.i18nManager.t('sessionManagement.createdTime') : '建立時間';
DOMUtils.safeSetTextContent(timeElement, createdTimeLabel + ': ' + timeText);
} }
}; };
@ -141,7 +143,8 @@
const projectElement = this.currentSessionCard.querySelector('.session-project'); const projectElement = this.currentSessionCard.querySelector('.session-project');
if (projectElement) { if (projectElement) {
const projectDir = sessionData.project_directory || './'; const projectDir = sessionData.project_directory || './';
DOMUtils.safeSetTextContent(projectElement, '專案: ' + projectDir); const projectLabel = window.i18nManager ? window.i18nManager.t('sessionManagement.project') : '專案';
DOMUtils.safeSetTextContent(projectElement, projectLabel + ': ' + projectDir);
} }
}; };
@ -151,8 +154,10 @@
SessionUIRenderer.prototype.updateSummary = function(sessionData) { SessionUIRenderer.prototype.updateSummary = function(sessionData) {
const summaryElement = this.currentSessionCard.querySelector('.session-summary'); const summaryElement = this.currentSessionCard.querySelector('.session-summary');
if (summaryElement) { if (summaryElement) {
const summary = sessionData.summary || '無摘要'; const noSummaryText = window.i18nManager ? window.i18nManager.t('sessionManagement.noSummary') : '無摘要';
DOMUtils.safeSetTextContent(summaryElement, 'AI 摘要: ' + summary); const summary = sessionData.summary || noSummaryText;
const summaryLabel = window.i18nManager ? window.i18nManager.t('sessionManagement.aiSummary') : 'AI 摘要';
DOMUtils.safeSetTextContent(summaryElement, summaryLabel + ': ' + summary);
} }
}; };
@ -205,9 +210,10 @@
* 渲染空歷史狀態 * 渲染空歷史狀態
*/ */
SessionUIRenderer.prototype.renderEmptyHistory = function() { SessionUIRenderer.prototype.renderEmptyHistory = function() {
const noHistoryText = window.i18nManager ? window.i18nManager.t('sessionManagement.noHistory') : '暫無歷史會話';
const emptyElement = DOMUtils.createElement('div', { const emptyElement = DOMUtils.createElement('div', {
className: 'no-sessions', className: 'no-sessions',
textContent: '暫無歷史會話' textContent: noHistoryText
}); });
this.historyList.appendChild(emptyElement); this.historyList.appendChild(emptyElement);
}; };
@ -242,9 +248,10 @@
const header = DOMUtils.createElement('div', { className: 'session-header' }); const header = DOMUtils.createElement('div', { className: 'session-header' });
// 會話 ID // 會話 ID
const sessionIdLabel = window.i18nManager ? window.i18nManager.t('sessionManagement.sessionId') : '會話 ID';
const sessionId = DOMUtils.createElement('div', { const sessionId = DOMUtils.createElement('div', {
className: 'session-id', className: 'session-id',
textContent: '會話 ID: ' + (sessionData.session_id || '').substring(0, 8) + '...' textContent: sessionIdLabel + ': ' + (sessionData.session_id || '').substring(0, 8) + '...'
}); });
// 狀態徽章 // 狀態徽章
@ -268,13 +275,17 @@
const info = DOMUtils.createElement('div', { className: 'session-info' }); const info = DOMUtils.createElement('div', { className: 'session-info' });
// 時間資訊 // 時間資訊
const timeText = sessionData.created_at ? const timeText = sessionData.created_at ?
TimeUtils.formatTimestamp(sessionData.created_at, { format: 'time' }) : TimeUtils.formatTimestamp(sessionData.created_at, { format: 'time' }) :
'--:--:--'; '--:--:--';
const timeLabel = isHistory ?
(window.i18nManager ? window.i18nManager.t('sessionManagement.sessionDetails.duration') : '完成時間') :
(window.i18nManager ? window.i18nManager.t('sessionManagement.createdTime') : '建立時間');
const timeElement = DOMUtils.createElement('div', { const timeElement = DOMUtils.createElement('div', {
className: 'session-time', className: 'session-time',
textContent: (isHistory ? '完成時間' : '建立時間') + ': ' + timeText textContent: timeLabel + ': ' + timeText
}); });
info.appendChild(timeElement); info.appendChild(timeElement);
@ -282,9 +293,10 @@
// 歷史會話顯示持續時間 // 歷史會話顯示持續時間
if (isHistory) { if (isHistory) {
const duration = this.calculateDisplayDuration(sessionData); const duration = this.calculateDisplayDuration(sessionData);
const durationLabel = window.i18nManager ? window.i18nManager.t('sessionManagement.sessionDetails.duration') : '持續時間';
const durationElement = DOMUtils.createElement('div', { const durationElement = DOMUtils.createElement('div', {
className: 'session-duration', className: 'session-duration',
textContent: '持續時間: ' + duration textContent: durationLabel + ': ' + duration
}); });
info.appendChild(durationElement); info.appendChild(durationElement);
} }
@ -304,7 +316,7 @@
} else if (sessionData.created_at) { } else if (sessionData.created_at) {
return TimeUtils.estimateSessionDuration(sessionData); return TimeUtils.estimateSessionDuration(sessionData);
} }
return '未知'; return window.i18nManager ? window.i18nManager.t('sessionManagement.sessionDetails.unknown') : '未知';
}; };
/** /**
@ -313,9 +325,13 @@
SessionUIRenderer.prototype.createSessionActions = function(sessionData, isHistory) { SessionUIRenderer.prototype.createSessionActions = function(sessionData, isHistory) {
const actions = DOMUtils.createElement('div', { className: 'session-actions' }); const actions = DOMUtils.createElement('div', { className: 'session-actions' });
const buttonText = isHistory ?
(window.i18nManager ? window.i18nManager.t('sessionManagement.viewDetails') : '查看') :
(window.i18nManager ? window.i18nManager.t('sessionManagement.viewDetails') : '詳細資訊');
const button = DOMUtils.createElement('button', { const button = DOMUtils.createElement('button', {
className: 'btn-small', className: 'btn-small',
textContent: isHistory ? '查看' : '詳細資訊' textContent: buttonText
}); });
// 添加點擊事件 // 添加點擊事件

View File

@ -321,8 +321,8 @@
default: default:
icon = '⏳'; icon = '⏳';
title = '等待回饋'; title = window.i18nManager ? window.i18nManager.t('status.waiting.title') : '等待回饋';
message = '請提供您的回饋意見'; message = window.i18nManager ? window.i18nManager.t('status.waiting.message') : '請提供您的回饋意見';
status = 'waiting'; status = 'waiting';
} }
@ -410,7 +410,8 @@
submitButtons.forEach(function(button) { submitButtons.forEach(function(button) {
button.disabled = false; button.disabled = false;
button.textContent = button.getAttribute('data-original-text') || '提交回饋'; const defaultText = window.i18nManager ? window.i18nManager.t('buttons.submit') : '提交回饋';
button.textContent = button.getAttribute('data-original-text') || defaultText;
}); });
console.log('✅ 回饋表單重置完成'); console.log('✅ 回饋表單重置完成');

View File

@ -17,34 +17,79 @@
*/ */
const StatusUtils = { const StatusUtils = {
/** /**
* 會話狀態映射 * 獲取會話狀態文字使用 i18n
*/ */
SESSION_STATUS_MAP: { getSessionStatusText: function(status) {
'waiting': '等待回饋', if (!window.i18nManager) {
'waiting_for_feedback': '等待回饋', // 回退到硬編碼文字
'active': '進行中', const fallbackMap = {
'feedback_submitted': '已提交回饋', 'waiting': '等待回饋',
'completed': '已完成', 'waiting_for_feedback': '等待回饋',
'timeout': '已逾時', 'active': '進行中',
'error': '錯誤', 'feedback_submitted': '已提交回饋',
'expired': '已過期', 'completed': '已完成',
'connecting': '連接中', 'timeout': '已逾時',
'connected': '已連接', 'error': '錯誤',
'disconnected': '已斷開', 'expired': '已過期',
'processing': '處理中', 'connecting': '連接中',
'ready': '就緒', 'connected': '已連接',
'closed': '已關閉' 'disconnected': '已斷開',
'processing': '處理中',
'ready': '就緒',
'closed': '已關閉'
};
return fallbackMap[status] || status;
}
// 使用 i18n 翻譯
const i18nKeyMap = {
'waiting': 'connectionMonitor.waiting',
'waiting_for_feedback': 'connectionMonitor.waiting',
'active': 'status.processing.title',
'feedback_submitted': 'status.submitted.title',
'completed': 'status.submitted.title',
'timeout': 'session.timeout',
'error': 'status.error',
'expired': 'session.timeout',
'connecting': 'connectionMonitor.connecting',
'connected': 'connectionMonitor.connected',
'disconnected': 'connectionMonitor.disconnected',
'processing': 'status.processing.title',
'ready': 'connectionMonitor.connected',
'closed': 'connectionMonitor.disconnected'
};
const i18nKey = i18nKeyMap[status];
return i18nKey ? window.i18nManager.t(i18nKey) : status;
}, },
/** /**
* 連線狀態映射 * 獲取連線狀態文字使用 i18n
*/ */
CONNECTION_STATUS_MAP: { getConnectionStatusText: function(status) {
'connecting': '連接中', if (!window.i18nManager) {
'connected': '已連接', // 回退到硬編碼文字
'disconnected': '已斷開', const fallbackMap = {
'reconnecting': '重連中', 'connecting': '連接中',
'error': '連接錯誤' 'connected': '已連接',
'disconnected': '已斷開',
'reconnecting': '重連中',
'error': '連接錯誤'
};
return fallbackMap[status] || status;
}
// 使用 i18n 翻譯
const i18nKeyMap = {
'connecting': 'connectionMonitor.connecting',
'connected': 'connectionMonitor.connected',
'disconnected': 'connectionMonitor.disconnected',
'reconnecting': 'connectionMonitor.reconnecting',
'error': 'status.error'
};
const i18nKey = i18nKeyMap[status];
return i18nKey ? window.i18nManager.t(i18nKey) : status;
}, },
/** /**
@ -69,21 +114,56 @@
}, },
/** /**
* 連線品質等級 * 獲取連線品質標籤使用 i18n
*/ */
CONNECTION_QUALITY_LEVELS: { getConnectionQualityLabel: function(level) {
'excellent': { threshold: 50, label: '優秀', color: '#4caf50' }, if (!window.i18nManager) {
'good': { threshold: 100, label: '良好', color: '#8bc34a' }, // 回退到硬編碼文字
'fair': { threshold: 200, label: '一般', color: '#ff9800' }, const fallbackLabels = {
'poor': { threshold: Infinity, label: '較差', color: '#f44336' } 'excellent': '優秀',
'good': '良好',
'fair': '一般',
'poor': '較差',
'unknown': '未知'
};
return fallbackLabels[level] || level;
}
const i18nKey = `connectionMonitor.quality.${level}`;
return window.i18nManager.t(i18nKey);
}, },
/** /**
* 獲取狀態文字 * 連線品質等級
*/
CONNECTION_QUALITY_LEVELS: {
'excellent': { threshold: 50, color: '#4caf50' },
'good': { threshold: 100, color: '#8bc34a' },
'fair': { threshold: 200, color: '#ff9800' },
'poor': { threshold: Infinity, color: '#f44336' }
},
/**
* 獲取狀態文字統一入口優先使用新方法
*/ */
getStatusText: function(status) { getStatusText: function(status) {
if (!status) return '未知'; if (!status) {
return this.SESSION_STATUS_MAP[status] || this.CONNECTION_STATUS_MAP[status] || status; return window.i18nManager ? window.i18nManager.t('sessionManagement.sessionDetails.unknown') : '未知';
}
// 優先嘗試會話狀態
const sessionText = this.getSessionStatusText(status);
if (sessionText !== status) {
return sessionText;
}
// 然後嘗試連線狀態
const connectionText = this.getConnectionStatusText(status);
if (connectionText !== status) {
return connectionText;
}
return status;
}, },
/** /**
@ -99,20 +179,28 @@
*/ */
calculateConnectionQuality: function(latency) { calculateConnectionQuality: function(latency) {
if (typeof latency !== 'number' || latency < 0) { if (typeof latency !== 'number' || latency < 0) {
return { level: 'unknown', label: '未知', color: '#757575' }; return {
level: 'unknown',
label: this.getConnectionQualityLabel('unknown'),
color: '#757575'
};
} }
for (const [level, config] of Object.entries(this.CONNECTION_QUALITY_LEVELS)) { for (const [level, config] of Object.entries(this.CONNECTION_QUALITY_LEVELS)) {
if (latency < config.threshold) { if (latency < config.threshold) {
return { return {
level: level, level: level,
label: config.label, label: this.getConnectionQualityLabel(level),
color: config.color color: config.color
}; };
} }
} }
return { level: 'poor', label: '較差', color: '#f44336' }; return {
level: 'poor',
label: this.getConnectionQualityLabel('poor'),
color: '#f44336'
};
}, },
/** /**

View File

@ -60,7 +60,8 @@
const wsUrl = protocol + '//' + host + '/ws'; const wsUrl = protocol + '//' + host + '/ws';
console.log('嘗試連接 WebSocket:', wsUrl); console.log('嘗試連接 WebSocket:', wsUrl);
this.updateConnectionStatus('connecting', '連接中...'); const connectingMessage = window.i18nManager ? window.i18nManager.t('connectionMonitor.connecting') : '連接中...';
this.updateConnectionStatus('connecting', connectingMessage);
try { try {
// 如果已有連接,先關閉 // 如果已有連接,先關閉
@ -74,7 +75,8 @@
} catch (error) { } catch (error) {
console.error('WebSocket 連接失敗:', error); console.error('WebSocket 連接失敗:', error);
this.updateConnectionStatus('error', '連接失敗'); const connectionFailedMessage = window.i18nManager ? window.i18nManager.t('connectionMonitor.connectionFailed') : '連接失敗';
this.updateConnectionStatus('error', connectionFailedMessage);
} }
}; };
@ -107,7 +109,8 @@
WebSocketManager.prototype.handleOpen = function() { WebSocketManager.prototype.handleOpen = function() {
this.isConnected = true; this.isConnected = true;
this.connectionReady = false; // 等待連接確認 this.connectionReady = false; // 等待連接確認
this.updateConnectionStatus('connected', '已連接'); const connectedMessage = window.i18nManager ? window.i18nManager.t('connectionMonitor.connected') : '已連接';
this.updateConnectionStatus('connected', connectedMessage);
console.log('WebSocket 連接已建立'); console.log('WebSocket 連接已建立');
// 重置重連計數器和延遲 // 重置重連計數器和延遲
@ -173,9 +176,11 @@
// 處理不同的關閉原因 // 處理不同的關閉原因
if (event.code === 4004) { if (event.code === 4004) {
this.updateConnectionStatus('disconnected', '沒有活躍會話'); const noActiveSessionMessage = window.i18nManager ? window.i18nManager.t('connectionMonitor.noActiveSession') : '沒有活躍會話';
this.updateConnectionStatus('disconnected', noActiveSessionMessage);
} else { } else {
this.updateConnectionStatus('disconnected', '已斷開'); const disconnectedMessage = window.i18nManager ? window.i18nManager.t('connectionMonitor.disconnected') : '已斷開';
this.updateConnectionStatus('disconnected', disconnectedMessage);
this.handleReconnection(event); this.handleReconnection(event);
} }
@ -190,8 +195,9 @@
*/ */
WebSocketManager.prototype.handleError = function(error) { WebSocketManager.prototype.handleError = function(error) {
console.error('WebSocket 錯誤:', error); console.error('WebSocket 錯誤:', error);
this.updateConnectionStatus('error', '連接錯誤'); const connectionErrorMessage = window.i18nManager ? window.i18nManager.t('connectionMonitor.connectionError') : '連接錯誤';
this.updateConnectionStatus('error', connectionErrorMessage);
// 調用外部回調 // 調用外部回調
if (this.onError) { if (this.onError) {
this.onError(error); this.onError(error);
@ -218,7 +224,9 @@
console.log(this.reconnectDelay / 1000 + '秒後嘗試重連... (第' + this.reconnectAttempts + '次)'); console.log(this.reconnectDelay / 1000 + '秒後嘗試重連... (第' + this.reconnectAttempts + '次)');
// 更新狀態為重連中 // 更新狀態為重連中
this.updateConnectionStatus('reconnecting', '重連中... (第' + this.reconnectAttempts + '次)'); const reconnectingTemplate = window.i18nManager ? window.i18nManager.t('connectionMonitor.reconnecting') : '重連中... (第{attempt}次)';
const reconnectingMessage = reconnectingTemplate.replace('{attempt}', this.reconnectAttempts);
this.updateConnectionStatus('reconnecting', reconnectingMessage);
const self = this; const self = this;
setTimeout(function() { setTimeout(function() {
@ -227,7 +235,8 @@
}, this.reconnectDelay); }, this.reconnectDelay);
} else if (this.reconnectAttempts >= this.maxReconnectAttempts) { } else if (this.reconnectAttempts >= this.maxReconnectAttempts) {
console.log('❌ 達到最大重連次數,停止重連'); console.log('❌ 達到最大重連次數,停止重連');
Utils.showMessage('WebSocket 連接失敗,請刷新頁面重試', Utils.CONSTANTS.MESSAGE_ERROR); const maxReconnectMessage = window.i18nManager ? window.i18nManager.t('connectionMonitor.maxReconnectReached') : 'WebSocket 連接失敗,請刷新頁面重試';
Utils.showMessage(maxReconnectMessage, Utils.CONSTANTS.MESSAGE_ERROR);
} }
}; };

View File

@ -385,9 +385,9 @@
<!-- 主要連線狀態 --> <!-- 主要連線狀態 -->
<div class="connection-indicator connecting" id="mainConnectionStatus"> <div class="connection-indicator connecting" id="mainConnectionStatus">
<div class="status-icon pulse"></div> <div class="status-icon pulse"></div>
<span class="status-text">連接中...</span> <span class="status-text" data-i18n="connectionMonitor.connecting">連接中...</span>
<div class="connection-quality"> <div class="connection-quality">
<div class="latency-indicator">延遲: --ms</div> <div class="latency-indicator"><span data-i18n="connectionMonitor.latency">延遲</span>: --ms</div>
<div class="signal-strength"> <div class="signal-strength">
<div class="signal-bar"></div> <div class="signal-bar"></div>
<div class="signal-bar"></div> <div class="signal-bar"></div>
@ -398,19 +398,19 @@
<!-- 連線詳細資訊 --> <!-- 連線詳細資訊 -->
<div class="connection-details"> <div class="connection-details">
<span class="connection-time">連線時間: --:--</span> <span class="connection-time"><span data-i18n="connectionMonitor.connectionTime">連線時間</span>: --:--</span>
<span class="reconnect-count">重連: 0 次</span> <span class="reconnect-count"><span data-i18n="connectionMonitor.reconnectCount">重連</span>: 0 <span data-i18n="connectionMonitor.times"></span></span>
</div> </div>
<!-- 詳細狀態資訊 --> <!-- 詳細狀態資訊 -->
<div class="detailed-status-info"> <div class="detailed-status-info">
<div class="websocket-metrics"> <div class="websocket-metrics">
<span class="metric">訊息: <span id="messageCount">0</span></span> <span class="metric"><span data-i18n="connectionMonitor.metrics.messages">訊息</span>: <span id="messageCount">0</span></span>
<span class="metric">延遲: <span id="latencyDisplay">--ms</span></span> <span class="metric"><span data-i18n="connectionMonitor.metrics.latencyMs">延遲</span>: <span id="latencyDisplay">--ms</span></span>
</div> </div>
<div class="session-metrics"> <div class="session-metrics">
<span class="metric">會話: <span id="sessionCount">1</span></span> <span class="metric"><span data-i18n="connectionMonitor.metrics.sessions">會話</span>: <span id="sessionCount">1</span></span>
<span class="metric">狀態: <span id="sessionStatusText">等待中</span></span> <span class="metric"><span data-i18n="connectionMonitor.statusText">狀態</span>: <span id="sessionStatusText" data-i18n="connectionMonitor.waiting">等待中</span></span>
</div> </div>
</div> </div>
</div> </div>
@ -430,9 +430,9 @@
<div class="session-management-panel" id="sessionPanel"> <div class="session-management-panel" id="sessionPanel">
<!-- 面板標題 --> <!-- 面板標題 -->
<div class="panel-header"> <div class="panel-header">
<h3>會話管理</h3> <h3 data-i18n="sessionManagement.title">會話管理</h3>
<div class="panel-controls"> <div class="panel-controls">
<button class="btn-icon" id="refreshSessions" title="重新整理"> <button class="btn-icon" id="refreshSessions" data-i18n-title="sessionManagement.refresh" title="重新整理">
🔄 🔄
</button> </button>
</div> </div>
@ -441,44 +441,44 @@
<div class="panel-content"> <div class="panel-content">
<!-- 當前活躍會話 --> <!-- 當前活躍會話 -->
<div class="current-session-section"> <div class="current-session-section">
<h4>當前會話</h4> <h4 data-i18n="sessionManagement.currentSession">當前會話</h4>
<div class="session-card active" id="currentSessionCard"> <div class="session-card active" id="currentSessionCard">
<div class="session-header"> <div class="session-header">
<div class="session-id">會話 ID: {{ session_id[:8] if session_id else 'loading' }}...</div> <div class="session-id"><span data-i18n="sessionManagement.sessionId">會話 ID</span>: {{ session_id[:8] if session_id else 'loading' }}...</div>
<div class="session-status"> <div class="session-status">
<span class="status-badge waiting">等待中</span> <span class="status-badge waiting" data-i18n="connectionMonitor.waiting">等待中</span>
</div> </div>
</div> </div>
<div class="session-info"> <div class="session-info">
<div class="session-time">建立時間: --:--:--</div> <div class="session-time"><span data-i18n="sessionManagement.createdTime">建立時間</span>: --:--:--</div>
<div class="session-project">專案: {{ project_directory }}</div> <div class="session-project"><span data-i18n="sessionManagement.project">專案</span>: {{ project_directory }}</div>
<div class="session-summary">AI 摘要: 載入中...</div> <div class="session-summary"><span data-i18n="sessionManagement.aiSummary">AI 摘要</span>: <span data-i18n="sessionManagement.loading">載入中...</span></div>
</div> </div>
<div class="session-actions"> <div class="session-actions">
<button class="btn-small" id="viewSessionDetails">詳細資訊</button> <button class="btn-small" id="viewSessionDetails" data-i18n="sessionManagement.viewDetails">詳細資訊</button>
</div> </div>
</div> </div>
</div> </div>
<!-- 會話歷史記錄 --> <!-- 會話歷史記錄 -->
<div class="session-history-section"> <div class="session-history-section">
<h4>會話歷史</h4> <h4 data-i18n="sessionManagement.sessionHistory">會話歷史</h4>
<div class="session-list" id="sessionHistoryList"> <div class="session-list" id="sessionHistoryList">
<div class="no-sessions">暫無歷史會話</div> <div class="no-sessions" data-i18n="sessionManagement.noHistory">暫無歷史會話</div>
</div> </div>
</div> </div>
<!-- 會話統計 --> <!-- 會話統計 -->
<div class="session-stats-section"> <div class="session-stats-section">
<h4>統計資訊</h4> <h4 data-i18n="sessionManagement.statistics">統計資訊</h4>
<div class="stats-grid"> <div class="stats-grid">
<div class="stat-item"> <div class="stat-item">
<div class="stat-value">0</div> <div class="stat-value">0</div>
<div class="stat-label">今日會話</div> <div class="stat-label" data-i18n="sessionManagement.todaySessions">今日會話</div>
</div> </div>
<div class="stat-item"> <div class="stat-item">
<div class="stat-value">--</div> <div class="stat-value">--</div>
<div class="stat-label">平均時長</div> <div class="stat-label" data-i18n="sessionManagement.averageDuration">平均時長</div>
</div> </div>
</div> </div>
</div> </div>
@ -486,7 +486,7 @@
<!-- 邊緣收合/展開按鈕 --> <!-- 邊緣收合/展開按鈕 -->
<div class="panel-edge-toggle" id="panelEdgeToggle"> <div class="panel-edge-toggle" id="panelEdgeToggle">
<button class="edge-toggle-btn" id="edgeToggleBtn" title="收合面板"> <button class="edge-toggle-btn" id="edgeToggleBtn" data-i18n-title="sessionManagement.collapsePanel" title="收合面板">
<span class="toggle-icon"></span> <span class="toggle-icon"></span>
</button> </button>
</div> </div>
@ -494,9 +494,9 @@
<!-- 收合狀態下的展開按鈕 --> <!-- 收合狀態下的展開按鈕 -->
<div class="collapsed-panel-toggle" id="collapsedPanelToggle" style="display: none;"> <div class="collapsed-panel-toggle" id="collapsedPanelToggle" style="display: none;">
<button class="collapsed-toggle-btn" id="collapsedToggleBtn" title="展開會話面板"> <button class="collapsed-toggle-btn" id="collapsedToggleBtn" data-i18n-title="sessionManagement.expandPanel" title="展開會話面板">
<span class="toggle-icon"></span> <span class="toggle-icon"></span>
<span class="toggle-text">會話</span> <span class="toggle-text" data-i18n="sessionManagement.sessionPanel">會話</span>
</button> </button>
</div> </div>
@ -506,12 +506,12 @@
<div class="session-status-bar" style="display: flex; justify-content: space-between; align-items: center; padding: 8px 16px; background: var(--bg-secondary); border-bottom: 1px solid var(--border-color); margin-bottom: 16px; border-radius: 6px;"> <div class="session-status-bar" style="display: flex; justify-content: space-between; align-items: center; padding: 8px 16px; background: var(--bg-secondary); border-bottom: 1px solid var(--border-color); margin-bottom: 16px; border-radius: 6px;">
<div class="current-session-info"> <div class="current-session-info">
<span class="session-indicator" style="display: flex; align-items: center; gap: 8px; font-size: 12px; color: var(--text-secondary);"> <span class="session-indicator" style="display: flex; align-items: center; gap: 8px; font-size: 12px; color: var(--text-secondary);">
📋 當前會話: <span id="currentSessionId" style="font-family: monospace; color: var(--accent-color);">{{ session_id[:8] if session_id else 'loading' }}...</span> 📋 <span data-i18n="sessionManagement.currentSession">當前會話</span>: <span id="currentSessionId" style="font-family: monospace; color: var(--accent-color);">{{ session_id[:8] if session_id else 'loading' }}...</span>
</span> </span>
<span class="session-age" style="margin-left: 16px; font-size: 12px; color: var(--text-secondary);">活躍時間: <span id="sessionAge">--</span></span> <span class="session-age" style="margin-left: 16px; font-size: 12px; color: var(--text-secondary);"><span data-i18n="sessionManagement.activeTime">活躍時間</span>: <span id="sessionAge">--</span></span>
</div> </div>
<div class="session-controls"> <div class="session-controls">
<button class="btn-link" id="switchSessionBtn" style="display: none; font-size: 12px; color: var(--accent-color); background: none; border: none; cursor: pointer;"> <button class="btn-link" id="switchSessionBtn" style="display: none; font-size: 12px; color: var(--accent-color); background: none; border: none; cursor: pointer;" data-i18n="sessionManagement.switchSession">
切換會話 切換會話
</button> </button>
</div> </div>