diff --git a/.gitignore b/.gitignore index 450a7e5e3945db67acc78c87c5976cf15a5caefe..95f19871372694b323daaf71e6df9c4d3ddb8b5a 100644 --- a/.gitignore +++ b/.gitignore @@ -20,3 +20,6 @@ # Cython *.c + +# Compiled i18n files +**/*.mo diff --git a/scripts/tools/i18n-manager.sh b/scripts/tools/i18n-manager.sh index 73f6be3079237ea038208afa6c8f8c7b75e5c7d6..ef38b42c68b1330c5fb3031d66c81fab32e4af38 100755 --- a/scripts/tools/i18n-manager.sh +++ b/scripts/tools/i18n-manager.sh @@ -2,6 +2,7 @@ # 国际化翻译管理脚本 set -e +set -o pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)" @@ -79,26 +80,24 @@ extract() { exit 1 fi - file_count=$(echo "$python_files" | wc -l | tr -d ' ') + file_count=$(echo "$python_files" | wc -l | sed 's/^[[:space:]]*//') echo " Found $file_count Python files" echo " Output file: $POT_FILE" # 使用 xgettext 提取字符串(使用相对路径) # shellcheck disable=SC2086 - xgettext \ + if xgettext \ --language=Python \ --keyword=_ \ --keyword=_n:1,2 \ --output="$POT_FILE" \ --from-code=UTF-8 \ - --package-name=smart-shell \ + --package-name=oi-cli \ --package-version=0.10.2 \ --msgid-bugs-address=contact@openeuler.org \ --copyright-holder="openEuler Intelligence Project" \ --add-comments=Translators \ - $python_files - - if [ $? -eq 0 ]; then + $python_files; then print_green "✅ Successfully extracted strings to messages.pot" else print_red "❌ Failed to extract strings" @@ -137,7 +136,7 @@ update() { echo " Updating $locale_name..." if msgmerge --update --backup=none "$po_file" "$POT_FILE" 2>/dev/null; then echo " ✅ Updated $locale_name" - ((updated++)) + updated=$((updated + 1)) else print_yellow " ⚠️ Failed to update $locale_name" fi @@ -163,6 +162,7 @@ compile() { check_gettext compiled=0 + failed=0 # 遍历所有语言目录 for locale_path in "$LOCALE_DIR"/*; do @@ -180,20 +180,35 @@ compile() { fi echo " Compiling $locale_name..." - if msgfmt -o "$mo_file" "$po_file" 2>/dev/null; then + # 临时禁用 set -e 和 set -o pipefail 以捕获错误但继续执行 + set +e + set +o pipefail + error_output=$(msgfmt -o "$mo_file" "$po_file" 2>&1) + msgfmt_status=$? + set -e + set -o pipefail + + if [ "$msgfmt_status" -eq 0 ]; then echo " ✅ Compiled $locale_name" - ((compiled++)) + compiled=$((compiled + 1)) else print_yellow " ⚠️ Failed to compile $locale_name" + echo " Error: $error_output" + failed=$((failed + 1)) fi done - if [ $compiled -gt 0 ]; then - echo "" + echo "" + if [ "$compiled" -gt 0 ]; then print_green "✅ Successfully compiled $compiled translation file(s)" - else - echo "" - print_yellow "⚠️ No translation files were compiled" + fi + + if [ "$failed" -gt 0 ]; then + print_yellow "⚠️ Failed to compile $failed translation file(s)" + fi + + if [ "$compiled" -eq 0 ] && [ "$failed" -eq 0 ]; then + print_yellow "⚠️ No translation files found to compile" fi } diff --git a/src/app/dialogs/agent.py b/src/app/dialogs/agent.py index c000d275c531abf11ca8ec0a1e3ca62305783d2f..b1cd115262d9d504b397ad9c1878a8ca3e96d728 100644 --- a/src/app/dialogs/agent.py +++ b/src/app/dialogs/agent.py @@ -14,6 +14,8 @@ from textual.containers import Container from textual.screen import ModalScreen from textual.widgets import Label, Static +from i18n.manager import _ + class BackendRequiredDialog(ModalScreen): """后端要求提示对话框""" @@ -22,9 +24,9 @@ class BackendRequiredDialog(ModalScreen): """构建后端要求提示对话框""" yield Container( Container( - Label("智能体功能提示", id="backend-dialog-title"), - Label("请选择 openEuler Intelligence 后端来使用智能体功能", id="backend-dialog-text"), - Label("按任意键关闭", id="backend-dialog-help"), + Label(_("智能体功能提示"), id="backend-dialog-title"), + Label(_("请选择 openEuler Intelligence 后端来使用智能体功能"), id="backend-dialog-text"), + Label(_("按任意键关闭"), id="backend-dialog-help"), id="backend-dialog", ), id="backend-dialog-screen", @@ -55,7 +57,7 @@ class AgentSelectionDialog(ModalScreen): """ super().__init__() - self.current_agent = current_agent or ("", "智能问答") + self.current_agent = current_agent or ("", _("智能问答")) self.callback = callback # 重新排序智能体列表:智能问答永远第一,当前智能体(如果不是智能问答)排第二 @@ -108,9 +110,9 @@ class AgentSelectionDialog(ModalScreen): yield Container( Container( - Label("OS 智能助手", id="agent-dialog-title"), + Label(_("OS 智能助手"), id="agent-dialog-title"), agent_content, - Label("使用上下键选择,回车确认,ESC取消 | ✓ 表示当前选中", id="agent-dialog-help"), + Label(_("使用上下键选择,回车确认,ESC取消 | ✓ 表示当前选中"), id="agent-dialog-help"), id="agent-dialog", ), id="agent-dialog-screen", @@ -125,7 +127,7 @@ class AgentSelectionDialog(ModalScreen): if self.agents and 0 <= self.selected_index < len(self.agents): selected_agent = self.agents[self.selected_index] else: - selected_agent = ("", "智能问答") + selected_agent = ("", _("智能问答")) self.callback(selected_agent) self.app.pop_screen() elif event.key == "up" and self.selected_index > 0: @@ -180,7 +182,7 @@ class AgentSelectionDialog(ModalScreen): # 如果没有智能体,添加默认选项 if not agent_text_lines: - agent_text_lines.append("[white on green]► ✓ 智能问答[/white on green]") + agent_text_lines.append(f"[white on green]► ✓ {_('智能问答')}[/white on green]") # 更新 Static 组件的内容 try: @@ -200,10 +202,10 @@ class AgentSelectionDialog(ModalScreen): 3. 其他智能体保持原有顺序 """ if not agents: - return [("", "智能问答")] + return [("", _("智能问答"))] # 查找智能问答和当前智能体 - default_qa = ("", "智能问答") + default_qa = ("", _("智能问答")) current_agent = self.current_agent reordered = [] diff --git a/src/app/dialogs/common.py b/src/app/dialogs/common.py index 995891722b033200753f9a23724e367ed83a8b2e..99049e2d0cf97acd8c8988c6c171882444d0e317 100644 --- a/src/app/dialogs/common.py +++ b/src/app/dialogs/common.py @@ -12,6 +12,8 @@ from textual.containers import Container, Horizontal from textual.screen import ModalScreen from textual.widgets import Button, Label +from i18n.manager import _ + class ExitDialog(ModalScreen): """退出确认对话框""" @@ -20,10 +22,10 @@ class ExitDialog(ModalScreen): """构建退出确认对话框""" yield Container( Container( - Label("确认退出吗?", id="dialog-text"), + Label(_("确认退出吗?"), id="dialog-text"), Horizontal( - Button("取消", classes="dialog-button", id="cancel"), - Button("确认", classes="dialog-button", id="confirm"), + Button(_("取消"), classes="dialog-button", id="cancel"), + Button(_("确认"), classes="dialog-button", id="confirm"), id="dialog-buttons", ), id="exit-dialog", diff --git a/src/app/mcp_widgets.py b/src/app/mcp_widgets.py index 12cdd3840a99ae6717c95a3a8604473545ec346c..7fb5d27f126fc0eb9063e97d7dfcd0aee782f9b0 100644 --- a/src/app/mcp_widgets.py +++ b/src/app/mcp_widgets.py @@ -10,6 +10,8 @@ from textual.containers import Container, Horizontal, Vertical from textual.message import Message from textual.widgets import Button, Input, Static +from i18n.manager import _ + if TYPE_CHECKING: from textual.app import ComposeResult @@ -42,14 +44,14 @@ class MCPConfirmWidget(Container): step_name = self.event.get_step_name() content = self.event.get_content() risk = content.get("risk", "unknown") - reason = content.get("reason", "需要用户确认是否执行此工具") + reason = content.get("reason", _("需要用户确认是否执行此工具")) # 风险级别文本和图标 risk_info = { - "low": ("🟢", "低风险"), - "medium": ("🟡", "中等风险"), - "high": ("🔴", "高风险"), - }.get(risk, ("⚪", "未知风险")) + "low": ("🟢", _("低风险")), + "medium": ("🟡", _("中等风险")), + "high": ("🔴", _("高风险")), + }.get(risk, ("⚪", _("未知风险"))) risk_icon, risk_text = risk_info @@ -76,8 +78,8 @@ class MCPConfirmWidget(Container): ) # 确保按钮始终显示 with Horizontal(classes="confirm-buttons"): - yield Button("✓ 确认", variant="success", id="mcp-confirm-yes") - yield Button("✗ 取消", variant="error", id="mcp-confirm-no") + yield Button(_("✓ 确认"), variant="success", id="mcp-confirm-yes") + yield Button(_("✗ 取消"), variant="error", id="mcp-confirm-no") @on(Button.Pressed, "#mcp-confirm-yes") def confirm_execution(self) -> None: @@ -159,12 +161,12 @@ class MCPParameterWidget(Container): """构建参数输入界面""" step_name = self.event.get_step_name() content = self.event.get_content() - message = content.get("message", "需要补充参数") + message = content.get("message", _("需要补充参数")) params = content.get("params", {}) with Vertical(classes="mcp-content"): # 紧凑的参数输入标题 - yield Static("📝 参数输入", classes="param-header", markup=False) + yield Static(_("📝 参数输入"), classes="param-header", markup=False) yield Static(f"🔧 {step_name}", classes="param-tool", markup=False) # 显示说明文字,超长时显示省略号 if len(message) > MAX_DISPLAY_LENGTH: @@ -176,7 +178,7 @@ class MCPParameterWidget(Container): for param_name, param_value in params.items(): if param_value is None or param_value == "": param_input = Input( - placeholder=f"请输入 {param_name}", + placeholder=_("请输入 {param_name}").format(param_name=param_name), id=f"param_{param_name}", classes="param-input-compact", ) @@ -186,7 +188,7 @@ class MCPParameterWidget(Container): # 简化的补充说明输入 if params: # 只有在有其他参数时才显示补充说明 description_input = Input( - placeholder="补充说明(可选)", + placeholder=_("补充说明(可选)"), id="param_description", classes="param-input-compact", ) @@ -195,8 +197,8 @@ class MCPParameterWidget(Container): # 紧凑的按钮行 with Horizontal(classes="param-buttons"): - yield Button("✓ 提交", variant="success", id="mcp-param-submit") - yield Button("✗ 取消", variant="error", id="mcp-param-cancel") + yield Button(_("✓ 提交"), variant="success", id="mcp-param-submit") + yield Button(_("✗ 取消"), variant="error", id="mcp-param-cancel") @on(Button.Pressed, "#mcp-param-submit") def submit_parameters(self) -> None: diff --git a/src/app/settings.py b/src/app/settings.py index caf448e2a2b1f6a2a3386775ab2ea0e766337310..4d2ec66313c7a26990d3c58b77323f18dadffb00 100644 --- a/src/app/settings.py +++ b/src/app/settings.py @@ -15,6 +15,7 @@ from app.dialogs import ExitDialog from backend.hermes import HermesChatClient from backend.openai import OpenAIClient from config import Backend, ConfigManager +from i18n.manager import _ from log import get_logger from tool.validators import APIValidator, validate_oi_connection @@ -59,10 +60,10 @@ class SettingsScreen(ModalScreen): """构建设置页面""" yield Container( Container( - Label("设置", id="settings-title"), + Label(_("设置"), id="settings-title"), # 后端选择 Horizontal( - Label("后端:", classes="settings-label"), + Label(_("后端:"), classes="settings-label"), Button( f"{self.backend.get_display_name()}", id="backend-btn", @@ -72,7 +73,7 @@ class SettingsScreen(ModalScreen): ), # Base URL 输入 Horizontal( - Label("Base URL:", classes="settings-label"), + Label(_("Base URL:"), classes="settings-label"), Input( value=self.config_manager.get_base_url() if self.backend == Backend.OPENAI @@ -84,14 +85,14 @@ class SettingsScreen(ModalScreen): ), # API Key 输入 Horizontal( - Label("API Key:", classes="settings-label"), + Label(_("API Key:"), classes="settings-label"), Input( value=self.config_manager.get_api_key() if self.backend == Backend.OPENAI else self.config_manager.get_eulerintelli_key(), classes="settings-input", id="api-key", - placeholder="API 访问密钥,可选", + placeholder=_("API 访问密钥,可选"), ), classes="settings-option", ), @@ -99,12 +100,12 @@ class SettingsScreen(ModalScreen): *( [ Horizontal( - Label("模型:", classes="settings-label"), + Label(_("模型:"), classes="settings-label"), Input( value=self.selected_model, classes="settings-input", id="model-input", - placeholder="模型名称,可选", + placeholder=_("模型名称,可选"), ), id="model-section", classes="settings-option", @@ -113,9 +114,9 @@ class SettingsScreen(ModalScreen): if self.backend == Backend.OPENAI else [ Horizontal( - Label("MCP 工具授权:", classes="settings-label"), + Label(_("MCP 工具授权:"), classes="settings-label"), Button( - "自动执行" if self.auto_execute_status else "手动确认", + _("自动执行") if self.auto_execute_status else _("手动确认"), id="mcp-btn", classes="settings-button", disabled=not self.mcp_status_loaded, @@ -129,8 +130,8 @@ class SettingsScreen(ModalScreen): Static("", id="spacer"), # 操作按钮 Horizontal( - Button("保存", id="save-btn", variant="primary"), - Button("取消", id="cancel-btn", variant="default"), + Button(_("保存"), id="save-btn", variant="primary"), + Button(_("取消"), id="cancel-btn", variant="default"), id="action-buttons", classes="settings-option", ), @@ -170,14 +171,14 @@ class SettingsScreen(ModalScreen): # 更新 MCP 按钮文本和状态 mcp_btn = self.query_one("#mcp-btn", Button) - mcp_btn.label = "自动执行" if self.auto_execute_status else "手动确认" + mcp_btn.label = _("自动执行") if self.auto_execute_status else _("手动确认") mcp_btn.disabled = not self.mcp_status_loaded except (OSError, ValueError, RuntimeError): self.auto_execute_status = False self.mcp_status_loaded = False mcp_btn = self.query_one("#mcp-btn", Button) - mcp_btn.label = "手动确认" + mcp_btn.label = _("手动确认") mcp_btn.disabled = True @on(Input.Changed, "#base-url, #api-key, #model-input") @@ -235,12 +236,12 @@ class SettingsScreen(ModalScreen): container = self.query_one("#settings-container") spacer = self.query_one("#spacer") model_section = Horizontal( - Label("模型:", classes="settings-label"), + Label(_("模型:"), classes="settings-label"), Input( value=self.selected_model, classes="settings-input", id="model-input", - placeholder="模型名称,可选", + placeholder=_("模型名称,可选"), ), id="model-section", classes="settings-option", @@ -268,9 +269,9 @@ class SettingsScreen(ModalScreen): container = self.query_one("#settings-container") spacer = self.query_one("#spacer") mcp_section = Horizontal( - Label("MCP 工具授权:", classes="settings-label"), + Label(_("MCP 工具授权:"), classes="settings-label"), Button( - "自动执行" if self.auto_execute_status else "手动确认", + _("自动执行") if self.auto_execute_status else _("手动确认"), id="mcp-btn", classes="settings-button", disabled=not self.mcp_status_loaded, @@ -433,7 +434,7 @@ class SettingsScreen(ModalScreen): if not base_url: self.is_validated = False - self.validation_message = "Base URL 不能为空" + self.validation_message = _("Base URL 不能为空") self._update_save_button_state() return @@ -447,7 +448,7 @@ class SettingsScreen(ModalScreen): model = self.selected_model # 验证 OpenAI 配置(模型和 API Key 都可以为空) - valid, message, _ = await self.validator.validate_llm_config( + valid, message, _additional_info = await self.validator.validate_llm_config( endpoint=base_url, api_key=api_key, model=model, @@ -530,7 +531,7 @@ class SettingsScreen(ModalScreen): # 先禁用按钮防止重复点击 mcp_btn = self.query_one("#mcp-btn", Button) mcp_btn.disabled = True - mcp_btn.label = "切换中..." + mcp_btn.label = _("切换中...") # 根据当前状态调用相应的方法 if self.auto_execute_status: @@ -545,13 +546,11 @@ class SettingsScreen(ModalScreen): self.auto_execute_status = await self.llm_client.get_auto_execute_status() # type: ignore[attr-defined] # 更新按钮状态 - mcp_btn.label = "自动执行" if self.auto_execute_status else "手动确认" + mcp_btn.label = _("自动执行") if self.auto_execute_status else _("手动确认") mcp_btn.disabled = False - except (OSError, ValueError, RuntimeError) as e: + except (OSError, ValueError, RuntimeError): # 发生错误时恢复按钮状态 mcp_btn = self.query_one("#mcp-btn", Button) - mcp_btn.label = "自动执行" if self.auto_execute_status else "手动确认" + mcp_btn.label = _("自动执行") if self.auto_execute_status else _("手动确认") mcp_btn.disabled = False - # 可以考虑显示错误消息 - self.notify(f"切换 MCP 工具授权模式失败: {e!s}", severity="error") diff --git a/src/app/tui.py b/src/app/tui.py index a13d38a322fd88ef391780a80a323049f3d7da31..8b20da56a500cbc544847ffacc8eb05991d00845 100644 --- a/src/app/tui.py +++ b/src/app/tui.py @@ -30,6 +30,7 @@ from backend.hermes.mcp_helpers import ( ) from config import ConfigManager from config.model import Backend +from i18n.manager import _ from log.manager import get_logger, log_exception from tool.command_processor import process_command from tool.validators import APIValidator, validate_oi_connection @@ -213,7 +214,7 @@ class CommandInput(Input): def __init__(self) -> None: """初始化命令输入组件""" - super().__init__(placeholder="输入命令或问题...", id="command-input") + super().__init__(placeholder=_("Enter command or question..."), id="command-input") class IntelligentTerminal(App): @@ -222,12 +223,12 @@ class IntelligentTerminal(App): CSS_PATH = "css/styles.tcss" BINDINGS: ClassVar[list[BindingType]] = [ - Binding(key="ctrl+q", action="request_quit", description="退出"), - Binding(key="ctrl+s", action="settings", description="设置"), - Binding(key="ctrl+r", action="reset_conversation", description="重置对话"), - Binding(key="ctrl+t", action="choose_agent", description="选择智能体"), - Binding(key="ctrl+c", action="cancel", description="取消", priority=True), - Binding(key="tab", action="toggle_focus", description="切换焦点"), + Binding(key="ctrl+q", action="request_quit", description=_("Quit")), + Binding(key="ctrl+s", action="settings", description=_("Settings")), + Binding(key="ctrl+r", action="reset_conversation", description=_("Reset")), + Binding(key="ctrl+t", action="choose_agent", description=_("Agent")), + Binding(key="ctrl+c", action="cancel", description=_("Cancel"), priority=True), + Binding(key="tab", action="toggle_focus", description=_("Focus")), ] class SwitchToMCPConfirm(Message): @@ -251,7 +252,7 @@ class IntelligentTerminal(App): super().__init__() # 设置应用标题 self.title = "openEuler Intelligence" - self.sub_title = f"智能命令行工具 {__version__}" + self.sub_title = _("Intelligent CLI Tool {version}").format(version=__version__) self.config_manager = ConfigManager() self.processing: bool = False # 添加保存任务的集合到类属性 @@ -367,7 +368,7 @@ class IntelligentTerminal(App): if interrupted_count > 0: # 显示中断消息 output_container = self.query_one("#output-container") - interrupt_line = OutputLine("[已取消]") + interrupt_line = OutputLine(_("[Cancelled]")) output_container.mount(interrupt_line) # 异步滚动到底部 scroll_task = asyncio.create_task(self._scroll_to_end()) @@ -571,7 +572,10 @@ class IntelligentTerminal(App): # 如果没有收到任何内容且应用仍在运行,显示错误信息 if not received_any_content and hasattr(self, "is_running") and self.is_running: output_container.mount( - OutputLine("没有收到响应,请检查网络连接或稍后重试", command=False), + OutputLine( + _("No response received, please check network connection or try again later"), + command=False, + ), ) except asyncio.CancelledError: @@ -677,14 +681,14 @@ class IntelligentTerminal(App): """检查各种超时条件,返回是否应该中断处理""" # 检查总体超时 if current_time - stream_state["start_time"] > stream_state["timeout_seconds"]: - output_container.mount(OutputLine("请求超时,已停止处理", command=False)) + output_container.mount(OutputLine(_("Request timeout, processing stopped"), command=False)) return True # 检查无内容超时 received_any_content = stream_state["received_any_content"] time_since_last_content = current_time - stream_state["last_content_time"] if received_any_content and time_since_last_content > stream_state["no_content_timeout"]: - output_container.mount(OutputLine("长时间无响应,已停止处理", command=False)) + output_container.mount(OutputLine(_("No response for a long time, processing stopped"), command=False)) return True return False @@ -712,7 +716,7 @@ class IntelligentTerminal(App): ) # 检查是否是 MCP 消息处理(返回值为 None 表示是 MCP 消息) - tool_name, _ = extract_mcp_tag(content) + tool_name, _cleaned_content = extract_mcp_tag(content) is_mcp_detected = processed_line is None and tool_name is not None # 只有当返回值不为None时才更新current_line @@ -737,7 +741,7 @@ class IntelligentTerminal(App): """处理超时错误""" self.logger.warning("Command stream timed out") if hasattr(self, "is_running") and self.is_running: - output_container.mount(OutputLine("请求超时,请稍后重试", command=False)) + output_container.mount(OutputLine(_("Request timeout, please try again later"), command=False)) return stream_state["received_any_content"] def _handle_cancelled_error(self, output_container: Container, stream_state: dict) -> bool: @@ -881,13 +885,13 @@ class IntelligentTerminal(App): # 处理 HermesAPIError 特殊情况 if hasattr(error, "status_code") and hasattr(error, "message"): if error.status_code == 500: # type: ignore[attr-defined] # noqa: PLR2004 - return f"服务端错误: {error.message}" # type: ignore[attr-defined] + return _("Server error: {message}").format(message=error.message) # type: ignore[attr-defined] if error.status_code >= 400: # type: ignore[attr-defined] # noqa: PLR2004 - return f"请求失败: {error.message}" # type: ignore[attr-defined] + return _("Request failed: {message}").format(message=error.message) # type: ignore[attr-defined] # 定义错误匹配规则和对应的用户友好消息 error_patterns = { - "网络连接异常中断,请检查网络连接后重试": [ + _("Network connection interrupted, please check network and try again"): [ "remoteprotocolerror", "server disconnected", "peer closed connection", @@ -895,11 +899,11 @@ class IntelligentTerminal(App): "connection refused", "broken pipe", ], - "请求超时,请稍后重试": [ + _("Request timeout, please try again later"): [ "timeout", "timed out", ], - "网络连接错误,请检查网络后重试": [ + _("Network connection error, please check network and try again"): [ "network", "connection", "unreachable", @@ -908,19 +912,19 @@ class IntelligentTerminal(App): "httperror", "requestserror", ], - "服务端响应异常,请稍后重试": [ + _("Server response error, please try again later"): [ "http", "status", "response", ], - "数据格式错误,请稍后重试": [ + _("Data format error, please try again later"): [ "json", "decode", "parse", "invalid", "malformed", ], - "认证失败,请检查配置": [ + _("Authentication failed, please check configuration"): [ "auth", "unauthorized", "forbidden", @@ -942,9 +946,9 @@ class IntelligentTerminal(App): "requesterror", ] ): - return "服务端响应异常,请稍后重试" + return _("Server response error, please try again later") - return f"处理命令时出错: {error!s}" + return _("Error processing command: {error}").format(error=str(error)) def _display_error_in_ui(self, error: BaseException) -> None: """在UI界面显示错误信息""" @@ -1163,10 +1167,10 @@ class IntelligentTerminal(App): ) if not success: # 如果没有收到任何响应内容,显示默认消息 - output_container.mount(OutputLine("💡 MCP 响应已发送")) + output_container.mount(OutputLine(_("💡 MCP response sent"))) else: self.logger.error("当前客户端不支持 MCP 响应功能") - output_container.mount(OutputLine("❌ 当前客户端不支持 MCP 响应功能")) + output_container.mount(OutputLine(_("❌ Current client does not support MCP response"))) except Exception as e: self.logger.exception("发送 MCP 响应失败") @@ -1174,7 +1178,9 @@ class IntelligentTerminal(App): if output_container is not None: try: error_message = self._format_error_message(e) - output_container.mount(OutputLine(f"❌ 发送 MCP 响应失败: {error_message}")) + output_container.mount( + OutputLine(_("❌ Failed to send MCP response: {error}").format(error=error_message)), + ) except Exception: # 如果连显示错误信息都失败了,至少记录日志 self.logger.exception("无法显示错误信息") @@ -1193,7 +1199,7 @@ class IntelligentTerminal(App): """处理 MCP 响应的流式回复""" if not isinstance(llm_client, HermesChatClient): self.logger.error("当前客户端不支持 MCP 响应功能") - output_container.mount(OutputLine("❌ 当前客户端不支持 MCP 响应功能")) + output_container.mount(OutputLine(_("❌ Current client does not support MCP response"))) return False # 使用统一的流状态管理,与 _handle_command_stream 保持一致 @@ -1219,7 +1225,7 @@ class IntelligentTerminal(App): break # 判断是否为 LLM 输出内容 - tool_name, _ = extract_mcp_tag(content) + tool_name, _cleaned_content = extract_mcp_tag(content) is_llm_output = tool_name is None # 处理内容 @@ -1239,10 +1245,12 @@ class IntelligentTerminal(App): return await asyncio.wait_for(_process_stream(), timeout=timeout_seconds) except TimeoutError: - output_container.mount(OutputLine(f"⏱️ MCP 响应超时 ({timeout_seconds}秒)")) + output_container.mount( + OutputLine(_("⏱️ MCP response timeout ({seconds} seconds)").format(seconds=timeout_seconds)), + ) return stream_state["received_any_content"] except asyncio.CancelledError: - output_container.mount(OutputLine("🚫 MCP 响应被取消")) + output_container.mount(OutputLine(_("🚫 MCP response cancelled"))) raise def _get_initial_agent(self) -> tuple[str, str]: @@ -1325,8 +1333,8 @@ class IntelligentTerminal(App): def _show_config_validation_notification(self) -> None: """显示配置验证失败的通知""" self.notify( - "后端配置验证失败,请检查并修改配置", - title="配置错误", + _("Backend configuration validation failed, please check and modify"), + title=_("Configuration Error"), severity="error", timeout=1, ) diff --git a/src/config/model.py b/src/config/model.py index aef1e7b489801aa86112b8612d30924f9efe70d5..ab986c4ea5db06ac56ca773a05551be75bd3fcff 100644 --- a/src/config/model.py +++ b/src/config/model.py @@ -84,7 +84,7 @@ class ConfigModel: openai: OpenAIConfig = field(default_factory=OpenAIConfig) eulerintelli: HermesConfig = field(default_factory=HermesConfig) log_level: LogLevel = field(default=LogLevel.DEBUG) - locale: str = field(default="en_US") # 默认语言为英语 + locale: str = field(default="") # 空字符串表示自动检测系统语言 @classmethod def from_dict(cls, d: dict) -> "ConfigModel": @@ -115,7 +115,7 @@ class ConfigModel: openai=OpenAIConfig.from_dict(d.get("openai", {})), eulerintelli=HermesConfig.from_dict(d.get("eulerintelli", {})), log_level=log_level, - locale=d.get("locale", "en_US"), + locale=d.get("locale", ""), # 空字符串表示自动检测 ) def to_dict(self) -> dict: diff --git a/src/i18n/locales/en_US/LC_MESSAGES/messages.po b/src/i18n/locales/en_US/LC_MESSAGES/messages.po index 991491c6a4d679eb98ecf5b39c12e25b18b83b23..f3065712dc48abe5cb684e38f27e6d01c3567ab9 100644 --- a/src/i18n/locales/en_US/LC_MESSAGES/messages.po +++ b/src/i18n/locales/en_US/LC_MESSAGES/messages.po @@ -1,13 +1,13 @@ -# English translations for smart-shell package. +# English translations for oi-cli package. # Copyright (C) 2025 openEuler Intelligence Project -# This file is distributed under the same license as the smart-shell package. +# This file is distributed under the same license as the oi-cli package. # msgid "" msgstr "" -"Project-Id-Version: smart-shell\n" +"Project-Id-Version: oi-cli\n" "Report-Msgid-Bugs-To: contact@openeuler.org\n" -"POT-Creation-Date: 2025-10-17 17:39+0800\n" -"PO-Revision-Date: 2025-01-17 00:00+0000\n" +"POT-Creation-Date: 2025-10-21 09:54+0800\n" +"PO-Revision-Date: 2025-10-20 19:28+0800\n" "Last-Translator: openEuler Intelligence Team\n" "Language-Team: English\n" "Language: en_US\n" @@ -15,6 +15,268 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" +"X-Generator: Poedit 3.8\n" + +#: src/app/mcp_widgets.py:47 +msgid "需要用户确认是否执行此工具" +msgstr "User confirmation required to execute this tool" + +#: src/app/mcp_widgets.py:51 +msgid "低风险" +msgstr "Low risk" + +#: src/app/mcp_widgets.py:52 +msgid "中等风险" +msgstr "Medium risk" + +#: src/app/mcp_widgets.py:53 +msgid "高风险" +msgstr "High risk" + +#: src/app/mcp_widgets.py:54 +msgid "未知风险" +msgstr "Unknown risk" + +#: src/app/mcp_widgets.py:81 +msgid "✓ 确认" +msgstr "✓ Confirm" + +#: src/app/mcp_widgets.py:82 src/app/mcp_widgets.py:201 +msgid "✗ 取消" +msgstr "✗ Cancel" + +#: src/app/mcp_widgets.py:164 +msgid "需要补充参数" +msgstr "Parameters required" + +#: src/app/mcp_widgets.py:169 +msgid "📝 参数输入" +msgstr "📝 Parameter Input" + +#: src/app/mcp_widgets.py:181 +#, python-brace-format +msgid "请输入 {param_name}" +msgstr "Please enter {param_name}" + +#: src/app/mcp_widgets.py:191 +msgid "补充说明(可选)" +msgstr "Additional notes (optional)" + +#: src/app/mcp_widgets.py:200 +msgid "✓ 提交" +msgstr "✓ Submit" + +#: src/app/settings.py:63 +msgid "设置" +msgstr "Settings" + +#: src/app/settings.py:66 +msgid "后端:" +msgstr "Backend:" + +#: src/app/settings.py:76 +msgid "Base URL:" +msgstr "Base URL:" + +#: src/app/settings.py:88 +msgid "API Key:" +msgstr "API Key:" + +#: src/app/settings.py:95 +msgid "API 访问密钥,可选" +msgstr "API access key, optional" + +#: src/app/settings.py:103 src/app/settings.py:239 +msgid "模型:" +msgstr "Model:" + +#: src/app/settings.py:108 src/app/settings.py:244 +msgid "模型名称,可选" +msgstr "Model name, optional" + +#: src/app/settings.py:117 src/app/settings.py:272 +msgid "MCP 工具授权:" +msgstr "MCP Tool Authorization:" + +#: src/app/settings.py:119 src/app/settings.py:174 src/app/settings.py:274 +#: src/app/settings.py:549 src/app/settings.py:555 +msgid "自动执行" +msgstr "Auto Execute" + +#: src/app/settings.py:119 src/app/settings.py:174 src/app/settings.py:181 +#: src/app/settings.py:274 src/app/settings.py:549 src/app/settings.py:555 +msgid "手动确认" +msgstr "Manual Confirm" + +#: src/app/settings.py:133 +msgid "保存" +msgstr "Save" + +#: src/app/settings.py:134 src/app/dialogs/common.py:27 +msgid "取消" +msgstr "Cancel" + +#: src/app/settings.py:437 +msgid "Base URL 不能为空" +msgstr "Base URL cannot be empty" + +#: src/app/settings.py:534 +msgid "切换中..." +msgstr "Switching..." + +#: src/app/tui.py:217 +msgid "Enter command or question..." +msgstr "Enter question or command..." + +#: src/app/tui.py:226 +msgid "Quit" +msgstr "Quit" + +#: src/app/tui.py:227 +msgid "Settings" +msgstr "Settings" + +#: src/app/tui.py:228 +msgid "Reset" +msgstr "Reset Conversation" + +#: src/app/tui.py:229 +msgid "Agent" +msgstr "Select Agent" + +#: src/app/tui.py:230 +msgid "Cancel" +msgstr "Cancel" + +#: src/app/tui.py:231 +msgid "Focus" +msgstr "Toggle Focus" + +#: src/app/tui.py:255 +#, python-brace-format +msgid "Intelligent CLI Tool {version}" +msgstr "Command Line Tool {version}" + +#: src/app/tui.py:371 +msgid "[Cancelled]" +msgstr "[Cancelled]" + +#: src/app/tui.py:576 +msgid "" +"No response received, please check network connection or try again later" +msgstr "" +"No response received, please check network connection or try again later" + +#: src/app/tui.py:684 +msgid "Request timeout, processing stopped" +msgstr "Request timeout, processing stopped" + +#: src/app/tui.py:691 +msgid "No response for a long time, processing stopped" +msgstr "No response for a long time, processing stopped" + +#: src/app/tui.py:744 src/app/tui.py:902 +msgid "Request timeout, please try again later" +msgstr "Request timeout, please try again later" + +#: src/app/tui.py:888 +#, python-brace-format +msgid "Server error: {message}" +msgstr "Server error: {message}" + +#: src/app/tui.py:890 +#, python-brace-format +msgid "Request failed: {message}" +msgstr "Request failed: {message}" + +#: src/app/tui.py:894 +msgid "Network connection interrupted, please check network and try again" +msgstr "Network connection interrupted, please check network and try again" + +#: src/app/tui.py:906 +msgid "Network connection error, please check network and try again" +msgstr "Network connection error, please check network and try again" + +#: src/app/tui.py:915 src/app/tui.py:949 +msgid "Server response error, please try again later" +msgstr "Server response error, please try again later" + +#: src/app/tui.py:920 +msgid "Data format error, please try again later" +msgstr "Data format error, please try again later" + +#: src/app/tui.py:927 +msgid "Authentication failed, please check configuration" +msgstr "Authentication failed, please check configuration" + +#: src/app/tui.py:951 +#, python-brace-format +msgid "Error processing command: {error}" +msgstr "Processing command failed with error: {error}" + +#: src/app/tui.py:1170 +msgid "💡 MCP response sent" +msgstr "💡 MCP response sent" + +#: src/app/tui.py:1173 src/app/tui.py:1202 +msgid "❌ Current client does not support MCP response" +msgstr "❌ Current client does not support MCP response" + +#: src/app/tui.py:1182 +#, python-brace-format +msgid "❌ Failed to send MCP response: {error}" +msgstr "❌ Failed to send MCP response: {error}" + +#: src/app/tui.py:1249 +#, python-brace-format +msgid "⏱️ MCP response timeout ({seconds} seconds)" +msgstr "⏱️ MCP response timeout ({seconds} seconds)" + +#: src/app/tui.py:1253 +msgid "🚫 MCP response cancelled" +msgstr "🚫 MCP response cancelled" + +#: src/app/tui.py:1336 +msgid "Backend configuration validation failed, please check and modify" +msgstr "Backend configuration validation failed, please check and modify" + +#: src/app/tui.py:1337 +msgid "Configuration Error" +msgstr "Configuration Error" + +#: src/app/dialogs/common.py:25 +msgid "确认退出吗?" +msgstr "Are you sure you want to exit?" + +#: src/app/dialogs/common.py:28 +msgid "确认" +msgstr "Confirm" + +#: src/app/dialogs/agent.py:27 +msgid "智能体功能提示" +msgstr "Agent Feature Notification" + +#: src/app/dialogs/agent.py:28 +msgid "请选择 openEuler Intelligence 后端来使用智能体功能" +msgstr "Please select openEuler Intelligence backend to use agent features" + +#: src/app/dialogs/agent.py:29 +msgid "按任意键关闭" +msgstr "Press any key to close" + +#: src/app/dialogs/agent.py:60 src/app/dialogs/agent.py:130 +#: src/app/dialogs/agent.py:185 src/app/dialogs/agent.py:205 +#: src/app/dialogs/agent.py:208 +msgid "智能问答" +msgstr "Smart Chat" + +#: src/app/dialogs/agent.py:113 +msgid "OS 智能助手" +msgstr "OS Smart Assistant" + +#: src/app/dialogs/agent.py:115 +msgid "使用上下键选择,回车确认,ESC取消 | ✓ 表示当前选中" +msgstr "Use arrow keys to select, Enter to confirm, ESC to cancel | ✓ indicates current selection" #: src/main.py:28 msgid "openEuler Intelligence - Intelligent command-line tool" @@ -157,16 +419,16 @@ msgstr "✓ Log level successfully set to: {level}\n" msgid "✓ Logging system initialized\n" msgstr "✓ Logging system initialized\n" -#: src/main.py:181 +#: src/main.py:191 #, python-brace-format msgid "✓ Language set to: {locale}\n" msgstr "✓ Language set to: {locale}\n" -#: src/main.py:183 +#: src/main.py:193 #, python-brace-format msgid "✗ Unsupported language: {locale}\n" msgstr "✗ Unsupported language: {locale}\n" -#: src/main.py:218 +#: src/main.py:228 msgid "Fatal error in Intelligent Shell application" msgstr "Fatal error in Intelligent Shell application" diff --git a/src/i18n/locales/messages.pot b/src/i18n/locales/messages.pot index 3545d8e97bced0e5a3603e16c3312e15187898c9..19f1cd4c32c12838865b58bf2c52bdc8f7a254ba 100644 --- a/src/i18n/locales/messages.pot +++ b/src/i18n/locales/messages.pot @@ -1,14 +1,14 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR openEuler Intelligence Project -# This file is distributed under the same license as the smart-shell package. +# This file is distributed under the same license as the oi-cli package. # FIRST AUTHOR , YEAR. # #, fuzzy msgid "" msgstr "" -"Project-Id-Version: smart-shell 0.10.2\n" +"Project-Id-Version: oi-cli 0.10.2\n" "Report-Msgid-Bugs-To: contact@openeuler.org\n" -"POT-Creation-Date: 2025-10-17 17:39+0800\n" +"POT-Creation-Date: 2025-10-21 09:54+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -17,6 +17,266 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" +#: src/app/mcp_widgets.py:47 +msgid "需要用户确认是否执行此工具" +msgstr "" + +#: src/app/mcp_widgets.py:51 +msgid "低风险" +msgstr "" + +#: src/app/mcp_widgets.py:52 +msgid "中等风险" +msgstr "" + +#: src/app/mcp_widgets.py:53 +msgid "高风险" +msgstr "" + +#: src/app/mcp_widgets.py:54 +msgid "未知风险" +msgstr "" + +#: src/app/mcp_widgets.py:81 +msgid "✓ 确认" +msgstr "" + +#: src/app/mcp_widgets.py:82 src/app/mcp_widgets.py:201 +msgid "✗ 取消" +msgstr "" + +#: src/app/mcp_widgets.py:164 +msgid "需要补充参数" +msgstr "" + +#: src/app/mcp_widgets.py:169 +msgid "📝 参数输入" +msgstr "" + +#: src/app/mcp_widgets.py:181 +#, python-brace-format +msgid "请输入 {param_name}" +msgstr "" + +#: src/app/mcp_widgets.py:191 +msgid "补充说明(可选)" +msgstr "" + +#: src/app/mcp_widgets.py:200 +msgid "✓ 提交" +msgstr "" + +#: src/app/settings.py:63 +msgid "设置" +msgstr "" + +#: src/app/settings.py:66 +msgid "后端:" +msgstr "" + +#: src/app/settings.py:76 +msgid "Base URL:" +msgstr "" + +#: src/app/settings.py:88 +msgid "API Key:" +msgstr "" + +#: src/app/settings.py:95 +msgid "API 访问密钥,可选" +msgstr "" + +#: src/app/settings.py:103 src/app/settings.py:239 +msgid "模型:" +msgstr "" + +#: src/app/settings.py:108 src/app/settings.py:244 +msgid "模型名称,可选" +msgstr "" + +#: src/app/settings.py:117 src/app/settings.py:272 +msgid "MCP 工具授权:" +msgstr "" + +#: src/app/settings.py:119 src/app/settings.py:174 src/app/settings.py:274 +#: src/app/settings.py:549 src/app/settings.py:555 +msgid "自动执行" +msgstr "" + +#: src/app/settings.py:119 src/app/settings.py:174 src/app/settings.py:181 +#: src/app/settings.py:274 src/app/settings.py:549 src/app/settings.py:555 +msgid "手动确认" +msgstr "" + +#: src/app/settings.py:133 +msgid "保存" +msgstr "" + +#: src/app/settings.py:134 src/app/dialogs/common.py:27 +msgid "取消" +msgstr "" + +#: src/app/settings.py:437 +msgid "Base URL 不能为空" +msgstr "" + +#: src/app/settings.py:534 +msgid "切换中..." +msgstr "" + +#: src/app/tui.py:217 +msgid "Enter command or question..." +msgstr "" + +#: src/app/tui.py:226 +msgid "Quit" +msgstr "" + +#: src/app/tui.py:227 +msgid "Settings" +msgstr "" + +#: src/app/tui.py:228 +msgid "Reset" +msgstr "" + +#: src/app/tui.py:229 +msgid "Agent" +msgstr "" + +#: src/app/tui.py:230 +msgid "Cancel" +msgstr "" + +#: src/app/tui.py:231 +msgid "Focus" +msgstr "" + +#: src/app/tui.py:255 +#, python-brace-format +msgid "Intelligent CLI Tool {version}" +msgstr "" + +#: src/app/tui.py:371 +msgid "[Cancelled]" +msgstr "" + +#: src/app/tui.py:576 +msgid "" +"No response received, please check network connection or try again later" +msgstr "" + +#: src/app/tui.py:684 +msgid "Request timeout, processing stopped" +msgstr "" + +#: src/app/tui.py:691 +msgid "No response for a long time, processing stopped" +msgstr "" + +#: src/app/tui.py:744 src/app/tui.py:902 +msgid "Request timeout, please try again later" +msgstr "" + +#: src/app/tui.py:888 +#, python-brace-format +msgid "Server error: {message}" +msgstr "" + +#: src/app/tui.py:890 +#, python-brace-format +msgid "Request failed: {message}" +msgstr "" + +#: src/app/tui.py:894 +msgid "Network connection interrupted, please check network and try again" +msgstr "" + +#: src/app/tui.py:906 +msgid "Network connection error, please check network and try again" +msgstr "" + +#: src/app/tui.py:915 src/app/tui.py:949 +msgid "Server response error, please try again later" +msgstr "" + +#: src/app/tui.py:920 +msgid "Data format error, please try again later" +msgstr "" + +#: src/app/tui.py:927 +msgid "Authentication failed, please check configuration" +msgstr "" + +#: src/app/tui.py:951 +#, python-brace-format +msgid "Error processing command: {error}" +msgstr "" + +#: src/app/tui.py:1170 +msgid "💡 MCP response sent" +msgstr "" + +#: src/app/tui.py:1173 src/app/tui.py:1202 +msgid "❌ Current client does not support MCP response" +msgstr "" + +#: src/app/tui.py:1182 +#, python-brace-format +msgid "❌ Failed to send MCP response: {error}" +msgstr "" + +#: src/app/tui.py:1249 +#, python-brace-format +msgid "⏱️ MCP response timeout ({seconds} seconds)" +msgstr "" + +#: src/app/tui.py:1253 +msgid "🚫 MCP response cancelled" +msgstr "" + +#: src/app/tui.py:1336 +msgid "Backend configuration validation failed, please check and modify" +msgstr "" + +#: src/app/tui.py:1337 +msgid "Configuration Error" +msgstr "" + +#: src/app/dialogs/common.py:25 +msgid "确认退出吗?" +msgstr "" + +#: src/app/dialogs/common.py:28 +msgid "确认" +msgstr "" + +#: src/app/dialogs/agent.py:27 +msgid "智能体功能提示" +msgstr "" + +#: src/app/dialogs/agent.py:28 +msgid "请选择 openEuler Intelligence 后端来使用智能体功能" +msgstr "" + +#: src/app/dialogs/agent.py:29 +msgid "按任意键关闭" +msgstr "" + +#: src/app/dialogs/agent.py:60 src/app/dialogs/agent.py:130 +#: src/app/dialogs/agent.py:185 src/app/dialogs/agent.py:205 +#: src/app/dialogs/agent.py:208 +msgid "智能问答" +msgstr "" + +#: src/app/dialogs/agent.py:113 +msgid "OS 智能助手" +msgstr "" + +#: src/app/dialogs/agent.py:115 +msgid "使用上下键选择,回车确认,ESC取消 | ✓ 表示当前选中" +msgstr "" + #: src/main.py:28 msgid "openEuler Intelligence - Intelligent command-line tool" msgstr "" @@ -148,16 +408,16 @@ msgstr "" msgid "✓ Logging system initialized\n" msgstr "" -#: src/main.py:181 +#: src/main.py:191 #, python-brace-format msgid "✓ Language set to: {locale}\n" msgstr "" -#: src/main.py:183 +#: src/main.py:193 #, python-brace-format msgid "✗ Unsupported language: {locale}\n" msgstr "" -#: src/main.py:218 +#: src/main.py:228 msgid "Fatal error in Intelligent Shell application" msgstr "" diff --git a/src/i18n/locales/zh_CN/LC_MESSAGES/messages.po b/src/i18n/locales/zh_CN/LC_MESSAGES/messages.po index a52bf853d0256ed052df6e6a782b10f52dbe5c5f..ea8ef32e3a4024a92fb1491f92b8bb1f73657636 100644 --- a/src/i18n/locales/zh_CN/LC_MESSAGES/messages.po +++ b/src/i18n/locales/zh_CN/LC_MESSAGES/messages.po @@ -1,13 +1,13 @@ -# Simplified Chinese translations for smart-shell package. +# Simplified Chinese translations for oi-cli package. # Copyright (C) 2025 openEuler Intelligence Project -# This file is distributed under the same license as the smart-shell package. +# This file is distributed under the same license as the oi-cli package. # msgid "" msgstr "" -"Project-Id-Version: smart-shell\n" +"Project-Id-Version: oi-cli\n" "Report-Msgid-Bugs-To: contact@openeuler.org\n" -"POT-Creation-Date: 2025-10-17 17:39+0800\n" -"PO-Revision-Date: 2025-01-17 00:00+0000\n" +"POT-Creation-Date: 2025-10-21 09:54+0800\n" +"PO-Revision-Date: 2025-10-21 09:40+0800\n" "Last-Translator: openEuler Intelligence Team\n" "Language-Team: Chinese (Simplified)\n" "Language: zh_CN\n" @@ -15,6 +15,267 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" +"X-Generator: Poedit 3.8\n" + +#: src/app/mcp_widgets.py:47 +msgid "需要用户确认是否执行此工具" +msgstr "需要用户确认是否执行此工具" + +#: src/app/mcp_widgets.py:51 +msgid "低风险" +msgstr "低风险" + +#: src/app/mcp_widgets.py:52 +msgid "中等风险" +msgstr "中等风险" + +#: src/app/mcp_widgets.py:53 +msgid "高风险" +msgstr "高风险" + +#: src/app/mcp_widgets.py:54 +msgid "未知风险" +msgstr "未知风险" + +#: src/app/mcp_widgets.py:81 +msgid "✓ 确认" +msgstr "✓ 确认" + +#: src/app/mcp_widgets.py:82 src/app/mcp_widgets.py:201 +msgid "✗ 取消" +msgstr "✗ 取消" + +#: src/app/mcp_widgets.py:164 +msgid "需要补充参数" +msgstr "需要补充参数" + +#: src/app/mcp_widgets.py:169 +msgid "📝 参数输入" +msgstr "📝 参数输入" + +#: src/app/mcp_widgets.py:181 +#, python-brace-format +msgid "请输入 {param_name}" +msgstr "请输入 {param_name}" + +#: src/app/mcp_widgets.py:191 +msgid "补充说明(可选)" +msgstr "补充说明(可选)" + +#: src/app/mcp_widgets.py:200 +msgid "✓ 提交" +msgstr "✓ 提交" + +#: src/app/settings.py:63 +msgid "设置" +msgstr "设置" + +#: src/app/settings.py:66 +msgid "后端:" +msgstr "后端:" + +#: src/app/settings.py:76 +msgid "Base URL:" +msgstr "基础 URL:" + +#: src/app/settings.py:88 +msgid "API Key:" +msgstr "API 密钥:" + +#: src/app/settings.py:95 +msgid "API 访问密钥,可选" +msgstr "API 访问密钥,可选" + +#: src/app/settings.py:103 src/app/settings.py:239 +msgid "模型:" +msgstr "模型:" + +#: src/app/settings.py:108 src/app/settings.py:244 +msgid "模型名称,可选" +msgstr "模型名称,可选" + +#: src/app/settings.py:117 src/app/settings.py:272 +msgid "MCP 工具授权:" +msgstr "MCP 工具授权:" + +#: src/app/settings.py:119 src/app/settings.py:174 src/app/settings.py:274 +#: src/app/settings.py:549 src/app/settings.py:555 +msgid "自动执行" +msgstr "自动执行" + +#: src/app/settings.py:119 src/app/settings.py:174 src/app/settings.py:181 +#: src/app/settings.py:274 src/app/settings.py:549 src/app/settings.py:555 +msgid "手动确认" +msgstr "手动确认" + +#: src/app/settings.py:133 +msgid "保存" +msgstr "保存" + +#: src/app/settings.py:134 src/app/dialogs/common.py:27 +msgid "取消" +msgstr "取消" + +#: src/app/settings.py:437 +msgid "Base URL 不能为空" +msgstr "基础 URL 不能为空" + +#: src/app/settings.py:534 +msgid "切换中..." +msgstr "切换中..." + +#: src/app/tui.py:217 +msgid "Enter command or question..." +msgstr "输入命令或问题..." + +#: src/app/tui.py:226 +msgid "Quit" +msgstr "退出" + +#: src/app/tui.py:227 +msgid "Settings" +msgstr "设置" + +#: src/app/tui.py:228 +msgid "Reset" +msgstr "重置对话" + +#: src/app/tui.py:229 +msgid "Agent" +msgstr "选择智能体" + +#: src/app/tui.py:230 +msgid "Cancel" +msgstr "取消" + +#: src/app/tui.py:231 +msgid "Focus" +msgstr "切换焦点" + +#: src/app/tui.py:255 +#, python-brace-format +msgid "Intelligent CLI Tool {version}" +msgstr "智能命令行工具 {version}" + +#: src/app/tui.py:371 +msgid "[Cancelled]" +msgstr "[已取消]" + +#: src/app/tui.py:576 +msgid "" +"No response received, please check network connection or try again later" +msgstr "没有收到响应,请检查网络连接或稍后重试" + +#: src/app/tui.py:684 +msgid "Request timeout, processing stopped" +msgstr "请求超时,已停止处理" + +#: src/app/tui.py:691 +msgid "No response for a long time, processing stopped" +msgstr "长时间无响应,已停止处理" + +#: src/app/tui.py:744 src/app/tui.py:902 +msgid "Request timeout, please try again later" +msgstr "请求超时,请稍后重试" + +#: src/app/tui.py:888 +#, python-brace-format +msgid "Server error: {message}" +msgstr "服务端错误: {message}" + +#: src/app/tui.py:890 +#, python-brace-format +msgid "Request failed: {message}" +msgstr "请求失败: {message}" + +#: src/app/tui.py:894 +msgid "Network connection interrupted, please check network and try again" +msgstr "网络连接异常中断,请检查网络连接后重试" + +#: src/app/tui.py:906 +msgid "Network connection error, please check network and try again" +msgstr "网络连接错误,请检查网络后重试" + +#: src/app/tui.py:915 src/app/tui.py:949 +msgid "Server response error, please try again later" +msgstr "服务端响应异常,请稍后重试" + +#: src/app/tui.py:920 +msgid "Data format error, please try again later" +msgstr "数据格式错误,请稍后重试" + +#: src/app/tui.py:927 +msgid "Authentication failed, please check configuration" +msgstr "认证失败,请检查配置" + +#: src/app/tui.py:951 +#, python-brace-format +msgid "Error processing command: {error}" +msgstr "处理命令时出错: {error}" + +#: src/app/tui.py:1170 +msgid "💡 MCP response sent" +msgstr "💡 MCP 响应已发送" + +#: src/app/tui.py:1173 src/app/tui.py:1202 +msgid "❌ Current client does not support MCP response" +msgstr "❌ 当前客户端不支持 MCP 响应功能" + +#: src/app/tui.py:1182 +#, python-brace-format +msgid "❌ Failed to send MCP response: {error}" +msgstr "❌ 发送 MCP 响应失败: {error}" + +#: src/app/tui.py:1249 +#, python-brace-format +msgid "⏱️ MCP response timeout ({seconds} seconds)" +msgstr "⏱️ MCP 响应超时 ({seconds}秒)" + +#: src/app/tui.py:1253 +msgid "🚫 MCP response cancelled" +msgstr "🚫 MCP 响应被取消" + +#: src/app/tui.py:1336 +msgid "Backend configuration validation failed, please check and modify" +msgstr "后端配置验证失败,请检查并修改配置" + +#: src/app/tui.py:1337 +msgid "Configuration Error" +msgstr "配置错误" + +#: src/app/dialogs/common.py:25 +msgid "确认退出吗?" +msgstr "确认退出吗?" + +#: src/app/dialogs/common.py:28 +msgid "确认" +msgstr "确认" + +#: src/app/dialogs/agent.py:27 +msgid "智能体功能提示" +msgstr "智能体功能提示" + +#: src/app/dialogs/agent.py:28 +msgid "请选择 openEuler Intelligence 后端来使用智能体功能" +msgstr "请选择 openEuler Intelligence 后端来使用智能体功能" + +#: src/app/dialogs/agent.py:29 +msgid "按任意键关闭" +msgstr "按任意键关闭" + +#: src/app/dialogs/agent.py:60 src/app/dialogs/agent.py:130 +#: src/app/dialogs/agent.py:185 src/app/dialogs/agent.py:205 +#: src/app/dialogs/agent.py:208 +msgid "智能问答" +msgstr "智能问答" + +#: src/app/dialogs/agent.py:113 +msgid "OS 智能助手" +msgstr "OS 智能助手" + +#: src/app/dialogs/agent.py:115 +msgid "使用上下键选择,回车确认,ESC取消 | ✓ 表示当前选中" +msgstr "使用上下键选择,回车确认,ESC取消 | ✓ 表示当前选中" #: src/main.py:28 msgid "openEuler Intelligence - Intelligent command-line tool" @@ -155,16 +416,16 @@ msgstr "✓ 日志级别已成功设置为: {level}\n" msgid "✓ Logging system initialized\n" msgstr "✓ 日志系统初始化完成\n" -#: src/main.py:181 +#: src/main.py:191 #, python-brace-format msgid "✓ Language set to: {locale}\n" msgstr "✓ 语言已设置为: {locale}\n" -#: src/main.py:183 +#: src/main.py:193 #, python-brace-format msgid "✗ Unsupported language: {locale}\n" msgstr "✗ 不支持的语言: {locale}\n" -#: src/main.py:218 +#: src/main.py:228 msgid "Fatal error in Intelligent Shell application" msgstr "智能 Shell 应用发生致命错误" diff --git a/src/i18n/manager.py b/src/i18n/manager.py index b4d682896ff9daf0ad78e4ecc8524728be9a4b90..7a04747ed0c33106d5cfe86b87a73f1bb5b81203 100644 --- a/src/i18n/manager.py +++ b/src/i18n/manager.py @@ -95,6 +95,8 @@ class I18nManager: if system_locale: # 标准化语言代码 (如 zh_CN.UTF-8 -> zh_CN) locale_code = system_locale.split(".")[0] + if locale_code.startswith("zh"): + locale_code = "zh_CN" if locale_code in SUPPORTED_LOCALES: return locale_code except (ValueError, TypeError, locale.Error): diff --git a/src/main.py b/src/main.py index 9d0378f72b829a9142f0fa16ea6eb3f26df45f38..85857671320908aec2c12a929fa7127e886b2a35 100644 --- a/src/main.py +++ b/src/main.py @@ -9,7 +9,7 @@ from __version__ import __version__ from app.tui import IntelligentTerminal from config.manager import ConfigManager from config.model import LogLevel -from i18n.manager import _, get_supported_locales, init_i18n, set_locale +from i18n.manager import _, get_locale, get_supported_locales, init_i18n, set_locale from log.manager import ( cleanup_empty_logs, disable_console_output, @@ -168,8 +168,18 @@ def main() -> None: # 首先初始化配置管理器 config_manager = ConfigManager() - # 初始化国际化系统 - 使用配置中的语言设置 - init_i18n(config_manager.get_locale()) + # 初始化国际化系统 + # 如果配置中没有设置语言(空字符串),则自动检测系统语言 + configured_locale = config_manager.get_locale() + if configured_locale: + # 使用用户配置的语言 + init_i18n(configured_locale) + else: + # 自动检测系统语言 + init_i18n(None) + # 保存检测到的语言到配置中 + detected_locale = get_locale() + config_manager.set_locale(detected_locale) # 解析命令行参数(需要在初始化 i18n 后进行,以支持翻译) args = parse_args()