From 3ceb5a7b068c9256867edd8eba96b4d1ef75ce96 Mon Sep 17 00:00:00 2001 From: Kirigaya <1193466151@qq.com> Date: Mon, 9 Jun 2025 17:54:50 +0800 Subject: [PATCH] =?UTF-8?q?=E6=94=AF=E6=8C=81=E5=85=B6=E4=BB=96=E8=AF=AD?= =?UTF-8?q?=E8=A8=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .vscode/settings.json | 7 +-- CHANGELOG.md | 1 + README.md | 2 - l10n/bundle.l10n.en.json | 17 ++++++ l10n/bundle.l10n.ja.json | 17 ++++++ l10n/bundle.l10n.zh-cn.json | 17 ++++++ package.json | 35 +++++++------ package.nls.ja.json | 17 ++++++ package.nls.json | 17 ++++++ package.nls.zh-cn.json | 17 ++++++ renderer/src/i18n/ar.json | 16 +++++- renderer/src/i18n/de.json | 16 +++++- renderer/src/i18n/fr.json | 16 +++++- renderer/src/i18n/ko.json | 16 +++++- renderer/src/i18n/ru.json | 16 +++++- renderer/src/i18n/zh-tw.json | 16 +++++- scripts/package-i18n-token.py | 87 +++++++++++++++++++++++++++++++ src/extension.ts | 2 + src/i18n/index.ts | 26 +++++++++ src/sidebar/help.controller.ts | 11 ++-- src/sidebar/installed.service.ts | 45 +++++++++------- src/sidebar/workspace.service.ts | 48 ++++++++--------- src/webview/webview.controller.ts | 3 +- 23 files changed, 385 insertions(+), 80 deletions(-) create mode 100644 l10n/bundle.l10n.en.json create mode 100644 l10n/bundle.l10n.ja.json create mode 100644 l10n/bundle.l10n.zh-cn.json create mode 100644 package.nls.ja.json create mode 100644 package.nls.json create mode 100644 package.nls.zh-cn.json create mode 100644 scripts/package-i18n-token.py create mode 100644 src/i18n/index.ts diff --git a/.vscode/settings.json b/.vscode/settings.json index 3bdf72f..37d3eaf 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -11,9 +11,6 @@ // Turn off tsc task auto detection since we have the necessary tasks as npm scripts "typescript.tsc.autoDetect": "off", - "i18n-haru.root": "renderer/src/i18n", - "i18n-haru.main": "zh", - "i18n-ally.localesPaths": [ - "renderer/src/i18n" - ] + "i18n-haru.root": "l10n", + "i18n-haru.main": "zh" } diff --git a/CHANGELOG.md b/CHANGELOG.md index 2bdf30c..91cee7f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ - 调试结果的工作区从 .vscode 迁移到 .openmcp,连接配置文件从 .vscode/openmcp_connection.json 迁移到 .openmcp/connection.json - 技术栈更新:openmcp 全链路组件切换为 esm - 优化引导界面文字布局。 +- 文档和软件本体支持其他国家语言。 ## [main] 0.1.4 - 重新实现 openai 协议的底层网络实现,从而支持 Google Gemini 全系列模型。 diff --git a/README.md b/README.md index d35e3d8..7491810 100644 --- a/README.md +++ b/README.md @@ -12,8 +12,6 @@ - - ## OpenMCP 一款用于 MCP 服务端调试的一体化 vscode/trae/cursor 插件。 diff --git a/l10n/bundle.l10n.en.json b/l10n/bundle.l10n.en.json new file mode 100644 index 0000000..679c124 --- /dev/null +++ b/l10n/bundle.l10n.en.json @@ -0,0 +1,17 @@ +{ + "ensure-delete-connection": "Are you sure you want to delete connection {0}?", + "confirm": "OK", + "choose-connection-type": "Please select the connection type", + "please-enter-connection-command": "Please enter the connection command", + "example-mcp-run": "For example: mcp run main.py", + "please-enter-cwd": "Please enter the working directory (cwd), optional", + "please-enter-cwd-placeholder": "For example: /path/to/project", + "please-enter-url": "Please enter the connection URL", + "example-as": "For example:", + "enter-optional-oauth": "Please enter the OAuth token, optional", + "quick-start": "Getting Started", + "read-document": "Read documentation", + "report-issue": "Report a problem", + "join-project": "Participate in the project", + "comment-plugin": "Comment Plugin" +} \ No newline at end of file diff --git a/l10n/bundle.l10n.ja.json b/l10n/bundle.l10n.ja.json new file mode 100644 index 0000000..1b2f359 --- /dev/null +++ b/l10n/bundle.l10n.ja.json @@ -0,0 +1,17 @@ +{ + "ensure-delete-connection": "接続 {0} を削除してもよろしいですか?", + "confirm": "確定", + "choose-connection-type": "接続タイプを選択してください", + "please-enter-connection-command": "接続コマンドを入力してください", + "example-mcp-run": "例: mcp run main.py", + "please-enter-cwd": "作業ディレクトリ (cwd) を入力してください (オプション)", + "please-enter-cwd-placeholder": "例: /path/to/project", + "please-enter-url": "接続URLを入力してください", + "example-as": "例えば:", + "enter-optional-oauth": "OAuthトークンを入力してください(任意)", + "quick-start": "はじめに", + "read-document": "ドキュメントを読む", + "report-issue": "問題を報告", + "join-project": "プロジェクトに参加する", + "comment-plugin": "コメントプラグイン" +} \ No newline at end of file diff --git a/l10n/bundle.l10n.zh-cn.json b/l10n/bundle.l10n.zh-cn.json new file mode 100644 index 0000000..e1eee9e --- /dev/null +++ b/l10n/bundle.l10n.zh-cn.json @@ -0,0 +1,17 @@ +{ + "ensure-delete-connection": "确定要删除连接 {0} 吗?", + "confirm": "确定", + "choose-connection-type": "请选择连接类型", + "please-enter-connection-command": "请输入连接的 command", + "example-mcp-run": "例如: mcp run main.py", + "please-enter-cwd": "请输入工作目录 (cwd),可选", + "please-enter-cwd-placeholder": "例如: /path/to/project", + "please-enter-url": "请输入连接的 URL", + "example-as": "例如:", + "enter-optional-oauth": "请输入 OAuth 令牌,可选", + "quick-start": "入门", + "read-document": "阅读文档", + "report-issue": "报告问题", + "join-project": "参与项目", + "comment-plugin": "评论插件" +} \ No newline at end of file diff --git a/package.json b/package.json index 40f36b2..a05892f 100644 --- a/package.json +++ b/package.json @@ -22,10 +22,13 @@ "main": "./dist/extension.js", "icon": "icons/openmcp.png", "contributes": { + "configuration": { + "properties": {} + }, "commands": [ { "command": "openmcp.showOpenMCP", - "title": "展示 OpenMCP", + "title": "%openmcp.showOpenMCP.title%", "category": "openmcp", "icon": { "light": "./icons/light/protocol.svg", @@ -34,7 +37,7 @@ }, { "command": "openmcp.sidebar.workspace-connection.revealWebviewPanel", - "title": "连接", + "title": "%openmcp.sidebar.workspace-connection.revealWebviewPanel.title%", "category": "openmcp", "icon": { "light": "./icons/light/protocol.svg", @@ -43,31 +46,31 @@ }, { "command": "openmcp.sidebar.workspace-connection.deleteConnection", - "title": "删除连接", + "title": "%openmcp.sidebar.workspace-connection.deleteConnection.title%", "category": "openmcp", "icon": "$(trash)" }, { "command": "openmcp.sidebar.workspace-connection.refresh", - "title": "刷新", + "title": "%openmcp.sidebar.workspace-connection.refresh.title%", "category": "openmcp", "icon": "$(refresh)" }, { "command": "openmcp.sidebar.workspace-connection.addConnection", - "title": "添加连接", + "title": "%openmcp.sidebar.workspace-connection.addConnection.title%", "category": "openmcp", "icon": "$(add)" }, { "command": "openmcp.sidebar.workspace-connection.openConfiguration", - "title": "打开配置", + "title": "%openmcp.sidebar.workspace-connection.openConfiguration.title%", "category": "openmcp", "icon": "$(gear)" }, { "command": "openmcp.sidebar.installed-connection.revealWebviewPanel", - "title": "连接", + "title": "%openmcp.sidebar.installed-connection.revealWebviewPanel.title%", "category": "openmcp", "icon": { "light": "./icons/light/protocol.svg", @@ -76,31 +79,31 @@ }, { "command": "openmcp.sidebar.installed-connection.deleteConnection", - "title": "删除连接", + "title": "%openmcp.sidebar.installed-connection.deleteConnection.title%", "category": "openmcp", "icon": "$(trash)" }, { "command": "openmcp.sidebar.installed-connection.refresh", - "title": "刷新", + "title": "%openmcp.sidebar.installed-connection.refresh.title%", "category": "openmcp", "icon": "$(refresh)" }, { "command": "openmcp.sidebar.installed-connection.addConnection", - "title": "添加连接", + "title": "%openmcp.sidebar.installed-connection.addConnection.title%", "category": "openmcp", "icon": "$(add)" }, { "command": "openmcp.sidebar.installed-connection.openConfiguration", - "title": "打开配置", + "title": "%openmcp.sidebar.installed-connection.openConfiguration.title%", "category": "openmcp", "icon": "$(gear)" }, { "command": "openmcp.hook.test-ocr", - "title": "测试 OCR", + "title": "%openmcp.hook.test-ocr.title%", "category": "openmcp", "icon": "$(test)" } @@ -194,19 +197,19 @@ { "id": "openmcp.sidebar.workspace-connection", "icon": "./icons/protocol.svg", - "name": "MCP 连接 (工作区)", + "name": "%openmcp.sidebar.workspace-connection.view.title%", "type": "tree" }, { "id": "openmcp.sidebar.installed-connection", "icon": "./icons/protocol.svg", - "name": "安装的 MCP 服务器", + "name": "%openmcp.sidebar.installed-connection.view.title%", "type": "tree" }, { "id": "openmcp.sidebar.help", "icon": "./icons/protocol.svg", - "name": "入门与帮助", + "name": "%openmcp.sidebar.help.view.title%", "type": "tree" } ] @@ -265,4 +268,4 @@ "webpack-cli": "^5.1.4" }, "packageManager": "npm@10.0.0" -} +} \ No newline at end of file diff --git a/package.nls.ja.json b/package.nls.ja.json new file mode 100644 index 0000000..176c5d2 --- /dev/null +++ b/package.nls.ja.json @@ -0,0 +1,17 @@ +{ + "openmcp.showOpenMCP.title": "OpenMCP を表示", + "openmcp.sidebar.workspace-connection.revealWebviewPanel.title": "接続", + "openmcp.sidebar.workspace-connection.deleteConnection.title": "接続を削除", + "openmcp.sidebar.workspace-connection.refresh.title": "更新", + "openmcp.sidebar.workspace-connection.addConnection.title": "接続を追加", + "openmcp.sidebar.workspace-connection.openConfiguration.title": "設定を開く", + "openmcp.sidebar.installed-connection.revealWebviewPanel.title": "接続", + "openmcp.sidebar.installed-connection.deleteConnection.title": "接続を削除", + "openmcp.sidebar.installed-connection.refresh.title": "更新", + "openmcp.sidebar.installed-connection.addConnection.title": "接続を追加", + "openmcp.sidebar.installed-connection.openConfiguration.title": "設定を開く", + "openmcp.hook.test-ocr.title": "OCR をテスト", + "openmcp.sidebar.workspace-connection.view.title": "MCP 接続(ワークスペース)", + "openmcp.sidebar.installed-connection.view.title": "インストール済み MCP サーバー", + "openmcp.sidebar.help.view.title": "はじめに・ヘルプ" +} diff --git a/package.nls.json b/package.nls.json new file mode 100644 index 0000000..8d1e9a6 --- /dev/null +++ b/package.nls.json @@ -0,0 +1,17 @@ +{ + "openmcp.showOpenMCP.title": "Show OpenMCP", + "openmcp.sidebar.workspace-connection.revealWebviewPanel.title": "Connect", + "openmcp.sidebar.workspace-connection.deleteConnection.title": "Delete Connection", + "openmcp.sidebar.workspace-connection.refresh.title": "Refresh", + "openmcp.sidebar.workspace-connection.addConnection.title": "Add Connection", + "openmcp.sidebar.workspace-connection.openConfiguration.title": "Open Configuration", + "openmcp.sidebar.installed-connection.revealWebviewPanel.title": "Connect", + "openmcp.sidebar.installed-connection.deleteConnection.title": "Delete Connection", + "openmcp.sidebar.installed-connection.refresh.title": "Refresh", + "openmcp.sidebar.installed-connection.addConnection.title": "Add Connection", + "openmcp.sidebar.installed-connection.openConfiguration.title": "Open Configuration", + "openmcp.hook.test-ocr.title": "Test OCR", + "openmcp.sidebar.workspace-connection.view.title": "MCP Connections (Workspace)", + "openmcp.sidebar.installed-connection.view.title": "Installed MCP Servers", + "openmcp.sidebar.help.view.title": "Getting Started & Help" +} diff --git a/package.nls.zh-cn.json b/package.nls.zh-cn.json new file mode 100644 index 0000000..1e0a2a8 --- /dev/null +++ b/package.nls.zh-cn.json @@ -0,0 +1,17 @@ +{ + "openmcp.showOpenMCP.title": "展示 OpenMCP", + "openmcp.sidebar.workspace-connection.revealWebviewPanel.title": "连接", + "openmcp.sidebar.workspace-connection.deleteConnection.title": "删除连接", + "openmcp.sidebar.workspace-connection.refresh.title": "刷新", + "openmcp.sidebar.workspace-connection.addConnection.title": "添加连接", + "openmcp.sidebar.workspace-connection.openConfiguration.title": "打开配置", + "openmcp.sidebar.installed-connection.revealWebviewPanel.title": "连接", + "openmcp.sidebar.installed-connection.deleteConnection.title": "删除连接", + "openmcp.sidebar.installed-connection.refresh.title": "刷新", + "openmcp.sidebar.installed-connection.addConnection.title": "添加连接", + "openmcp.sidebar.installed-connection.openConfiguration.title": "打开配置", + "openmcp.hook.test-ocr.title": "测试 OCR", + "openmcp.sidebar.workspace-connection.view.title": "MCP 连接 (工作区)", + "openmcp.sidebar.installed-connection.view.title": "安装的 MCP 服务器", + "openmcp.sidebar.help.view.title": "入门与帮助" +} \ No newline at end of file diff --git a/renderer/src/i18n/ar.json b/renderer/src/i18n/ar.json index dfabad6..3e0b8de 100644 --- a/renderer/src/i18n/ar.json +++ b/renderer/src/i18n/ar.json @@ -158,5 +158,19 @@ "waiting-mcp-server": "في انتظار استجابة خادم MCP", "parallel-tool-calls": "السماح للنموذج باستدعاء أدوات متعددة في رد واحد", "proxy-server": "خادم وكيل", - "update-model-list": "تحديث قائمة النماذج" + "update-model-list": "تحديث قائمة النماذج", + "ensure-delete-connection": "هل أنت متأكد أنك تريد حذف الاتصال $1؟", + "choose-connection-type": "الرجاء اختيار نوع الاتصال", + "please-enter-connection-command": "الرجاء إدخال أمر الاتصال", + "example-mcp-run": "على سبيل المثال: mcp run main.py", + "please-enter-cwd": "الرجاء إدخال دليل العمل (cwd)، اختياري", + "please-enter-cwd-placeholder": "على سبيل المثال: /path/to/project", + "please-enter-url": "الرجاء إدخال عنوان URL للاتصال", + "example-as": "على سبيل المثال:", + "enter-optional-oauth": "الرجاء إدخال رمز OAuth، اختياري", + "quick-start": "مقدمة", + "read-document": "قراءة الوثائق", + "report-issue": "الإبلاغ عن مشكلة", + "join-project": "المشاركة في المشروع", + "comment-plugin": "ملحق التعليقات" } \ No newline at end of file diff --git a/renderer/src/i18n/de.json b/renderer/src/i18n/de.json index f6e40f6..6de8b0e 100644 --- a/renderer/src/i18n/de.json +++ b/renderer/src/i18n/de.json @@ -158,5 +158,19 @@ "waiting-mcp-server": "Warten auf Antwort vom MCP-Server", "parallel-tool-calls": "Erlauben Sie dem Modell, mehrere Tools in einer einzigen Antwort aufzurufen", "proxy-server": "Proxy-Server", - "update-model-list": "Modellliste aktualisieren" + "update-model-list": "Modellliste aktualisieren", + "ensure-delete-connection": "Möchten Sie die Verbindung $1 wirklich löschen?", + "choose-connection-type": "Bitte wählen Sie den Verbindungstyp", + "please-enter-connection-command": "Bitte geben Sie den Verbindungsbefehl ein", + "example-mcp-run": "Beispiel: mcp run main.py", + "please-enter-cwd": "Bitte geben Sie das Arbeitsverzeichnis (cwd) ein, optional", + "please-enter-cwd-placeholder": "Zum Beispiel: /path/to/project", + "please-enter-url": "Bitte geben Sie die Verbindungs-URL ein", + "example-as": "Zum Beispiel:", + "enter-optional-oauth": "Bitte geben Sie das OAuth-Token ein, optional", + "quick-start": "Einführung", + "read-document": "Dokumentation lesen", + "report-issue": "Problem melden", + "join-project": "Am Projekt teilnehmen", + "comment-plugin": "Kommentar-Plugin" } \ No newline at end of file diff --git a/renderer/src/i18n/fr.json b/renderer/src/i18n/fr.json index 5d44228..31b29ab 100644 --- a/renderer/src/i18n/fr.json +++ b/renderer/src/i18n/fr.json @@ -158,5 +158,19 @@ "waiting-mcp-server": "En attente de la réponse du serveur MCP", "parallel-tool-calls": "Permettre au modèle d'appeler plusieurs outils en une seule réponse", "proxy-server": "Serveur proxy", - "update-model-list": "Mettre à jour la liste des modèles" + "update-model-list": "Mettre à jour la liste des modèles", + "ensure-delete-connection": "Êtes-vous sûr de vouloir supprimer la connexion $1 ?", + "choose-connection-type": "Veuillez sélectionner le type de connexion", + "please-enter-connection-command": "Veuillez saisir la commande de connexion", + "example-mcp-run": "Par exemple : mcp run main.py", + "please-enter-cwd": "Veuillez entrer le répertoire de travail (cwd), facultatif", + "please-enter-cwd-placeholder": "Par exemple : /path/to/project", + "please-enter-url": "Veuillez saisir l'URL de connexion", + "example-as": "Par exemple :", + "enter-optional-oauth": "Veuillez entrer le jeton OAuth, facultatif", + "quick-start": "Premiers pas", + "read-document": "Lire la documentation", + "report-issue": "Signaler un problème", + "join-project": "Participer au projet", + "comment-plugin": "Plugin de commentaires" } \ No newline at end of file diff --git a/renderer/src/i18n/ko.json b/renderer/src/i18n/ko.json index 6dd67a3..5d66f4b 100644 --- a/renderer/src/i18n/ko.json +++ b/renderer/src/i18n/ko.json @@ -158,5 +158,19 @@ "waiting-mcp-server": "MCP 서버 응답 대기 중", "parallel-tool-calls": "모델이 단일 응답에서 여러 도구를 호출할 수 있도록 허용", "proxy-server": "프록시 서버", - "update-model-list": "모델 목록 업데이트" + "update-model-list": "모델 목록 업데이트", + "ensure-delete-connection": "연결 $1을(를) 삭제하시겠습니까?", + "choose-connection-type": "연결 유형을 선택해 주세요", + "please-enter-connection-command": "연결 명령을 입력해 주세요", + "example-mcp-run": "예: mcp run main.py", + "please-enter-cwd": "작업 디렉토리 (cwd)를 입력하세요 (선택 사항)", + "please-enter-cwd-placeholder": "예: /path/to/project", + "please-enter-url": "연결 URL을 입력해 주세요", + "example-as": "예를 들어:", + "enter-optional-oauth": "OAuth 토큰을 입력하세요 (선택 사항)", + "quick-start": "시작하기", + "read-document": "문서 읽기", + "report-issue": "문제 신고", + "join-project": "프로젝트 참여", + "comment-plugin": "댓글 플러그인" } \ No newline at end of file diff --git a/renderer/src/i18n/ru.json b/renderer/src/i18n/ru.json index 9ada280..ba13d4e 100644 --- a/renderer/src/i18n/ru.json +++ b/renderer/src/i18n/ru.json @@ -158,5 +158,19 @@ "waiting-mcp-server": "Ожидание ответа от сервера MCP", "parallel-tool-calls": "Разрешить модели вызывать несколько инструментов в одном ответе", "proxy-server": "Прокси-сервер", - "update-model-list": "Обновить список моделей" + "update-model-list": "Обновить список моделей", + "ensure-delete-connection": "Вы уверены, что хотите удалить соединение $1?", + "choose-connection-type": "Пожалуйста, выберите тип подключения", + "please-enter-connection-command": "Пожалуйста, введите команду подключения", + "example-mcp-run": "Например: mcp run main.py", + "please-enter-cwd": "Пожалуйста, введите рабочий каталог (cwd), необязательно", + "please-enter-cwd-placeholder": "Например: /path/to/project", + "please-enter-url": "Пожалуйста, введите URL-адрес подключения", + "example-as": "Например:", + "enter-optional-oauth": "Пожалуйста, введите токен OAuth, необязательно", + "quick-start": "Начало работы", + "read-document": "Читать документацию", + "report-issue": "Сообщить о проблеме", + "join-project": "Участвовать в проекте", + "comment-plugin": "Плагин комментариев" } \ No newline at end of file diff --git a/renderer/src/i18n/zh-tw.json b/renderer/src/i18n/zh-tw.json index 9234bec..ae95641 100644 --- a/renderer/src/i18n/zh-tw.json +++ b/renderer/src/i18n/zh-tw.json @@ -158,5 +158,19 @@ "waiting-mcp-server": "等待MCP伺服器響應", "parallel-tool-calls": "允許模型在單輪回覆中調用多個工具", "proxy-server": "代理伺服器", - "update-model-list": "更新模型列表" + "update-model-list": "更新模型列表", + "ensure-delete-connection": "確定要刪除連接 $1 嗎?", + "choose-connection-type": "請選擇連接類型", + "please-enter-connection-command": "請輸入連接命令", + "example-mcp-run": "例如: mcp run main.py", + "please-enter-cwd": "請輸入工作目錄 (cwd),可選", + "please-enter-cwd-placeholder": "例如: /path/to/project", + "please-enter-url": "請輸入連接的 URL", + "example-as": "例如:", + "enter-optional-oauth": "請輸入 OAuth 令牌,可選", + "quick-start": "入門", + "read-document": "閱讀文件", + "report-issue": "報告問題", + "join-project": "參與專案", + "comment-plugin": "評論插件" } \ No newline at end of file diff --git a/scripts/package-i18n-token.py b/scripts/package-i18n-token.py new file mode 100644 index 0000000..ea60128 --- /dev/null +++ b/scripts/package-i18n-token.py @@ -0,0 +1,87 @@ +from typing import List +import sys +import os +sys.path.append(os.path.abspath('.')) + +import json +from typing import Any + +PACKAGE_FILE = './package.json' + +LANG_PACKGE_FILES = { + 'en': './package.nls.json', + 'zh-cn': './package.nls.zh-cn.json', + 'ja': './package.nls.ja.json' +} + +def read_json(path: str) -> Any: + if not os.path.exists(path): + return {} + try: + with open(path, 'r', encoding='utf-8') as fp: + config = json.load(fp=fp) + return config + except Exception as e: + return {} + +def write_json(path: str, obj: object): + with open(path, 'w', encoding='utf-8') as fp: + json.dump(obj, fp=fp, indent=4, ensure_ascii=False) + +def generate_title_token(command_name: str) -> str: + names = command_name.split('.') + prj_name = names[0] + main_names = names[1:] + title_token_name = [prj_name] + main_names + ['title'] + return '.'.join(title_token_name) + +def merge_tokens(lang_package_path: str, tokens: List[str], token_values: List[str]): + config = read_json(lang_package_path) + for token, value in zip(tokens, token_values): + if token not in config: + config[token] = value + + write_json(lang_package_path, config) + +if __name__ == '__main__': + # adjust main package + config = read_json(PACKAGE_FILE) + token_names = [] + token_values = [] + + # 获取 properties 中的 title + for property_name in config.get('contributes', {}).get('configuration', {}).get('properties', {}): + # property_name: digital-ide.welcome.show + property_body = config['contributes']['configuration']['properties'][property_name] + print(property_body) + token_name = generate_title_token(property_name) + token_names.append(token_name) + if 'description' in property_body and not property_body['description'].startswith('%'): + token_values.append(property_body['description']) + else: + token_values.append("") + property_body['description'] = '%' + token_name + '%' + + # 获取 command 中的 title + for item in config.get('contributes', {}).get('commands', []): + if 'command' in item: + token_name = generate_title_token(item['command']) + token_names.append(token_name) + token_values.append(item.get('title', '')) + item['title'] = '%' + token_name + '%' + + # 获取 command 中的 title + for viewName in config.get('contributes', {}).get('views', {}): + view = config['contributes']['views'][viewName] + for item in view: + if 'id' in item: + token_name = generate_title_token(item['id'] + '.view') + token_names.append(token_name) + token_values.append(item.get('name', '')) + item['name'] = '%' + token_name + '%' + + write_json(PACKAGE_FILE, config) + + # cover in lang package + for name, lang_path in LANG_PACKGE_FILES.items(): + merge_tokens(lang_path, token_names, token_values) \ No newline at end of file diff --git a/src/extension.ts b/src/extension.ts index 16f01cb..7c37e86 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -1,6 +1,7 @@ import * as vscode from 'vscode'; import { setRunningCWD, setVscodeWorkspace } from '../openmcp-sdk/service'; import { launch } from './common/entry'; +import { initialiseI18n } from './i18n'; export function activate(context: vscode.ExtensionContext) { console.log('activate openmcp'); @@ -12,6 +13,7 @@ export function activate(context: vscode.ExtensionContext) { setVscodeWorkspace(workspace); setRunningCWD(context.extensionPath); + initialiseI18n(context); launch(context); } diff --git a/src/i18n/index.ts b/src/i18n/index.ts new file mode 100644 index 0000000..4e176eb --- /dev/null +++ b/src/i18n/index.ts @@ -0,0 +1,26 @@ +import * as vscode from 'vscode'; +import * as fs from 'fs'; + +const defaultBundle: Record = {} + +export function initialiseI18n(context: vscode.ExtensionContext) { + if (vscode.l10n.bundle === undefined) { + const bundlePath = context.asAbsolutePath('l10n/bundle.l10n.en.json'); + const bundle = JSON.parse(fs.readFileSync(bundlePath, { encoding: 'utf-8' })) as Record; + Object.assign(defaultBundle, bundle); + } +} + +export function t(message: string, ...args: string[]): string { + if (vscode.l10n.bundle === undefined) { + let translateMessage = defaultBundle[message] || message; + + for (let i = 0; i < args.length; ++ i) { + translateMessage = translateMessage.replace(`{${i}}`, args[i]); + } + + return translateMessage; + } else { + return vscode.l10n.t(message, ...args); + } +} \ No newline at end of file diff --git a/src/sidebar/help.controller.ts b/src/sidebar/help.controller.ts index 4868210..4be84f9 100644 --- a/src/sidebar/help.controller.ts +++ b/src/sidebar/help.controller.ts @@ -1,6 +1,7 @@ import * as vscode from 'vscode'; import { SidebarItem } from './common'; import { RegisterTreeDataProvider } from '../common'; +import { t } from '../i18n'; @RegisterTreeDataProvider('openmcp.sidebar.help') export class HelpProvider implements vscode.TreeDataProvider { @@ -16,27 +17,27 @@ export class HelpProvider implements vscode.TreeDataProvider { getChildren(element?: SidebarItem): Thenable { // 返回子节点 return Promise.resolve([ - new SidebarItem('入门', vscode.TreeItemCollapsibleState.None, { + new SidebarItem(t('quick-start'), vscode.TreeItemCollapsibleState.None, { command: 'vscode.open', title: 'Open Guide', arguments: [vscode.Uri.parse('https://kirigaya.cn/openmcp/plugin-tutorial/usage/connect-mcp.html·')] }, 'book'), - new SidebarItem('阅读文档', vscode.TreeItemCollapsibleState.None, { + new SidebarItem(t('read-document'), vscode.TreeItemCollapsibleState.None, { command: 'vscode.open', title: 'Open Documentation', arguments: [vscode.Uri.parse('https://kirigaya.cn/openmcp')] }, 'file-text'), - new SidebarItem('报告问题', vscode.TreeItemCollapsibleState.None, { + new SidebarItem(t('report-issue'), vscode.TreeItemCollapsibleState.None, { command: 'vscode.open', title: 'Report Issue', arguments: [vscode.Uri.parse('https://github.com/LSTM-Kirigaya/openmcp-client/issues')] }, 'bug'), - new SidebarItem('参与项目', vscode.TreeItemCollapsibleState.None, { + new SidebarItem(t('join-project'), vscode.TreeItemCollapsibleState.None, { command: 'vscode.open', title: 'Join Project', arguments: [vscode.Uri.parse('https://qm.qq.com/cgi-bin/qm/qr?k=C6ZUTZvfqWoI12lWe7L93cWa1hUsuVT0&jump_from=webapi&authKey=McW6B1ogTPjPDrCyGttS890tMZGQ1KB3QLuG4aqVNRaYp4vlTSgf2c6dMcNjMuBD')] }, 'organization'), - new SidebarItem('评论插件', vscode.TreeItemCollapsibleState.None, { + new SidebarItem(t('comment-plugin'), vscode.TreeItemCollapsibleState.None, { command: 'vscode.open', title: 'Review Extension', arguments: [vscode.Uri.parse('https://marketplace.visualstudio.com/items?itemName=kirigaya.openmcp&ssr=false#review-details')] diff --git a/src/sidebar/installed.service.ts b/src/sidebar/installed.service.ts index 54e77f0..fbc585b 100644 --- a/src/sidebar/installed.service.ts +++ b/src/sidebar/installed.service.ts @@ -1,21 +1,26 @@ import { getConnectionConfig, panels, saveConnectionConfig, getFirstValidPathFromCommand, McpOptions } from "../global"; import { exec, spawn } from 'node:child_process'; import * as vscode from 'vscode'; +import { t } from "../i18n"; export async function deleteInstalledConnection(item: McpOptions[] | McpOptions) { // 弹出确认对话框 const masterNode = Array.isArray(item) ? item[0] : item; - const name = masterNode.name; - const confirm = await vscode.window.showWarningMessage( - `确定要删除连接 "${name}" 吗?`, + const name = masterNode.name || 'unknown node name'; + + const res = await vscode.window.showWarningMessage( + t("ensure-delete-connection", name), { modal: true }, - '确定' + { title: t('confirm'), value: true }, ); - if (confirm !== '确定') { + const confirm = res?.value; + + if (!confirm) { return; // 用户取消删除 } + const installedConnection = getConnectionConfig(); // 从配置中移除该连接项 @@ -50,14 +55,14 @@ export async function validateAndGetCommandPath(commandString: string, cwd?: str return ''; } catch (error) { console.log(error); - throw new Error(`无法找到命令: ${commandString.split(' ')[0]}`); + throw new Error(`Cannot find command: ${commandString.split(' ')[0]}`); } } export async function acquireInstalledConnection(): Promise { // 让用户选择连接类型 const connectionType = await vscode.window.showQuickPick(['STDIO', 'SSE', 'STREAMABLE_HTTP'], { - placeHolder: '请选择连接类型', + placeHolder: t('choose-connection-type'), canPickMany: false, ignoreFocusOut: true, }); @@ -69,8 +74,8 @@ export async function acquireInstalledConnection(): Promise { if (connectionType === 'STDIO') { // 获取 command const commandString = await vscode.window.showInputBox({ - prompt: '请输入连接的 command', - placeHolder: '例如: mcp run main.py' + prompt: t('please-enter-connection-command'), + placeHolder: t('example-mcp-run') }); if (!commandString) { @@ -79,8 +84,8 @@ export async function acquireInstalledConnection(): Promise { // 获取 cwd const cwd = await vscode.window.showInputBox({ - prompt: '请输入工作目录 (cwd),可选', - placeHolder: '例如: /path/to/project' + prompt: t('please-enter-cwd'), + placeHolder: t('please-enter-cwd-placeholder') }); // 校验 command + cwd 是否有效 @@ -88,7 +93,7 @@ export async function acquireInstalledConnection(): Promise { const commandPath = await validateAndGetCommandPath(commandString, cwd); console.log('Command Path:', commandPath); } catch (error) { - vscode.window.showErrorMessage(`无效的 command: ${error}`); + vscode.window.showErrorMessage(`Invalid command: ${error}`); return []; } @@ -113,8 +118,8 @@ export async function acquireInstalledConnection(): Promise { } else if (connectionType === 'SSE') { // 获取 url const url = await vscode.window.showInputBox({ - prompt: '请输入连接的 URL', - placeHolder: '例如: https://127.0.0.1:8282/sse' + prompt: t('please-enter-url'), + placeHolder: t('example-as') + 'https://127.0.0.1:8282/sse' }); if (!url) { @@ -123,8 +128,8 @@ export async function acquireInstalledConnection(): Promise { // 获取 oauth const oauth = await vscode.window.showInputBox({ - prompt: '请输入 OAuth 令牌,可选', - placeHolder: '例如: your-oauth-token' + prompt: t('enter-optional-oauth'), + placeHolder: t('example-as') + ' your-oauth-token' }); // 保存连接配置 @@ -138,8 +143,8 @@ export async function acquireInstalledConnection(): Promise { } else if (connectionType === 'STREAMABLE_HTTP') { // 获取 url const url = await vscode.window.showInputBox({ - prompt: '请输入连接的 URL', - placeHolder: '例如: https://127.0.0.1:8282/stream' + prompt: t('please-enter-url'), + placeHolder: t('example-as') + ' https://127.0.0.1:8282/stream' }); if (!url) { @@ -148,8 +153,8 @@ export async function acquireInstalledConnection(): Promise { // 获取 oauth const oauth = await vscode.window.showInputBox({ - prompt: '请输入 OAuth 令牌,可选', - placeHolder: '例如: your-oauth-token' + prompt: t('enter-optional-oauth'), + placeHolder: t('example-as') + ' your-oauth-token' }); // 保存连接配置 diff --git a/src/sidebar/workspace.service.ts b/src/sidebar/workspace.service.ts index 3724a0b..add69e2 100644 --- a/src/sidebar/workspace.service.ts +++ b/src/sidebar/workspace.service.ts @@ -1,28 +1,28 @@ import { getFirstValidPathFromCommand, getWorkspaceConnectionConfig, getWorkspacePath, McpOptions, panels, saveWorkspaceConnectionConfig } from "../global"; import * as vscode from 'vscode'; +import { t } from "../i18n"; export async function deleteUserConnection(item: McpOptions[] | McpOptions) { // 弹出确认对话框 const masterNode = Array.isArray(item) ? item[0] : item; - const name = masterNode.name; + const name = masterNode.name || 'unknown node name'; - console.log('enter delete'); - - const confirm = await vscode.window.showWarningMessage( - `确定要删除连接 "${name}" 吗?`, + const res = await vscode.window.showWarningMessage( + t("ensure-delete-connection", name), { modal: true }, - '确定' + { title: t('confirm'), value: true }, ); - if (confirm !== '确定') { + const confirm = res?.value; + + if (!confirm) { return; // 用户取消删除 } const workspaceConnectionConfig = getWorkspaceConnectionConfig(); // 从配置中移除该连接项 - console.log(item); - console.log(workspaceConnectionConfig.items); + // TODO: 改成基于 path 进行搜索 const index = workspaceConnectionConfig.items.indexOf(item); @@ -53,14 +53,14 @@ export async function validateAndGetCommandPath(command: string, cwd?: string): const { stdout } = await execAsync(`which ${command.split(' ')[0]}`, { cwd }); return stdout.trim(); } catch (error) { - throw new Error(`无法找到命令: ${command.split(' ')[0]}`); + throw new Error(`Cannot find command: ${command.split(' ')[0]}`); } } export async function acquireUserCustomConnection(): Promise { // 让用户选择连接类型 const connectionType = await vscode.window.showQuickPick(['STDIO', 'SSE', 'STREAMABLE_HTTP'], { - placeHolder: '请选择连接类型', + placeHolder: t('choose-connection-type'), canPickMany: false, ignoreFocusOut: true, }); @@ -72,8 +72,8 @@ export async function acquireUserCustomConnection(): Promise { if (connectionType === 'STDIO') { // 获取 command const commandString = await vscode.window.showInputBox({ - prompt: '请输入连接的 command', - placeHolder: '例如: mcp run main.py' + prompt: t('please-enter-connection-command'), + placeHolder: t('example-mcp-run') }); if (!commandString) { @@ -82,8 +82,8 @@ export async function acquireUserCustomConnection(): Promise { // 获取 cwd const cwd = await vscode.window.showInputBox({ - prompt: '请输入工作目录 (cwd),可选', - placeHolder: '例如: /path/to/project' + prompt: t('please-enter-cwd'), + placeHolder: t('please-enter-cwd-placeholder') }); // 校验 command + cwd 是否有效 @@ -91,7 +91,7 @@ export async function acquireUserCustomConnection(): Promise { const commandPath = await validateAndGetCommandPath(commandString, cwd); console.log('Command Path:', commandPath); } catch (error) { - vscode.window.showErrorMessage(`无效的 command: ${error}`); + vscode.window.showErrorMessage(`Invalid command: ${error}`); return []; } @@ -113,8 +113,8 @@ export async function acquireUserCustomConnection(): Promise { } else if (connectionType === 'SSE') { // 获取 url const url = await vscode.window.showInputBox({ - prompt: '请输入连接的 URL', - placeHolder: '例如: https://127.0.0.1:8282/sse' + prompt: t('please-enter-url'), + placeHolder: t('example-as') + 'https://127.0.0.1:8282/sse' }); if (!url) { @@ -123,8 +123,8 @@ export async function acquireUserCustomConnection(): Promise { // 获取 oauth const oauth = await vscode.window.showInputBox({ - prompt: '请输入 OAuth 令牌,可选', - placeHolder: '例如: your-oauth-token' + prompt: t('enter-optional-oauth'), + placeHolder: t('example-as') + ' your-oauth-token' }); // 保存连接配置 @@ -138,8 +138,8 @@ export async function acquireUserCustomConnection(): Promise { } else if (connectionType === 'STREAMABLE_HTTP') { // 获取 url const url = await vscode.window.showInputBox({ - prompt: '请输入连接的 URL', - placeHolder: '例如: https://127.0.0.1:8282/stream' + prompt: t('please-enter-url'), + placeHolder: t('example-as') + ' https://127.0.0.1:8282/stream' }); if (!url) { @@ -148,8 +148,8 @@ export async function acquireUserCustomConnection(): Promise { // 获取 oauth const oauth = await vscode.window.showInputBox({ - prompt: '请输入 OAuth 令牌,可选', - placeHolder: '例如: your-oauth-token' + prompt: t('enter-optional-oauth'), + placeHolder: t('example-as') + ' your-oauth-token' }); // 保存连接配置 diff --git a/src/webview/webview.controller.ts b/src/webview/webview.controller.ts index 71f0d24..74130ab 100644 --- a/src/webview/webview.controller.ts +++ b/src/webview/webview.controller.ts @@ -15,8 +15,7 @@ export class WebviewController { const signature = getDefaultLanunchSignature(uri.fsPath, cwd); if (!signature) { - vscode.window.showInformationMessage('OpenMCP: 无法获取启动参数'); - vscode.window.showErrorMessage('OpenMCP: 无法获取启动参数'); + vscode.window.showErrorMessage('OpenMCP: Cannot acquire launch parameters'); return; }