diff --git a/crates/tui/locales/en.json b/crates/tui/locales/en.json index dacec1543b..91da337f1f 100644 --- a/crates/tui/locales/en.json +++ b/crates/tui/locales/en.json @@ -13,6 +13,47 @@ "StatusPickerActionNone": "none ", "StatusPickerActionSave": "save ", "StatusPickerActionCancel": "cancel ", + "HotbarSetupTitle": " Hotbar setup ", + "HotbarSetupSourceApp": "app", + "HotbarSetupSourceSlash": "slash", + "HotbarSetupSourceMcp": "mcp", + "HotbarSetupSourceSkill": "skill", + "HotbarSetupSourcePlugin": "plugin", + "HotbarSetupStatusDisabled": "disabled", + "HotbarSetupStatusPrefill": "prefill", + "HotbarSetupStatusReady": "ready", + "HotbarSetupDirtyModified": "modified", + "HotbarSetupDirtyClean": "clean", + "HotbarSetupNoAction": "No action", + "HotbarSetupStatusLine": "slot {slot} | {action} | {dirty}", + "HotbarSetupSlotOutOfRange": "Hotbar slot {slot} is outside 1-{max}", + "HotbarSetupNoActionSelected": "No action selected.", + "HotbarSetupCannotAssign": "{action} cannot be assigned: {reason}", + "HotbarSetupNoActions": "No hotbar actions are available.", + "HotbarSetupRecommended": "rec", + "HotbarSetupEmptySlot": "empty", + "HotbarSetupHelp": "Tab/Shift+Tab source Up/Down action 1-8 slot Enter assign Space toggle Delete clear s save Esc cancel", + "HotbarActionVoiceToggleName": "Voice input", + "HotbarActionVoiceToggleDescription": "Toggle voice capture from the terminal microphone.", + "HotbarActionSessionCompactName": "Compact session", + "HotbarActionSessionCompactDescription": "Compact the current conversation context.", + "HotbarActionModePlanName": "Plan mode", + "HotbarActionModePlanDescription": "Switch the conversation into Plan mode.", + "HotbarActionModeAgentName": "Agent mode", + "HotbarActionModeAgentDescription": "Switch the conversation into Agent mode.", + "HotbarActionModeYoloName": "YOLO mode", + "HotbarActionModeYoloDescription": "Switch the conversation into YOLO mode.", + "HotbarActionReasoningCycleName": "Cycle reasoning", + "HotbarActionReasoningCycleDescription": "Cycle the configured reasoning effort for the active provider.", + "HotbarActionReasoningCycleAutoDisabled": "Reasoning effort is controlled by auto model routing.", + "HotbarActionSidebarToggleName": "Toggle sidebar", + "HotbarActionSidebarToggleDescription": "Show or hide the sidebar.", + "HotbarActionFileTreeToggleName": "Toggle file tree", + "HotbarActionFileTreeToggleDescription": "Show or hide the workspace file tree.", + "HotbarActionPaletteOpenName": "Command palette", + "HotbarActionPaletteOpenDescription": "Open the command palette.", + "HotbarActionTrustToggleName": "Toggle trust", + "HotbarActionTrustToggleDescription": "Enable or disable workspace trust mode.", "ConfigTitle": "Session Configuration", "ConfigModalTitle": " Config ", "ConfigSearchPlaceholder": "type to filter", diff --git a/crates/tui/locales/es-419.json b/crates/tui/locales/es-419.json index e5f7617eaa..e18570d88e 100644 --- a/crates/tui/locales/es-419.json +++ b/crates/tui/locales/es-419.json @@ -13,6 +13,47 @@ "StatusPickerActionNone": "ninguno ", "StatusPickerActionSave": "guardar ", "StatusPickerActionCancel": "cancelar ", + "HotbarSetupTitle": " Configuración de Hotbar ", + "HotbarSetupSourceApp": "app", + "HotbarSetupSourceSlash": "comando", + "HotbarSetupSourceMcp": "MCP", + "HotbarSetupSourceSkill": "skill", + "HotbarSetupSourcePlugin": "plugin", + "HotbarSetupStatusDisabled": "desactivado", + "HotbarSetupStatusPrefill": "prellenar", + "HotbarSetupStatusReady": "listo", + "HotbarSetupDirtyModified": "modificado", + "HotbarSetupDirtyClean": "sin cambios", + "HotbarSetupNoAction": "Sin acción", + "HotbarSetupStatusLine": "ranura {slot} | {action} | {dirty}", + "HotbarSetupSlotOutOfRange": "La ranura {slot} de Hotbar está fuera de 1-{max}", + "HotbarSetupNoActionSelected": "No hay ninguna acción seleccionada.", + "HotbarSetupCannotAssign": "{action} no se puede asignar: {reason}", + "HotbarSetupNoActions": "No hay acciones de Hotbar disponibles.", + "HotbarSetupRecommended": "rec", + "HotbarSetupEmptySlot": "vacío", + "HotbarSetupHelp": "Tab/Shift+Tab origen Up/Down acción 1-8 ranura Enter asignar Space alternar Delete limpiar s guardar Esc cancelar", + "HotbarActionVoiceToggleName": "Entrada de voz", + "HotbarActionVoiceToggleDescription": "Alternar captura de voz desde el micrófono de la terminal.", + "HotbarActionSessionCompactName": "Compactar sesión", + "HotbarActionSessionCompactDescription": "Compactar el contexto de la conversación actual.", + "HotbarActionModePlanName": "Modo Plan", + "HotbarActionModePlanDescription": "Cambiar la conversación al modo Plan.", + "HotbarActionModeAgentName": "Modo Agent", + "HotbarActionModeAgentDescription": "Cambiar la conversación al modo Agent.", + "HotbarActionModeYoloName": "Modo YOLO", + "HotbarActionModeYoloDescription": "Cambiar la conversación al modo YOLO.", + "HotbarActionReasoningCycleName": "Alternar razonamiento", + "HotbarActionReasoningCycleDescription": "Alternar el esfuerzo de razonamiento configurado para el proveedor activo.", + "HotbarActionReasoningCycleAutoDisabled": "El esfuerzo de razonamiento lo controla el enrutamiento automático de modelo.", + "HotbarActionSidebarToggleName": "Alternar barra lateral", + "HotbarActionSidebarToggleDescription": "Mostrar u ocultar la barra lateral.", + "HotbarActionFileTreeToggleName": "Alternar árbol de archivos", + "HotbarActionFileTreeToggleDescription": "Mostrar u ocultar el árbol de archivos del espacio de trabajo.", + "HotbarActionPaletteOpenName": "Paleta de comandos", + "HotbarActionPaletteOpenDescription": "Abrir la paleta de comandos.", + "HotbarActionTrustToggleName": "Alternar confianza", + "HotbarActionTrustToggleDescription": "Activar o desactivar el modo de confianza del espacio de trabajo.", "ConfigTitle": "Configuración de la sesión", "ConfigSearchPlaceholder": "escribe para filtrar", "ConfigNoSettings": " No hay configuraciones disponibles.", diff --git a/crates/tui/locales/ja.json b/crates/tui/locales/ja.json index e7b7fce12f..c882f8dddb 100644 --- a/crates/tui/locales/ja.json +++ b/crates/tui/locales/ja.json @@ -13,6 +13,47 @@ "StatusPickerActionNone": "なし ", "StatusPickerActionSave": "保存 ", "StatusPickerActionCancel": "キャンセル ", + "HotbarSetupTitle": " Hotbar設定 ", + "HotbarSetupSourceApp": "アプリ", + "HotbarSetupSourceSlash": "コマンド", + "HotbarSetupSourceMcp": "MCP", + "HotbarSetupSourceSkill": "スキル", + "HotbarSetupSourcePlugin": "プラグイン", + "HotbarSetupStatusDisabled": "無効", + "HotbarSetupStatusPrefill": "事前入力", + "HotbarSetupStatusReady": "準備完了", + "HotbarSetupDirtyModified": "変更あり", + "HotbarSetupDirtyClean": "未変更", + "HotbarSetupNoAction": "アクションなし", + "HotbarSetupStatusLine": "スロット {slot} | {action} | {dirty}", + "HotbarSetupSlotOutOfRange": "Hotbarスロット {slot} は 1-{max} の範囲外です", + "HotbarSetupNoActionSelected": "アクションが選択されていません。", + "HotbarSetupCannotAssign": "{action} は割り当てできません: {reason}", + "HotbarSetupNoActions": "利用可能なHotbarアクションがありません。", + "HotbarSetupRecommended": "推奨", + "HotbarSetupEmptySlot": "空", + "HotbarSetupHelp": "Tab/Shift+Tab ソース Up/Down アクション 1-8 スロット Enter 割り当て Space 切替 Delete クリア s 保存 Esc キャンセル", + "HotbarActionVoiceToggleName": "音声入力", + "HotbarActionVoiceToggleDescription": "端末マイクからの音声キャプチャを切り替えます。", + "HotbarActionSessionCompactName": "セッション圧縮", + "HotbarActionSessionCompactDescription": "現在の会話コンテキストを圧縮します。", + "HotbarActionModePlanName": "Planモード", + "HotbarActionModePlanDescription": "会話をPlanモードに切り替えます。", + "HotbarActionModeAgentName": "Agentモード", + "HotbarActionModeAgentDescription": "会話をAgentモードに切り替えます。", + "HotbarActionModeYoloName": "YOLOモード", + "HotbarActionModeYoloDescription": "会話をYOLOモードに切り替えます。", + "HotbarActionReasoningCycleName": "推論強度を切替", + "HotbarActionReasoningCycleDescription": "現在のプロバイダーで設定された推論強度を順に切り替えます。", + "HotbarActionReasoningCycleAutoDisabled": "推論強度は自動モデルルーティングで制御されています。", + "HotbarActionSidebarToggleName": "サイドバー切替", + "HotbarActionSidebarToggleDescription": "サイドバーを表示または非表示にします。", + "HotbarActionFileTreeToggleName": "ファイルツリー切替", + "HotbarActionFileTreeToggleDescription": "ワークスペースのファイルツリーを表示または非表示にします。", + "HotbarActionPaletteOpenName": "コマンドパレット", + "HotbarActionPaletteOpenDescription": "コマンドパレットを開きます。", + "HotbarActionTrustToggleName": "信頼モード切替", + "HotbarActionTrustToggleDescription": "ワークスペース信頼モードを有効または無効にします。", "ConfigTitle": "セッション設定", "ConfigModalTitle": " 設定 ", "ConfigSearchPlaceholder": "入力して絞り込み", diff --git a/crates/tui/locales/pt-BR.json b/crates/tui/locales/pt-BR.json index 8deef83efc..0a05a48803 100644 --- a/crates/tui/locales/pt-BR.json +++ b/crates/tui/locales/pt-BR.json @@ -12,6 +12,47 @@ "StatusPickerActionNone": "nenhum ", "StatusPickerActionSave": "salvar ", "StatusPickerActionCancel": "cancelar ", + "HotbarSetupTitle": " Configuração da Hotbar ", + "HotbarSetupSourceApp": "app", + "HotbarSetupSourceSlash": "comando", + "HotbarSetupSourceMcp": "MCP", + "HotbarSetupSourceSkill": "skill", + "HotbarSetupSourcePlugin": "plugin", + "HotbarSetupStatusDisabled": "desativado", + "HotbarSetupStatusPrefill": "preencher", + "HotbarSetupStatusReady": "pronto", + "HotbarSetupDirtyModified": "modificado", + "HotbarSetupDirtyClean": "sem alterações", + "HotbarSetupNoAction": "Nenhuma ação", + "HotbarSetupStatusLine": "slot {slot} | {action} | {dirty}", + "HotbarSetupSlotOutOfRange": "Slot {slot} da Hotbar está fora de 1-{max}", + "HotbarSetupNoActionSelected": "Nenhuma ação selecionada.", + "HotbarSetupCannotAssign": "{action} não pode ser atribuída: {reason}", + "HotbarSetupNoActions": "Nenhuma ação da Hotbar disponível.", + "HotbarSetupRecommended": "rec", + "HotbarSetupEmptySlot": "vazio", + "HotbarSetupHelp": "Tab/Shift+Tab origem Up/Down ação 1-8 slot Enter atribuir Space alternar Delete limpar s salvar Esc cancelar", + "HotbarActionVoiceToggleName": "Entrada de voz", + "HotbarActionVoiceToggleDescription": "Alternar captura de voz pelo microfone do terminal.", + "HotbarActionSessionCompactName": "Compactar sessão", + "HotbarActionSessionCompactDescription": "Compactar o contexto da conversa atual.", + "HotbarActionModePlanName": "Modo Plan", + "HotbarActionModePlanDescription": "Alternar a conversa para o modo Plan.", + "HotbarActionModeAgentName": "Modo Agent", + "HotbarActionModeAgentDescription": "Alternar a conversa para o modo Agent.", + "HotbarActionModeYoloName": "Modo YOLO", + "HotbarActionModeYoloDescription": "Alternar a conversa para o modo YOLO.", + "HotbarActionReasoningCycleName": "Alternar raciocínio", + "HotbarActionReasoningCycleDescription": "Alternar o esforço de raciocínio configurado para o provedor ativo.", + "HotbarActionReasoningCycleAutoDisabled": "O esforço de raciocínio é controlado pelo roteamento automático de modelo.", + "HotbarActionSidebarToggleName": "Alternar barra lateral", + "HotbarActionSidebarToggleDescription": "Mostrar ou ocultar a barra lateral.", + "HotbarActionFileTreeToggleName": "Alternar árvore de arquivos", + "HotbarActionFileTreeToggleDescription": "Mostrar ou ocultar a árvore de arquivos do workspace.", + "HotbarActionPaletteOpenName": "Paleta de comandos", + "HotbarActionPaletteOpenDescription": "Abrir a paleta de comandos.", + "HotbarActionTrustToggleName": "Alternar confiança", + "HotbarActionTrustToggleDescription": "Ativar ou desativar o modo de confiança do workspace.", "ConfigTitle": "Configuração da sessão", "ConfigSearchPlaceholder": "digite para filtrar", "ConfigNoSettings": " Nenhuma configuração disponível.", diff --git a/crates/tui/locales/vi.json b/crates/tui/locales/vi.json index 29bd00503a..d6565d7276 100644 --- a/crates/tui/locales/vi.json +++ b/crates/tui/locales/vi.json @@ -13,6 +13,47 @@ "StatusPickerActionNone": "không ", "StatusPickerActionSave": "lưu ", "StatusPickerActionCancel": "huỷ ", + "HotbarSetupTitle": " Thiết lập Hotbar ", + "HotbarSetupSourceApp": "ứng dụng", + "HotbarSetupSourceSlash": "lệnh", + "HotbarSetupSourceMcp": "MCP", + "HotbarSetupSourceSkill": "kỹ năng", + "HotbarSetupSourcePlugin": "plugin", + "HotbarSetupStatusDisabled": "đã tắt", + "HotbarSetupStatusPrefill": "điền sẵn", + "HotbarSetupStatusReady": "sẵn sàng", + "HotbarSetupDirtyModified": "đã sửa", + "HotbarSetupDirtyClean": "chưa đổi", + "HotbarSetupNoAction": "Không có thao tác", + "HotbarSetupStatusLine": "ô {slot} | {action} | {dirty}", + "HotbarSetupSlotOutOfRange": "Ô Hotbar {slot} nằm ngoài 1-{max}", + "HotbarSetupNoActionSelected": "Chưa chọn thao tác.", + "HotbarSetupCannotAssign": "Không thể gán {action}: {reason}", + "HotbarSetupNoActions": "Không có thao tác Hotbar nào khả dụng.", + "HotbarSetupRecommended": "gợi ý", + "HotbarSetupEmptySlot": "trống", + "HotbarSetupHelp": "Tab/Shift+Tab nguồn Up/Down thao tác 1-8 ô Enter gán Space bật/tắt Delete xoá s lưu Esc huỷ", + "HotbarActionVoiceToggleName": "Nhập giọng nói", + "HotbarActionVoiceToggleDescription": "Bật/tắt ghi âm từ micrô của terminal.", + "HotbarActionSessionCompactName": "Nén phiên", + "HotbarActionSessionCompactDescription": "Nén ngữ cảnh cuộc trò chuyện hiện tại.", + "HotbarActionModePlanName": "Chế độ Plan", + "HotbarActionModePlanDescription": "Chuyển cuộc trò chuyện sang chế độ Plan.", + "HotbarActionModeAgentName": "Chế độ Agent", + "HotbarActionModeAgentDescription": "Chuyển cuộc trò chuyện sang chế độ Agent.", + "HotbarActionModeYoloName": "Chế độ YOLO", + "HotbarActionModeYoloDescription": "Chuyển cuộc trò chuyện sang chế độ YOLO.", + "HotbarActionReasoningCycleName": "Đổi mức suy luận", + "HotbarActionReasoningCycleDescription": "Luân phiên mức suy luận đã cấu hình cho nhà cung cấp đang hoạt động.", + "HotbarActionReasoningCycleAutoDisabled": "Mức suy luận do định tuyến mô hình tự động kiểm soát.", + "HotbarActionSidebarToggleName": "Bật/tắt thanh bên", + "HotbarActionSidebarToggleDescription": "Hiển thị hoặc ẩn thanh bên.", + "HotbarActionFileTreeToggleName": "Bật/tắt cây tệp", + "HotbarActionFileTreeToggleDescription": "Hiển thị hoặc ẩn cây tệp của workspace.", + "HotbarActionPaletteOpenName": "Bảng lệnh", + "HotbarActionPaletteOpenDescription": "Mở bảng lệnh.", + "HotbarActionTrustToggleName": "Bật/tắt tin cậy", + "HotbarActionTrustToggleDescription": "Bật hoặc tắt chế độ tin cậy của workspace.", "ConfigTitle": "Cấu hình phiên làm việc", "ConfigModalTitle": " Cấu hình ", "ConfigSearchPlaceholder": "Nhập để lọc kết quả", diff --git a/crates/tui/locales/zh-Hans.json b/crates/tui/locales/zh-Hans.json index 269614ebba..712e203e05 100644 --- a/crates/tui/locales/zh-Hans.json +++ b/crates/tui/locales/zh-Hans.json @@ -13,6 +13,47 @@ "StatusPickerActionNone": "无 ", "StatusPickerActionSave": "保存 ", "StatusPickerActionCancel": "取消 ", + "HotbarSetupTitle": " Hotbar 设置 ", + "HotbarSetupSourceApp": "应用", + "HotbarSetupSourceSlash": "命令", + "HotbarSetupSourceMcp": "MCP", + "HotbarSetupSourceSkill": "技能", + "HotbarSetupSourcePlugin": "插件", + "HotbarSetupStatusDisabled": "不可用", + "HotbarSetupStatusPrefill": "预填", + "HotbarSetupStatusReady": "就绪", + "HotbarSetupDirtyModified": "已修改", + "HotbarSetupDirtyClean": "未修改", + "HotbarSetupNoAction": "无操作", + "HotbarSetupStatusLine": "槽位 {slot} | {action} | {dirty}", + "HotbarSetupSlotOutOfRange": "Hotbar 槽位 {slot} 超出 1-{max}", + "HotbarSetupNoActionSelected": "未选择操作。", + "HotbarSetupCannotAssign": "{action} 无法分配:{reason}", + "HotbarSetupNoActions": "没有可用的 Hotbar 操作。", + "HotbarSetupRecommended": "荐", + "HotbarSetupEmptySlot": "空", + "HotbarSetupHelp": "Tab/Shift+Tab 来源 Up/Down 操作 1-8 槽位 Enter 分配 Space 切换 Delete 清除 s 保存 Esc 取消", + "HotbarActionVoiceToggleName": "语音输入", + "HotbarActionVoiceToggleDescription": "切换终端麦克风语音采集。", + "HotbarActionSessionCompactName": "压缩会话", + "HotbarActionSessionCompactDescription": "压缩当前对话上下文。", + "HotbarActionModePlanName": "Plan 模式", + "HotbarActionModePlanDescription": "将对话切换到 Plan 模式。", + "HotbarActionModeAgentName": "Agent 模式", + "HotbarActionModeAgentDescription": "将对话切换到 Agent 模式。", + "HotbarActionModeYoloName": "YOLO 模式", + "HotbarActionModeYoloDescription": "将对话切换到 YOLO 模式。", + "HotbarActionReasoningCycleName": "切换推理强度", + "HotbarActionReasoningCycleDescription": "轮换当前提供商配置的推理强度。", + "HotbarActionReasoningCycleAutoDisabled": "推理强度由自动模型路由控制。", + "HotbarActionSidebarToggleName": "切换侧边栏", + "HotbarActionSidebarToggleDescription": "显示或隐藏侧边栏。", + "HotbarActionFileTreeToggleName": "切换文件树", + "HotbarActionFileTreeToggleDescription": "显示或隐藏工作区文件树。", + "HotbarActionPaletteOpenName": "命令面板", + "HotbarActionPaletteOpenDescription": "打开命令面板。", + "HotbarActionTrustToggleName": "切换信任", + "HotbarActionTrustToggleDescription": "启用或停用工作区信任模式。", "ConfigTitle": "会话配置", "ConfigModalTitle": " 配置 ", "ConfigSearchPlaceholder": "输入以筛选", diff --git a/crates/tui/locales/zh-Hant.json b/crates/tui/locales/zh-Hant.json index 9d1768ddc2..277c2c8186 100644 --- a/crates/tui/locales/zh-Hant.json +++ b/crates/tui/locales/zh-Hant.json @@ -1,5 +1,8 @@ { "CmdRelayDescription": "為新執行緒建立會話接力摘要", + "CmdHotbarDescription": "開啟 Hotbar 設定", + "KbJumpPlanAgentYolo": "觸發 Hotbar 槽位", + "KbAltJumpPlanAgentYolo": "替代快捷鍵跳到 Plan / Agent / YOLO 模式", "CmdTranslateDescription": "切換輸出翻譯為目前系統語言的開關狀態", "CmdTranslateOff": "輸出翻譯已關閉(顯示原始模型輸出)", "CmdTranslateOn": "輸出翻譯已開啟:模型回覆將以繁體中文顯示", @@ -135,6 +138,47 @@ "StatusPickerActionNone": "無 ", "StatusPickerActionSave": "儲存 ", "StatusPickerActionCancel": "取消 ", + "HotbarSetupTitle": " Hotbar 設定 ", + "HotbarSetupSourceApp": "應用", + "HotbarSetupSourceSlash": "命令", + "HotbarSetupSourceMcp": "MCP", + "HotbarSetupSourceSkill": "技能", + "HotbarSetupSourcePlugin": "外掛", + "HotbarSetupStatusDisabled": "不可用", + "HotbarSetupStatusPrefill": "預填", + "HotbarSetupStatusReady": "就緒", + "HotbarSetupDirtyModified": "已修改", + "HotbarSetupDirtyClean": "未修改", + "HotbarSetupNoAction": "無操作", + "HotbarSetupStatusLine": "槽位 {slot} | {action} | {dirty}", + "HotbarSetupSlotOutOfRange": "Hotbar 槽位 {slot} 超出 1-{max}", + "HotbarSetupNoActionSelected": "未選擇操作。", + "HotbarSetupCannotAssign": "{action} 無法分配:{reason}", + "HotbarSetupNoActions": "沒有可用的 Hotbar 操作。", + "HotbarSetupRecommended": "薦", + "HotbarSetupEmptySlot": "空", + "HotbarSetupHelp": "Tab/Shift+Tab 來源 Up/Down 操作 1-8 槽位 Enter 分配 Space 切換 Delete 清除 s 儲存 Esc 取消", + "HotbarActionVoiceToggleName": "語音輸入", + "HotbarActionVoiceToggleDescription": "切換終端麥克風語音擷取。", + "HotbarActionSessionCompactName": "壓縮會話", + "HotbarActionSessionCompactDescription": "壓縮目前對話上下文。", + "HotbarActionModePlanName": "Plan 模式", + "HotbarActionModePlanDescription": "將對話切換到 Plan 模式。", + "HotbarActionModeAgentName": "Agent 模式", + "HotbarActionModeAgentDescription": "將對話切換到 Agent 模式。", + "HotbarActionModeYoloName": "YOLO 模式", + "HotbarActionModeYoloDescription": "將對話切換到 YOLO 模式。", + "HotbarActionReasoningCycleName": "切換推理強度", + "HotbarActionReasoningCycleDescription": "輪換目前提供商設定的推理強度。", + "HotbarActionReasoningCycleAutoDisabled": "推理強度由自動模型路由控制。", + "HotbarActionSidebarToggleName": "切換側邊欄", + "HotbarActionSidebarToggleDescription": "顯示或隱藏側邊欄。", + "HotbarActionFileTreeToggleName": "切換檔案樹", + "HotbarActionFileTreeToggleDescription": "顯示或隱藏工作區檔案樹。", + "HotbarActionPaletteOpenName": "命令面板", + "HotbarActionPaletteOpenDescription": "開啟命令面板。", + "HotbarActionTrustToggleName": "切換信任", + "HotbarActionTrustToggleDescription": "啟用或停用工作區信任模式。", "ToolFamilyRead": "讀取", "ToolFamilyPatch": "修補", "ToolFamilyRun": "執行", diff --git a/crates/tui/src/localization.rs b/crates/tui/src/localization.rs index 490cc957fa..36d4786f8e 100644 --- a/crates/tui/src/localization.rs +++ b/crates/tui/src/localization.rs @@ -236,6 +236,48 @@ pub enum MessageId { StatusPickerActionNone, StatusPickerActionSave, StatusPickerActionCancel, + // Hotbar setup wizard chrome and validation. + HotbarSetupTitle, + HotbarSetupSourceApp, + HotbarSetupSourceSlash, + HotbarSetupSourceMcp, + HotbarSetupSourceSkill, + HotbarSetupSourcePlugin, + HotbarSetupStatusDisabled, + HotbarSetupStatusPrefill, + HotbarSetupStatusReady, + HotbarSetupDirtyModified, + HotbarSetupDirtyClean, + HotbarSetupNoAction, + HotbarSetupStatusLine, + HotbarSetupSlotOutOfRange, + HotbarSetupNoActionSelected, + HotbarSetupCannotAssign, + HotbarSetupNoActions, + HotbarSetupRecommended, + HotbarSetupEmptySlot, + HotbarSetupHelp, + HotbarActionVoiceToggleName, + HotbarActionVoiceToggleDescription, + HotbarActionSessionCompactName, + HotbarActionSessionCompactDescription, + HotbarActionModePlanName, + HotbarActionModePlanDescription, + HotbarActionModeAgentName, + HotbarActionModeAgentDescription, + HotbarActionModeYoloName, + HotbarActionModeYoloDescription, + HotbarActionReasoningCycleName, + HotbarActionReasoningCycleDescription, + HotbarActionReasoningCycleAutoDisabled, + HotbarActionSidebarToggleName, + HotbarActionSidebarToggleDescription, + HotbarActionFileTreeToggleName, + HotbarActionFileTreeToggleDescription, + HotbarActionPaletteOpenName, + HotbarActionPaletteOpenDescription, + HotbarActionTrustToggleName, + HotbarActionTrustToggleDescription, ConfigTitle, ConfigModalTitle, ConfigSearchPlaceholder, @@ -698,6 +740,47 @@ pub const ALL_MESSAGE_IDS: &[MessageId] = &[ MessageId::StatusPickerActionNone, MessageId::StatusPickerActionSave, MessageId::StatusPickerActionCancel, + MessageId::HotbarSetupTitle, + MessageId::HotbarSetupSourceApp, + MessageId::HotbarSetupSourceSlash, + MessageId::HotbarSetupSourceMcp, + MessageId::HotbarSetupSourceSkill, + MessageId::HotbarSetupSourcePlugin, + MessageId::HotbarSetupStatusDisabled, + MessageId::HotbarSetupStatusPrefill, + MessageId::HotbarSetupStatusReady, + MessageId::HotbarSetupDirtyModified, + MessageId::HotbarSetupDirtyClean, + MessageId::HotbarSetupNoAction, + MessageId::HotbarSetupStatusLine, + MessageId::HotbarSetupSlotOutOfRange, + MessageId::HotbarSetupNoActionSelected, + MessageId::HotbarSetupCannotAssign, + MessageId::HotbarSetupNoActions, + MessageId::HotbarSetupRecommended, + MessageId::HotbarSetupEmptySlot, + MessageId::HotbarSetupHelp, + MessageId::HotbarActionVoiceToggleName, + MessageId::HotbarActionVoiceToggleDescription, + MessageId::HotbarActionSessionCompactName, + MessageId::HotbarActionSessionCompactDescription, + MessageId::HotbarActionModePlanName, + MessageId::HotbarActionModePlanDescription, + MessageId::HotbarActionModeAgentName, + MessageId::HotbarActionModeAgentDescription, + MessageId::HotbarActionModeYoloName, + MessageId::HotbarActionModeYoloDescription, + MessageId::HotbarActionReasoningCycleName, + MessageId::HotbarActionReasoningCycleDescription, + MessageId::HotbarActionReasoningCycleAutoDisabled, + MessageId::HotbarActionSidebarToggleName, + MessageId::HotbarActionSidebarToggleDescription, + MessageId::HotbarActionFileTreeToggleName, + MessageId::HotbarActionFileTreeToggleDescription, + MessageId::HotbarActionPaletteOpenName, + MessageId::HotbarActionPaletteOpenDescription, + MessageId::HotbarActionTrustToggleName, + MessageId::HotbarActionTrustToggleDescription, MessageId::ConfigTitle, MessageId::ConfigModalTitle, MessageId::ConfigSearchPlaceholder, @@ -1386,6 +1469,23 @@ mod tests { } } + #[test] + fn zh_hant_hotbar_command_and_keybinding_strings_are_native() { + for id in [ + MessageId::CmdHotbarDescription, + MessageId::KbJumpPlanAgentYolo, + MessageId::KbAltJumpPlanAgentYolo, + ] { + let localized = tr(Locale::ZhHant, id); + assert!(!localized.is_empty(), "zh-Hant empty for {id:?}"); + assert_ne!( + localized, + tr(Locale::En, id), + "zh-Hant should translate {id:?}" + ); + } + } + #[test] fn unsupported_locale_falls_back_to_english() { assert_eq!( diff --git a/crates/tui/src/tui/hotbar/actions.rs b/crates/tui/src/tui/hotbar/actions.rs index 13b40673ad..aa2577c857 100644 --- a/crates/tui/src/tui/hotbar/actions.rs +++ b/crates/tui/src/tui/hotbar/actions.rs @@ -5,7 +5,7 @@ use std::sync::Arc; use anyhow::{Result, bail}; use crate::commands::{self, CommandInfo, CommandResult}; -use crate::localization::Locale; +use crate::localization::{Locale, MessageId, tr}; use crate::tui::app::{App, AppAction, AppMode, SidebarFocus}; use crate::tui::command_palette::{ CommandPaletteView, build_entries as build_command_palette_entries, @@ -703,6 +703,52 @@ impl AppHotbarAction { HotbarRecommendation::Eligible } } + + fn localized_display_name(&self, locale: Locale) -> String { + let Some(id) = self.display_name_id() else { + return self.display_name.to_string(); + }; + tr(locale, id).into_owned() + } + + fn localized_description(&self, locale: Locale) -> String { + let Some(id) = self.description_id() else { + return self.description.to_string(); + }; + tr(locale, id).into_owned() + } + + fn display_name_id(&self) -> Option { + Some(match self.kind { + AppHotbarKind::VoiceToggle => MessageId::HotbarActionVoiceToggleName, + AppHotbarKind::SessionCompact => MessageId::HotbarActionSessionCompactName, + AppHotbarKind::Mode(AppMode::Plan) => MessageId::HotbarActionModePlanName, + AppHotbarKind::Mode(AppMode::Agent) => MessageId::HotbarActionModeAgentName, + AppHotbarKind::Mode(AppMode::Yolo) => MessageId::HotbarActionModeYoloName, + AppHotbarKind::Mode(AppMode::Auto) => return None, + AppHotbarKind::ReasoningCycle => MessageId::HotbarActionReasoningCycleName, + AppHotbarKind::SidebarToggle => MessageId::HotbarActionSidebarToggleName, + AppHotbarKind::FileTreeToggle => MessageId::HotbarActionFileTreeToggleName, + AppHotbarKind::PaletteOpen => MessageId::HotbarActionPaletteOpenName, + AppHotbarKind::TrustToggle => MessageId::HotbarActionTrustToggleName, + }) + } + + fn description_id(&self) -> Option { + Some(match self.kind { + AppHotbarKind::VoiceToggle => MessageId::HotbarActionVoiceToggleDescription, + AppHotbarKind::SessionCompact => MessageId::HotbarActionSessionCompactDescription, + AppHotbarKind::Mode(AppMode::Plan) => MessageId::HotbarActionModePlanDescription, + AppHotbarKind::Mode(AppMode::Agent) => MessageId::HotbarActionModeAgentDescription, + AppHotbarKind::Mode(AppMode::Yolo) => MessageId::HotbarActionModeYoloDescription, + AppHotbarKind::Mode(AppMode::Auto) => return None, + AppHotbarKind::ReasoningCycle => MessageId::HotbarActionReasoningCycleDescription, + AppHotbarKind::SidebarToggle => MessageId::HotbarActionSidebarToggleDescription, + AppHotbarKind::FileTreeToggle => MessageId::HotbarActionFileTreeToggleDescription, + AppHotbarKind::PaletteOpen => MessageId::HotbarActionPaletteOpenDescription, + AppHotbarKind::TrustToggle => MessageId::HotbarActionTrustToggleDescription, + }) + } } impl HotbarAction for AppHotbarAction { @@ -710,13 +756,13 @@ impl HotbarAction for AppHotbarAction { self.id } - fn metadata(&self, _locale: Locale) -> HotbarActionMetadata { + fn metadata(&self, locale: Locale) -> HotbarActionMetadata { HotbarActionMetadata { id: self.id.to_string(), source_id: "builtin".to_string(), - display_name: self.display_name.to_string(), + display_name: self.localized_display_name(locale), compact_label: self.short_label.to_string(), - description: self.description.to_string(), + description: self.localized_description(locale), category: HotbarActionCategory::App, args: HotbarArgsBehavior::None, safety: self.safety(), @@ -749,9 +795,13 @@ impl HotbarAction for AppHotbarAction { fn disabled_reason(&self, app: &App) -> Option { match self.kind { - AppHotbarKind::ReasoningCycle if app.auto_model => { - Some("Reasoning effort is controlled by auto model routing.".to_string()) - } + AppHotbarKind::ReasoningCycle if app.auto_model => Some( + tr( + app.ui_locale, + MessageId::HotbarActionReasoningCycleAutoDisabled, + ) + .into_owned(), + ), _ => None, } } diff --git a/crates/tui/src/tui/hotbar/setup.rs b/crates/tui/src/tui/hotbar/setup.rs index deba5c3375..b05ab56b82 100644 --- a/crates/tui/src/tui/hotbar/setup.rs +++ b/crates/tui/src/tui/hotbar/setup.rs @@ -10,6 +10,7 @@ use ratatui::{ }; use crate::config::Config; +use crate::localization::{Locale, MessageId, tr}; use crate::palette; use crate::tui::app::App; use crate::tui::views::{ModalKind, ModalView, ViewAction, ViewEvent}; @@ -26,19 +27,58 @@ pub struct HotbarSetupActionRow { } impl HotbarSetupActionRow { - fn status_label(&self) -> &'static str { - if self.disabled_reason.is_some() { - "disabled" - } else if matches!(self.metadata.args, HotbarArgsBehavior::Required) { - "prefill" - } else { - "ready" - } + fn status_label(&self, locale: Locale) -> String { + tr( + locale, + if self.disabled_reason.is_some() { + MessageId::HotbarSetupStatusDisabled + } else if matches!(self.metadata.args, HotbarArgsBehavior::Required) { + MessageId::HotbarSetupStatusPrefill + } else { + MessageId::HotbarSetupStatusReady + }, + ) + .into_owned() + } +} + +fn hotbar_setup_source_label(locale: Locale, source: HotbarActionCategory) -> String { + tr( + locale, + match source { + HotbarActionCategory::App => MessageId::HotbarSetupSourceApp, + HotbarActionCategory::Slash => MessageId::HotbarSetupSourceSlash, + HotbarActionCategory::Mcp => MessageId::HotbarSetupSourceMcp, + HotbarActionCategory::Skill => MessageId::HotbarSetupSourceSkill, + HotbarActionCategory::Plugin => MessageId::HotbarSetupSourcePlugin, + }, + ) + .into_owned() +} + +fn tr_hotbar_setup(locale: Locale, id: MessageId, replacements: &[(&str, String)]) -> String { + let mut message = tr(locale, id).into_owned(); + for (placeholder, value) in replacements { + message = message.replace(placeholder, value); } + message +} + +fn hotbar_setup_dirty_label(locale: Locale, is_dirty: bool) -> String { + tr( + locale, + if is_dirty { + MessageId::HotbarSetupDirtyModified + } else { + MessageId::HotbarSetupDirtyClean + }, + ) + .into_owned() } #[derive(Debug, Clone, PartialEq, Eq)] pub struct HotbarSetupView { + locale: Locale, sources: Vec, actions: Vec, selected_source_idx: usize, @@ -113,6 +153,7 @@ impl HotbarSetupView { .collect::>(); Self { + locale: app.ui_locale, sources, actions, selected_source_idx: 0, @@ -188,12 +229,26 @@ impl HotbarSetupView { if let Some(error) = self.validation_errors.last() { return error.clone(); } - let dirty = if self.is_dirty() { "modified" } else { "clean" }; + let dirty = hotbar_setup_dirty_label(self.locale, self.is_dirty()); let action = self .selected_action() - .map(|row| format!("{} ({})", row.metadata.display_name, row.status_label())) - .unwrap_or_else(|| "No action".to_string()); - format!("slot {} | {action} | {dirty}", self.selected_slot) + .map(|row| { + format!( + "{} ({})", + row.metadata.display_name, + row.status_label(self.locale) + ) + }) + .unwrap_or_else(|| tr(self.locale, MessageId::HotbarSetupNoAction).into_owned()); + tr_hotbar_setup( + self.locale, + MessageId::HotbarSetupStatusLine, + &[ + ("{slot}", self.selected_slot.to_string()), + ("{action}", action), + ("{dirty}", dirty), + ], + ) } #[cfg(test)] @@ -227,9 +282,13 @@ impl HotbarSetupView { pub fn select_slot(&mut self, slot: u8) -> bool { if !(1..=codewhale_config::HOTBAR_SLOT_COUNT).contains(&slot) { - self.validation_errors = vec![format!( - "Hotbar slot {slot} is outside 1-{}", - codewhale_config::HOTBAR_SLOT_COUNT + self.validation_errors = vec![tr_hotbar_setup( + self.locale, + MessageId::HotbarSetupSlotOutOfRange, + &[ + ("{slot}", slot.to_string()), + ("{max}", codewhale_config::HOTBAR_SLOT_COUNT.to_string()), + ], )]; return false; } @@ -240,13 +299,18 @@ impl HotbarSetupView { pub fn assign_selected_action(&mut self) -> bool { let Some(row) = self.selected_action().cloned() else { - self.validation_errors = vec!["No action selected.".to_string()]; + self.validation_errors = + vec![tr(self.locale, MessageId::HotbarSetupNoActionSelected).into_owned()]; return false; }; if let Some(reason) = row.disabled_reason { - self.validation_errors = vec![format!( - "{} cannot be assigned: {reason}", - row.metadata.display_name + self.validation_errors = vec![tr_hotbar_setup( + self.locale, + MessageId::HotbarSetupCannotAssign, + &[ + ("{action}", row.metadata.display_name), + ("{reason}", reason), + ], )]; return false; } @@ -358,10 +422,11 @@ impl HotbarSetupView { .sources .iter() .map(|source| { + let label = hotbar_setup_source_label(self.locale, *source); if Some(*source) == self.selected_source() { - format!("[{}]", source.as_str()) + format!("[{label}]") } else { - source.as_str().to_string() + label } }) .collect::>() @@ -375,7 +440,9 @@ impl HotbarSetupView { lines.push(Line::from("")); let Some(source) = self.selected_source() else { - lines.push(Line::from("No hotbar actions are available.")); + lines.push(Line::from( + tr(self.locale, MessageId::HotbarSetupNoActions).into_owned(), + )); return lines; }; @@ -395,15 +462,15 @@ impl HotbarSetupView { " " }; let recommended = if self.recommended_action_ids.contains(&row.metadata.id) { - "rec" + tr(self.locale, MessageId::HotbarSetupRecommended).into_owned() } else { - "" + String::new() }; let mut text = format!( "{marker}{checked} {:<3} {:<20} {:<8} {}", recommended, row.metadata.display_name, - row.status_label(), + row.status_label(self.locale), row.metadata.description ); if let Some(reason) = row.disabled_reason.as_deref() { @@ -421,7 +488,9 @@ impl HotbarSetupView { .draft_bindings .get(&slot) .map(|binding| compact_action_id(&binding.action)) - .unwrap_or_else(|| "empty".to_string()); + .unwrap_or_else(|| { + tr(self.locale, MessageId::HotbarSetupEmptySlot).into_owned() + }); if slot == self.selected_slot { format!("[{slot}:{label}]") } else { @@ -434,7 +503,7 @@ impl HotbarSetupView { lines.push(Line::from(self.status_text())); if self.help_visible { lines.push(Line::from( - "Tab/Shift+Tab source Up/Down action 1-8 slot Enter assign Space toggle Delete clear s save Esc cancel", + tr(self.locale, MessageId::HotbarSetupHelp).into_owned(), )); } lines @@ -523,7 +592,12 @@ impl ModalView for HotbarSetupView { }; Clear.render(popup_area, buf); let block = Block::default() - .title(" Hotbar setup ") + .title(Line::from(Span::styled( + tr(self.locale, MessageId::HotbarSetupTitle), + Style::default() + .fg(palette::DEEPSEEK_SKY) + .add_modifier(Modifier::BOLD), + ))) .borders(Borders::ALL) .border_style(Style::default().fg(palette::BORDER_COLOR)); let inner = block.inner(popup_area); @@ -561,6 +635,7 @@ fn compact_action_id(action_id: &str) -> String { mod tests { use super::*; use crate::config::Config; + use crate::localization::{Locale, MessageId, tr}; use crate::tui::app::TuiOptions; use crossterm::event::KeyModifiers; use std::path::PathBuf; @@ -588,7 +663,13 @@ mod tests { initial_input: None, }; let mut app = App::new(options, &Config::default()); - app.ui_locale = crate::localization::Locale::En; + app.ui_locale = Locale::En; + app + } + + fn test_app_with_locale(locale: Locale) -> App { + let mut app = test_app(); + app.ui_locale = locale; app } @@ -596,6 +677,21 @@ mod tests { KeyEvent::new(code, KeyModifiers::NONE) } + fn rendered_text(view: &HotbarSetupView) -> String { + let area = Rect::new(0, 0, 140, 36); + let mut buf = Buffer::empty(area); + view.render(area, &mut buf); + + let mut out = String::new(); + for y in area.top()..area.bottom() { + for x in area.left()..area.right() { + out.push_str(buf[(x, y)].symbol()); + } + out.push('\n'); + } + out + } + #[test] fn wizard_sources_follow_registered_action_categories() { let app = test_app(); @@ -610,6 +706,69 @@ mod tests { assert!(view.checked_action_ids().contains("mode.plan")); } + #[test] + fn wizard_chrome_uses_non_english_locale() { + let app = test_app_with_locale(Locale::ZhHant); + let mut view = HotbarSetupView::new(&app, &Config::default()); + view.clear_selected_slot(); + view.handle_key(key(KeyCode::Char('?'))); + + let status = view.status_text(); + assert!(status.contains("槽位 1"), "status was {status:?}"); + assert!( + status.contains(tr(Locale::ZhHant, MessageId::HotbarSetupDirtyModified).as_ref()), + "status was {status:?}" + ); + assert!(!status.contains("slot 1 |"), "status was {status:?}"); + assert!(!status.contains("modified"), "status was {status:?}"); + + let rendered = rendered_text(&view); + let compact_rendered = rendered.replace(' ', ""); + for expected in [ + "Hotbar設定", + "[應用]", + "命令", + "就緒", + "槽位", + "來源", + "分配", + "儲存", + "取消", + "Agent模式", + "命令面板", + "切換側邊欄", + ] { + assert!( + compact_rendered.contains(expected), + "missing {expected:?} in render:\n{rendered}" + ); + } + assert!( + compact_rendered.contains(":空"), + "missing localized empty slot:\n{rendered}" + ); + + for leaked in [ + "Hotbar setup", + "Tab/Shift+Tab source", + "Enter assign", + "Esc cancel", + "slot 1 |", + "ready", + "modified", + "empty", + "Agent mode", + "Command palette", + "Toggle sidebar", + "Switch the conversation", + ] { + assert!( + !rendered.contains(leaked), + "leaked {leaked:?} in render:\n{rendered}" + ); + } + } + #[test] fn wizard_assigns_replaces_toggles_and_clears_slots() { let app = test_app();