From 82a7473f8591a928652dc6a0d047cf8c2061f90e Mon Sep 17 00:00:00 2001 From: Minidoracat Date: Fri, 13 Jun 2025 10:33:24 +0800 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20=E8=A3=9C=E5=85=85=E5=A4=9A?= =?UTF-8?q?=E8=AA=9E=E7=B3=BB=E6=96=87=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../web/locales/en/translation.json | 82 ++++++++- .../web/locales/zh-CN/translation.json | 82 ++++++++- .../web/locales/zh-TW/translation.json | 82 ++++++++- .../web/static/js/app.js | 45 +++-- .../web/static/js/i18n.js | 52 ++++++ .../static/js/modules/connection-monitor.js | 27 +-- .../modules/session/session-details-modal.js | 28 ++-- .../js/modules/session/session-ui-renderer.js | 48 ++++-- .../web/static/js/modules/ui-manager.js | 7 +- .../static/js/modules/utils/status-utils.js | 158 ++++++++++++++---- .../static/js/modules/websocket-manager.js | 27 ++- .../web/templates/feedback.html | 56 +++---- 12 files changed, 558 insertions(+), 136 deletions(-) diff --git a/src/mcp_feedback_enhanced/web/locales/en/translation.json b/src/mcp_feedback_enhanced/web/locales/en/translation.json index 6e8ebcc..5cd7bbd 100644 --- a/src/mcp_feedback_enhanced/web/locales/en/translation.json +++ b/src/mcp_feedback_enhanced/web/locales/en/translation.json @@ -2,7 +2,8 @@ "app": { "title": "MCP Interactive Feedback System", "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": { "feedback": "💬 Feedback", @@ -32,7 +33,15 @@ "submit": "Ctrl+Enter to submit (Cmd+Enter on Mac, numpad supported)", "clear": "Ctrl+Delete to clear (Cmd+Delete 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": { "title": "📋 AI Work Summary", @@ -55,7 +64,11 @@ "running": "Running...", "completed": "Completed", "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": { "title": "⚡ Command Execution", @@ -179,6 +192,69 @@ "detected": "Detected", "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": { "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!", diff --git a/src/mcp_feedback_enhanced/web/locales/zh-CN/translation.json b/src/mcp_feedback_enhanced/web/locales/zh-CN/translation.json index 15e5730..a678806 100644 --- a/src/mcp_feedback_enhanced/web/locales/zh-CN/translation.json +++ b/src/mcp_feedback_enhanced/web/locales/zh-CN/translation.json @@ -2,7 +2,8 @@ "app": { "title": "MCP 交互反馈系统", "subtitle": "AI 助手交互反馈平台", - "projectDirectory": "项目目录" + "projectDirectory": "项目目录", + "updateFailed": "更新内容失败,请手动刷新页面以查看新的 AI 工作摘要" }, "tabs": { "feedback": "💬 反馈", @@ -32,7 +33,15 @@ "submit": "Ctrl+Enter 提交 (Mac 用 Cmd+Enter,支持数字键盘)", "clear": "Ctrl+Delete 清除 (Mac 用 Cmd+Delete)", "paste": "Ctrl+V 粘贴图片 (Mac 用 Cmd+V)" - } + }, + "submitSuccess": "反馈提交成功!", + "submittedWaiting": "已送出反馈,等待下次 MCP 调用...", + "waitingForUser": "等待用户反馈...", + "alreadySubmitted": "反馈已提交,请等待下次 MCP 调用", + "processingFeedback": "正在处理中,请稍候", + "connectingMessage": "WebSocket 连接中,反馈将在连接就绪后自动提交...", + "invalidState": "当前状态不允许提交", + "sendFailed": "发送失败,请重试" }, "summary": { "title": "📋 AI 工作摘要", @@ -55,7 +64,11 @@ "running": "执行中...", "completed": "执行完成", "error": "执行错误", - "history": "命令历史" + "history": "命令历史", + "notConnected": "WebSocket 未连接,无法执行命令", + "emptyCommand": "请输入命令", + "sendFailed": "发送命令失败", + "executing": "正在执行..." }, "command": { "title": "⚡ 命令执行", @@ -179,6 +192,69 @@ "detected": "已检测", "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": { "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请测试这些功能并提供反馈!", diff --git a/src/mcp_feedback_enhanced/web/locales/zh-TW/translation.json b/src/mcp_feedback_enhanced/web/locales/zh-TW/translation.json index 59309fa..3ec98dc 100644 --- a/src/mcp_feedback_enhanced/web/locales/zh-TW/translation.json +++ b/src/mcp_feedback_enhanced/web/locales/zh-TW/translation.json @@ -7,7 +7,8 @@ "author": "作者:Fábio Ferreira (原作者) / Minidoracat (增強版)", "authorLink": "GitHub: Minidoracat", "credits": "⭐ 如果這個專案對您有幫助,請在 GitHub 上給我們一個星星!\n\n本增強版本由 Minidoracat 開發和維護,大幅擴展了專案功能,新增了 Web UI 介面、圖片支援、多語言能力以及許多其他改進功能。\n\n同時感謝 sanshao85 的 mcp-feedback-collector 專案提供的 UI 設計靈感。\n\n開源協作讓技術變得更美好!", - "projectDirectory": "專案目錄" + "projectDirectory": "專案目錄", + "updateFailed": "更新內容失敗,請手動刷新頁面以查看新的 AI 工作摘要" }, "tabs": { "feedback": "💬 回饋", @@ -37,7 +38,15 @@ "submit": "Ctrl+Enter 提交 (Mac 用 Cmd+Enter,支援數字鍵盤)", "clear": "Ctrl+Delete 清除 (Mac 用 Cmd+Delete)", "paste": "Ctrl+V 貼上圖片 (Mac 用 Cmd+V)" - } + }, + "submitSuccess": "回饋提交成功!", + "submittedWaiting": "已送出反饋,等待下次 MCP 調用...", + "waitingForUser": "等待用戶回饋...", + "alreadySubmitted": "回饋已提交,請等待下次 MCP 調用", + "processingFeedback": "正在處理中,請稍候", + "connectingMessage": "WebSocket 連接中,回饋將在連接就緒後自動提交...", + "invalidState": "當前狀態不允許提交", + "sendFailed": "發送失敗,請重試" }, "summary": { "title": "📋 AI 工作摘要", @@ -60,7 +69,11 @@ "running": "執行中...", "completed": "執行完成", "error": "執行錯誤", - "history": "命令歷史" + "history": "命令歷史", + "notConnected": "WebSocket 未連接,無法執行命令", + "emptyCommand": "請輸入命令", + "sendFailed": "發送命令失敗", + "executing": "正在執行..." }, "command": { "title": "⚡ 命令執行", @@ -184,6 +197,69 @@ "detected": "已檢測", "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": { "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請測試這些功能並提供回饋!", diff --git a/src/mcp_feedback_enhanced/web/static/js/app.js b/src/mcp_feedback_enhanced/web/static/js/app.js index e13c2d0..af6a8b7 100644 --- a/src/mcp_feedback_enhanced/web/static/js/app.js +++ b/src/mcp_feedback_enhanced/web/static/js/app.js @@ -434,10 +434,12 @@ 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 摘要區域顯示「已送出反饋」狀態 - this.updateSummaryStatus('已送出反饋,等待下次 MCP 調用...'); + const submittedMessage = window.i18nManager ? window.i18nManager.t('feedback.submittedWaiting') : '已送出反饋,等待下次 MCP 調用...'; + this.updateSummaryStatus(submittedMessage); console.log('反饋已提交,頁面保持開啟狀態'); }; @@ -562,7 +564,8 @@ switch (statusInfo.status) { case 'feedback_submitted': 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; case 'active': @@ -575,7 +578,8 @@ } if (statusInfo.status === 'waiting') { - this.updateSummaryStatus('等待用戶回饋...'); + const waitingMessage = window.i18nManager ? window.i18nManager.t('feedback.waitingForUser') : '等待用戶回饋...'; + this.updateSummaryStatus(waitingMessage); } break; } @@ -620,18 +624,22 @@ const feedbackState = this.uiManager ? this.uiManager.getFeedbackState() : null; 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) { - 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()) { // 收集回饋數據,等待連接就緒後提交 const feedbackData = this.collectFeedbackData(); if (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 { - 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) { 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) { @@ -742,12 +751,14 @@ const command = commandInput ? commandInput.value.trim() : ''; if (!command) { - this.appendCommandOutput('⚠️ 請輸入命令\n'); + const emptyCommandMessage = window.i18nManager ? window.i18nManager.t('commands.emptyCommand') : '請輸入命令'; + this.appendCommandOutput('⚠️ ' + emptyCommandMessage + '\n'); return; } 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; } @@ -764,13 +775,16 @@ if (success) { // 清空輸入框 commandInput.value = ''; - this.appendCommandOutput('[正在執行...]\n'); + const executingMessage = window.i18nManager ? window.i18nManager.t('commands.executing') : '正在執行...'; + this.appendCommandOutput('[' + executingMessage + ']\n'); } else { - this.appendCommandOutput('❌ 發送命令失敗\n'); + const sendFailedMessage = window.i18nManager ? window.i18nManager.t('commands.sendFailed') : '發送命令失敗'; + this.appendCommandOutput('❌ ' + sendFailedMessage + '\n'); } } 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) { 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); }); }; diff --git a/src/mcp_feedback_enhanced/web/static/js/i18n.js b/src/mcp_feedback_enhanced/web/static/js/i18n.js index 592eaf3..35b573f 100644 --- a/src/mcp_feedback_enhanced/web/static/js/i18n.js +++ b/src/mcp_feedback_enhanced/web/static/js/i18n.js @@ -171,6 +171,12 @@ class I18nManager { // 只更新終端歡迎信息,不要覆蓋 AI 摘要 this.updateTerminalWelcome(); + // 更新會話管理相關的動態內容 + this.updateSessionManagementContent(); + + // 更新連線監控相關的動態內容 + this.updateConnectionMonitorContent(); + // 更新應用程式中的動態狀態文字(使用新的模組化架構) if (window.feedbackApp && window.feedbackApp.isInitialized) { // 更新 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() { // 舊版下拉選擇器(兼容性保留) const selector = document.getElementById('settingsLanguageSelect'); diff --git a/src/mcp_feedback_enhanced/web/static/js/modules/connection-monitor.js b/src/mcp_feedback_enhanced/web/static/js/modules/connection-monitor.js index f3f6f7f..92eed5b 100644 --- a/src/mcp_feedback_enhanced/web/static/js/modules/connection-monitor.js +++ b/src/mcp_feedback_enhanced/web/static/js/modules/connection-monitor.js @@ -101,16 +101,19 @@ */ ConnectionMonitor.prototype.updateConnectionStatus = function(status, message) { console.log('🔍 連線狀態更新:', status, message); - + // 更新狀態顯示 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) { this.statusIcon.className = 'status-icon'; - + switch (status) { case 'connecting': case 'reconnecting': @@ -123,7 +126,7 @@ this.statusIcon.classList.remove('pulse'); } } - + // 更新連線指示器樣式 const indicator = Utils.safeQuerySelector('.connection-indicator'); if (indicator) { @@ -263,10 +266,11 @@ ConnectionMonitor.prototype.updateDisplay = function() { // 更新延遲顯示 if (this.latencyDisplay) { + const latencyLabel = window.i18nManager ? window.i18nManager.t('connectionMonitor.latency') : '延遲'; if (this.currentLatency > 0) { - this.latencyDisplay.textContent = '延遲: ' + this.currentLatency + 'ms'; + this.latencyDisplay.textContent = latencyLabel + ': ' + this.currentLatency + 'ms'; } else { - this.latencyDisplay.textContent = '延遲: --ms'; + this.latencyDisplay.textContent = latencyLabel + ': --ms'; } } @@ -283,14 +287,17 @@ const duration = Math.floor((Date.now() - this.connectionStartTime) / 1000); const minutes = Math.floor(duration / 60); const seconds = duration % 60; - this.connectionTimeDisplay.textContent = '連線時間: ' + - String(minutes).padStart(2, '0') + ':' + + const connectionTimeLabel = window.i18nManager ? window.i18nManager.t('connectionMonitor.connectionTime') : '連線時間'; + this.connectionTimeDisplay.textContent = connectionTimeLabel + ': ' + + String(minutes).padStart(2, '0') + ':' + String(seconds).padStart(2, '0'); } // 更新重連次數 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; } // 更新訊息計數 diff --git a/src/mcp_feedback_enhanced/web/static/js/modules/session/session-details-modal.js b/src/mcp_feedback_enhanced/web/static/js/modules/session/session-details-modal.js index 9f06159..48690aa 100644 --- a/src/mcp_feedback_enhanced/web/static/js/modules/session/session-details-modal.js +++ b/src/mcp_feedback_enhanced/web/static/js/modules/session/session-details-modal.js @@ -96,8 +96,8 @@ statusColor: statusColor, createdTime: createdTime, duration: duration, - projectDirectory: sessionData.project_directory || '未知', - summary: sessionData.summary || '暫無摘要' + projectDirectory: sessionData.project_directory || (window.i18nManager ? window.i18nManager.t('sessionManagement.sessionDetails.unknown') : '未知'), + summary: sessionData.summary || (window.i18nManager ? window.i18nManager.t('sessionManagement.sessionDetails.noSummary') : '暫無摘要') }; }; @@ -125,42 +125,48 @@ * 創建彈窗 HTML */ 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 `
diff --git a/src/mcp_feedback_enhanced/web/static/js/modules/session/session-ui-renderer.js b/src/mcp_feedback_enhanced/web/static/js/modules/session/session-ui-renderer.js index 643c342..3fd4ce9 100644 --- a/src/mcp_feedback_enhanced/web/static/js/modules/session/session-ui-renderer.js +++ b/src/mcp_feedback_enhanced/web/static/js/modules/session/session-ui-renderer.js @@ -102,10 +102,11 @@ SessionUIRenderer.prototype.updateSessionId = function(sessionData) { const sessionIdElement = this.currentSessionCard.querySelector('.session-id'); if (sessionIdElement && sessionData.session_id) { - const displayId = this.showFullSessionId ? - sessionData.session_id : + const displayId = this.showFullSessionId ? + sessionData.session_id : 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'); if (timeElement && sessionData.created_at) { 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'); if (projectElement) { 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) { const summaryElement = this.currentSessionCard.querySelector('.session-summary'); if (summaryElement) { - const summary = sessionData.summary || '無摘要'; - DOMUtils.safeSetTextContent(summaryElement, 'AI 摘要: ' + summary); + const noSummaryText = window.i18nManager ? window.i18nManager.t('sessionManagement.noSummary') : '無摘要'; + 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() { + const noHistoryText = window.i18nManager ? window.i18nManager.t('sessionManagement.noHistory') : '暫無歷史會話'; const emptyElement = DOMUtils.createElement('div', { className: 'no-sessions', - textContent: '暫無歷史會話' + textContent: noHistoryText }); this.historyList.appendChild(emptyElement); }; @@ -242,9 +248,10 @@ const header = DOMUtils.createElement('div', { className: 'session-header' }); // 會話 ID + const sessionIdLabel = window.i18nManager ? window.i18nManager.t('sessionManagement.sessionId') : '會話 ID'; const sessionId = DOMUtils.createElement('div', { 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 timeText = sessionData.created_at ? - TimeUtils.formatTimestamp(sessionData.created_at, { format: 'time' }) : + const timeText = sessionData.created_at ? + 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', { className: 'session-time', - textContent: (isHistory ? '完成時間' : '建立時間') + ': ' + timeText + textContent: timeLabel + ': ' + timeText }); info.appendChild(timeElement); @@ -282,9 +293,10 @@ // 歷史會話顯示持續時間 if (isHistory) { const duration = this.calculateDisplayDuration(sessionData); + const durationLabel = window.i18nManager ? window.i18nManager.t('sessionManagement.sessionDetails.duration') : '持續時間'; const durationElement = DOMUtils.createElement('div', { className: 'session-duration', - textContent: '持續時間: ' + duration + textContent: durationLabel + ': ' + duration }); info.appendChild(durationElement); } @@ -304,7 +316,7 @@ } else if (sessionData.created_at) { return TimeUtils.estimateSessionDuration(sessionData); } - return '未知'; + return window.i18nManager ? window.i18nManager.t('sessionManagement.sessionDetails.unknown') : '未知'; }; /** @@ -313,9 +325,13 @@ SessionUIRenderer.prototype.createSessionActions = function(sessionData, isHistory) { 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', { className: 'btn-small', - textContent: isHistory ? '查看' : '詳細資訊' + textContent: buttonText }); // 添加點擊事件 diff --git a/src/mcp_feedback_enhanced/web/static/js/modules/ui-manager.js b/src/mcp_feedback_enhanced/web/static/js/modules/ui-manager.js index c6851a1..e929185 100644 --- a/src/mcp_feedback_enhanced/web/static/js/modules/ui-manager.js +++ b/src/mcp_feedback_enhanced/web/static/js/modules/ui-manager.js @@ -321,8 +321,8 @@ default: icon = '⏳'; - title = '等待回饋'; - message = '請提供您的回饋意見'; + title = window.i18nManager ? window.i18nManager.t('status.waiting.title') : '等待回饋'; + message = window.i18nManager ? window.i18nManager.t('status.waiting.message') : '請提供您的回饋意見'; status = 'waiting'; } @@ -410,7 +410,8 @@ submitButtons.forEach(function(button) { 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('✅ 回饋表單重置完成'); diff --git a/src/mcp_feedback_enhanced/web/static/js/modules/utils/status-utils.js b/src/mcp_feedback_enhanced/web/static/js/modules/utils/status-utils.js index ff99ed9..e107d66 100644 --- a/src/mcp_feedback_enhanced/web/static/js/modules/utils/status-utils.js +++ b/src/mcp_feedback_enhanced/web/static/js/modules/utils/status-utils.js @@ -17,34 +17,79 @@ */ const StatusUtils = { /** - * 會話狀態映射 + * 獲取會話狀態文字(使用 i18n) */ - SESSION_STATUS_MAP: { - 'waiting': '等待回饋', - 'waiting_for_feedback': '等待回饋', - 'active': '進行中', - 'feedback_submitted': '已提交回饋', - 'completed': '已完成', - 'timeout': '已逾時', - 'error': '錯誤', - 'expired': '已過期', - 'connecting': '連接中', - 'connected': '已連接', - 'disconnected': '已斷開', - 'processing': '處理中', - 'ready': '就緒', - 'closed': '已關閉' + getSessionStatusText: function(status) { + if (!window.i18nManager) { + // 回退到硬編碼文字 + const fallbackMap = { + 'waiting': '等待回饋', + 'waiting_for_feedback': '等待回饋', + 'active': '進行中', + 'feedback_submitted': '已提交回饋', + 'completed': '已完成', + 'timeout': '已逾時', + 'error': '錯誤', + 'expired': '已過期', + 'connecting': '連接中', + 'connected': '已連接', + '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: { - 'connecting': '連接中', - 'connected': '已連接', - 'disconnected': '已斷開', - 'reconnecting': '重連中', - 'error': '連接錯誤' + getConnectionStatusText: function(status) { + if (!window.i18nManager) { + // 回退到硬編碼文字 + const fallbackMap = { + 'connecting': '連接中', + '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: { - 'excellent': { threshold: 50, label: '優秀', color: '#4caf50' }, - 'good': { threshold: 100, label: '良好', color: '#8bc34a' }, - 'fair': { threshold: 200, label: '一般', color: '#ff9800' }, - 'poor': { threshold: Infinity, label: '較差', color: '#f44336' } + getConnectionQualityLabel: function(level) { + if (!window.i18nManager) { + // 回退到硬編碼文字 + const fallbackLabels = { + '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) { - if (!status) return '未知'; - return this.SESSION_STATUS_MAP[status] || this.CONNECTION_STATUS_MAP[status] || status; + if (!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) { 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)) { if (latency < config.threshold) { return { level: level, - label: config.label, + label: this.getConnectionQualityLabel(level), color: config.color }; } } - return { level: 'poor', label: '較差', color: '#f44336' }; + return { + level: 'poor', + label: this.getConnectionQualityLabel('poor'), + color: '#f44336' + }; }, /** diff --git a/src/mcp_feedback_enhanced/web/static/js/modules/websocket-manager.js b/src/mcp_feedback_enhanced/web/static/js/modules/websocket-manager.js index f2c86cd..e354af0 100644 --- a/src/mcp_feedback_enhanced/web/static/js/modules/websocket-manager.js +++ b/src/mcp_feedback_enhanced/web/static/js/modules/websocket-manager.js @@ -60,7 +60,8 @@ const wsUrl = protocol + '//' + host + '/ws'; console.log('嘗試連接 WebSocket:', wsUrl); - this.updateConnectionStatus('connecting', '連接中...'); + const connectingMessage = window.i18nManager ? window.i18nManager.t('connectionMonitor.connecting') : '連接中...'; + this.updateConnectionStatus('connecting', connectingMessage); try { // 如果已有連接,先關閉 @@ -74,7 +75,8 @@ } catch (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() { this.isConnected = true; this.connectionReady = false; // 等待連接確認 - this.updateConnectionStatus('connected', '已連接'); + const connectedMessage = window.i18nManager ? window.i18nManager.t('connectionMonitor.connected') : '已連接'; + this.updateConnectionStatus('connected', connectedMessage); console.log('WebSocket 連接已建立'); // 重置重連計數器和延遲 @@ -173,9 +176,11 @@ // 處理不同的關閉原因 if (event.code === 4004) { - this.updateConnectionStatus('disconnected', '沒有活躍會話'); + const noActiveSessionMessage = window.i18nManager ? window.i18nManager.t('connectionMonitor.noActiveSession') : '沒有活躍會話'; + this.updateConnectionStatus('disconnected', noActiveSessionMessage); } else { - this.updateConnectionStatus('disconnected', '已斷開'); + const disconnectedMessage = window.i18nManager ? window.i18nManager.t('connectionMonitor.disconnected') : '已斷開'; + this.updateConnectionStatus('disconnected', disconnectedMessage); this.handleReconnection(event); } @@ -190,8 +195,9 @@ */ WebSocketManager.prototype.handleError = function(error) { console.error('WebSocket 錯誤:', error); - this.updateConnectionStatus('error', '連接錯誤'); - + const connectionErrorMessage = window.i18nManager ? window.i18nManager.t('connectionMonitor.connectionError') : '連接錯誤'; + this.updateConnectionStatus('error', connectionErrorMessage); + // 調用外部回調 if (this.onError) { this.onError(error); @@ -218,7 +224,9 @@ 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; setTimeout(function() { @@ -227,7 +235,8 @@ }, this.reconnectDelay); } else if (this.reconnectAttempts >= this.maxReconnectAttempts) { 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); } }; diff --git a/src/mcp_feedback_enhanced/web/templates/feedback.html b/src/mcp_feedback_enhanced/web/templates/feedback.html index 7814e46..aa76f25 100644 --- a/src/mcp_feedback_enhanced/web/templates/feedback.html +++ b/src/mcp_feedback_enhanced/web/templates/feedback.html @@ -385,9 +385,9 @@
- 連接中... + 連接中...
-
延遲: --ms
+
延遲: --ms
@@ -398,19 +398,19 @@
- 連線時間: --:-- - 重連: 0 次 + 連線時間: --:-- + 重連: 0
- 訊息: 0 - 延遲: --ms + 訊息: 0 + 延遲: --ms
- 會話: 1 - 狀態: 等待中 + 會話: 1 + 狀態: 等待中
@@ -430,9 +430,9 @@
-

會話管理

+

會話管理

-
@@ -441,44 +441,44 @@
-

當前會話

+

當前會話

-
會話 ID: {{ session_id[:8] if session_id else 'loading' }}...
+
會話 ID: {{ session_id[:8] if session_id else 'loading' }}...
- 等待中 + 等待中
-
建立時間: --:--:--
-
專案: {{ project_directory }}
-
AI 摘要: 載入中...
+
建立時間: --:--:--
+
專案: {{ project_directory }}
+
AI 摘要: 載入中...
- +
-

會話歷史

+

會話歷史

-
暫無歷史會話
+
暫無歷史會話
-

統計資訊

+

統計資訊

0
-
今日會話
+
今日會話
--
-
平均時長
+
平均時長
@@ -486,7 +486,7 @@
-
@@ -494,9 +494,9 @@ @@ -506,12 +506,12 @@
- 📋 當前會話: {{ session_id[:8] if session_id else 'loading' }}... + 📋 當前會話: {{ session_id[:8] if session_id else 'loading' }}... - 活躍時間: -- + 活躍時間: --
-