新建项目,实现基本功能,可使用百度翻译API

This commit is contained in:
tianjianyong 2025-03-09 14:36:27 +08:00
commit 2c3e291411
8 changed files with 1037 additions and 0 deletions

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
/out
/node_modules

141
docs/design.md Normal file
View File

@ -0,0 +1,141 @@
# VSCode 中英文变量名翻译插件设计文档
## 1. 项目概述
### 1.1 项目目标
开发一个VSCode插件实现以下核心功能
- 把选中的中文翻译成英文变量名并替换
- 支持选中英文文本翻译为中文
- 提供变量命名规范化处理(支持驼峰命名、帕斯卡命名、下划线命名)
### 1.2 技术栈选择
- 开发语言TypeScript
- 开发框架VSCode Extension API
- 翻译服务OpenAI API提供更准确的上下文翻译
- 开发工具VSCode、Node.js
## 2. 系统架构
### 2.1 核心模块
1. **选中文本翻译模块**
- 获取用户选中的中文文本
- 处理选中的中文内容
- 触发翻译流程
2. **翻译服务模块**
- 集成Google Translate API 和百度翻译API
- 处理翻译请求
- 缓存常用翻译结果
3. **变量命名处理模块**
- 驼峰命名转换
- 变量命名规范检查
- 特殊字符处理
4. **用户界面模块**
- 翻译结果展示
- 快捷命令注册
- 配置界面
### 2.2 数据流
1. 用户输入/选择文本
2. 触发翻译事件
3. 调用翻译服务
4. 处理翻译结果
5. 更新编辑器文本
## 3. 功能详细设计
### 3.1 中文翻译为英文变量名
- 获取用户选中的中文文本
- 调用翻译API获取英文翻译
- 应用变量命名规范
- 替换原文本
### 3.2 选中文本翻译
- 注册命令`translate.toEnglish`和`translate.toChinese`
- 获取选中文本范围和内容
- 调用翻译服务
- 在状态栏或悬浮窗显示翻译结果
- 提供快速替换选项
### 3.3 变量命名规范化
- 支持驼峰命名(camelCase)
- 支持帕斯卡命名(PascalCase)
- 支持下划线命名(snake_case)
- 自动移除特殊字符
- 处理多词组合
### 3.4 配置选项
- 翻译服务API配置
- 默认变量命名风格
- 快捷键自定义
- 自动翻译开关
- 翻译结果展示方式
## 4. 性能优化
### 4.1 翻译性能
- 实现本地翻译缓存
- 批量翻译请求合并
- 设置翻译频率限制
### 4.2 编辑器性能
- 防抖处理输入事件
- 异步处理翻译请求
- 优化文本替换操作
## 5. 错误处理
### 5.1 翻译服务异常
- API调用失败重试机制
- 错误信息友好展示
- 降级使用备用翻译服务
### 5.2 输入异常
- 非法字符检测
- 超长输入限制
- 特殊格式处理
## 6. 安全性考虑
### 6.1 API密钥管理
- 安全存储API密钥
- 加密传输敏感信息
- 访问权限控制
### 6.2 数据安全
- 本地缓存加密
- 用户数据保护
- 隐私政策遵守
## 7. 后续优化方向
### 7.1 功能扩展
- 支持更多翻译服务
- 添加自定义词典
- 批量翻译功能
- 翻译历史记录
### 7.2 用户体验
- 智能上下文理解
- 实时翻译预览
- 多语言支持
- 统计分析功能
## 8. 开发计划
### 8.1 第一阶段
- 基础框架搭建
- 核心翻译功能实现
- 基本UI组件开发
### 8.2 第二阶段
- 性能优化
- 错误处理完善
- 配置功能实现
### 8.3 第三阶段
- 功能测试与修复
- 文档编写
- 发布与维护

484
package-lock.json generated Normal file
View File

@ -0,0 +1,484 @@
{
"name": "vscode-translate-plugin",
"version": "0.0.1",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "vscode-translate-plugin",
"version": "0.0.1",
"dependencies": {
"@types/axios": "^0.9.36",
"@vitalets/google-translate-api": "^9.2.0",
"axios": "^1.8.2",
"crypto": "^1.0.1"
},
"devDependencies": {
"@types/node": "^20.10.5",
"@types/node-fetch": "^2.6.12",
"@types/vscode": "^1.85.0",
"typescript": "^5.3.3"
},
"engines": {
"vscode": "^1.60.0"
}
},
"node_modules/@types/axios": {
"version": "0.9.36",
"resolved": "https://registry.npmmirror.com/@types/axios/-/axios-0.9.36.tgz",
"integrity": "sha512-NLOpedx9o+rxo/X5ChbdiX6mS1atE4WHmEEIcR9NLenRVa5HoVjAvjafwU3FPTqnZEstpoqCaW7fagqSoTDNeg==",
"license": "MIT"
},
"node_modules/@types/http-errors": {
"version": "1.8.2",
"resolved": "https://registry.npmmirror.com/@types/http-errors/-/http-errors-1.8.2.tgz",
"integrity": "sha512-EqX+YQxINb+MeXaIqYDASb6U6FCHbWjkj4a1CKDBks3d/QiB2+PqBLyO72vLDgAO1wUI4O+9gweRcQK11bTL/w==",
"license": "MIT"
},
"node_modules/@types/node": {
"version": "20.17.24",
"resolved": "https://registry.npmmirror.com/@types/node/-/node-20.17.24.tgz",
"integrity": "sha512-d7fGCyB96w9BnWQrOsJtpyiSaBcAYYr75bnK6ZRjDbql2cGLj/3GsL5OYmLPNq76l7Gf2q4Rv9J2o6h5CrD9sA==",
"dev": true,
"license": "MIT",
"dependencies": {
"undici-types": "~6.19.2"
}
},
"node_modules/@types/node-fetch": {
"version": "2.6.12",
"resolved": "https://registry.npmmirror.com/@types/node-fetch/-/node-fetch-2.6.12.tgz",
"integrity": "sha512-8nneRWKCg3rMtF69nLQJnOYUcbafYeFSjqkw3jCRLsqkWFlHaoQrr5mXmofFGOx3DKn7UfmBMyov8ySvLRVldA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@types/node": "*",
"form-data": "^4.0.0"
}
},
"node_modules/@types/vscode": {
"version": "1.98.0",
"resolved": "https://registry.npmmirror.com/@types/vscode/-/vscode-1.98.0.tgz",
"integrity": "sha512-+KuiWhpbKBaG2egF+51KjbGWatTH5BbmWQjSLMDCssb4xF8FJnW4nGH4nuAdOOfMbpD0QlHtI+C3tPq+DoKElg==",
"dev": true,
"license": "MIT"
},
"node_modules/@vitalets/google-translate-api": {
"version": "9.2.1",
"resolved": "https://registry.npmmirror.com/@vitalets/google-translate-api/-/google-translate-api-9.2.1.tgz",
"integrity": "sha512-zlwQWSjXUZhbZQ6qwtIQ7GdYXFQmJ4wYqzcrYJUxtvzQQwUP+uKUb/SRJaBOQuBntjBjzcdcJoLFrpCKUbIkOg==",
"license": "MIT",
"dependencies": {
"@types/http-errors": "^1.8.2",
"http-errors": "^2.0.0",
"node-fetch": "^2.6.7"
},
"engines": {
"node": ">=14"
}
},
"node_modules/asynckit": {
"version": "0.4.0",
"resolved": "https://registry.npmmirror.com/asynckit/-/asynckit-0.4.0.tgz",
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
"license": "MIT"
},
"node_modules/axios": {
"version": "1.8.2",
"resolved": "https://registry.npmmirror.com/axios/-/axios-1.8.2.tgz",
"integrity": "sha512-ls4GYBm5aig9vWx8AWDSGLpnpDQRtWAfrjU+EuytuODrFBkqesN2RkOQCBzrA1RQNHw1SmRMSDDDSwzNAYQ6Rg==",
"license": "MIT",
"dependencies": {
"follow-redirects": "^1.15.6",
"form-data": "^4.0.0",
"proxy-from-env": "^1.1.0"
}
},
"node_modules/call-bind-apply-helpers": {
"version": "1.0.2",
"resolved": "https://registry.npmmirror.com/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
"integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==",
"license": "MIT",
"dependencies": {
"es-errors": "^1.3.0",
"function-bind": "^1.1.2"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/combined-stream": {
"version": "1.0.8",
"resolved": "https://registry.npmmirror.com/combined-stream/-/combined-stream-1.0.8.tgz",
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
"license": "MIT",
"dependencies": {
"delayed-stream": "~1.0.0"
},
"engines": {
"node": ">= 0.8"
}
},
"node_modules/crypto": {
"version": "1.0.1",
"resolved": "https://registry.npmmirror.com/crypto/-/crypto-1.0.1.tgz",
"integrity": "sha512-VxBKmeNcqQdiUQUW2Tzq0t377b54N2bMtXO/qiLa+6eRRmmC4qT3D4OnTGoT/U6O9aklQ/jTwbOtRMTTY8G0Ig==",
"deprecated": "This package is no longer supported. It's now a built-in Node module. If you've depended on crypto, you should switch to the one that's built-in.",
"license": "ISC"
},
"node_modules/delayed-stream": {
"version": "1.0.0",
"resolved": "https://registry.npmmirror.com/delayed-stream/-/delayed-stream-1.0.0.tgz",
"integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
"license": "MIT",
"engines": {
"node": ">=0.4.0"
}
},
"node_modules/depd": {
"version": "2.0.0",
"resolved": "https://registry.npmmirror.com/depd/-/depd-2.0.0.tgz",
"integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==",
"license": "MIT",
"engines": {
"node": ">= 0.8"
}
},
"node_modules/dunder-proto": {
"version": "1.0.1",
"resolved": "https://registry.npmmirror.com/dunder-proto/-/dunder-proto-1.0.1.tgz",
"integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==",
"license": "MIT",
"dependencies": {
"call-bind-apply-helpers": "^1.0.1",
"es-errors": "^1.3.0",
"gopd": "^1.2.0"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/es-define-property": {
"version": "1.0.1",
"resolved": "https://registry.npmmirror.com/es-define-property/-/es-define-property-1.0.1.tgz",
"integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
"license": "MIT",
"engines": {
"node": ">= 0.4"
}
},
"node_modules/es-errors": {
"version": "1.3.0",
"resolved": "https://registry.npmmirror.com/es-errors/-/es-errors-1.3.0.tgz",
"integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
"license": "MIT",
"engines": {
"node": ">= 0.4"
}
},
"node_modules/es-object-atoms": {
"version": "1.1.1",
"resolved": "https://registry.npmmirror.com/es-object-atoms/-/es-object-atoms-1.1.1.tgz",
"integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==",
"license": "MIT",
"dependencies": {
"es-errors": "^1.3.0"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/es-set-tostringtag": {
"version": "2.1.0",
"resolved": "https://registry.npmmirror.com/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz",
"integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==",
"license": "MIT",
"dependencies": {
"es-errors": "^1.3.0",
"get-intrinsic": "^1.2.6",
"has-tostringtag": "^1.0.2",
"hasown": "^2.0.2"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/follow-redirects": {
"version": "1.15.9",
"resolved": "https://registry.npmmirror.com/follow-redirects/-/follow-redirects-1.15.9.tgz",
"integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==",
"funding": [
{
"type": "individual",
"url": "https://github.com/sponsors/RubenVerborgh"
}
],
"license": "MIT",
"engines": {
"node": ">=4.0"
},
"peerDependenciesMeta": {
"debug": {
"optional": true
}
}
},
"node_modules/form-data": {
"version": "4.0.2",
"resolved": "https://registry.npmmirror.com/form-data/-/form-data-4.0.2.tgz",
"integrity": "sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w==",
"license": "MIT",
"dependencies": {
"asynckit": "^0.4.0",
"combined-stream": "^1.0.8",
"es-set-tostringtag": "^2.1.0",
"mime-types": "^2.1.12"
},
"engines": {
"node": ">= 6"
}
},
"node_modules/function-bind": {
"version": "1.1.2",
"resolved": "https://registry.npmmirror.com/function-bind/-/function-bind-1.1.2.tgz",
"integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
"license": "MIT",
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/get-intrinsic": {
"version": "1.3.0",
"resolved": "https://registry.npmmirror.com/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
"integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==",
"license": "MIT",
"dependencies": {
"call-bind-apply-helpers": "^1.0.2",
"es-define-property": "^1.0.1",
"es-errors": "^1.3.0",
"es-object-atoms": "^1.1.1",
"function-bind": "^1.1.2",
"get-proto": "^1.0.1",
"gopd": "^1.2.0",
"has-symbols": "^1.1.0",
"hasown": "^2.0.2",
"math-intrinsics": "^1.1.0"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/get-proto": {
"version": "1.0.1",
"resolved": "https://registry.npmmirror.com/get-proto/-/get-proto-1.0.1.tgz",
"integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==",
"license": "MIT",
"dependencies": {
"dunder-proto": "^1.0.1",
"es-object-atoms": "^1.0.0"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/gopd": {
"version": "1.2.0",
"resolved": "https://registry.npmmirror.com/gopd/-/gopd-1.2.0.tgz",
"integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
"license": "MIT",
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/has-symbols": {
"version": "1.1.0",
"resolved": "https://registry.npmmirror.com/has-symbols/-/has-symbols-1.1.0.tgz",
"integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==",
"license": "MIT",
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/has-tostringtag": {
"version": "1.0.2",
"resolved": "https://registry.npmmirror.com/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
"integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
"license": "MIT",
"dependencies": {
"has-symbols": "^1.0.3"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/hasown": {
"version": "2.0.2",
"resolved": "https://registry.npmmirror.com/hasown/-/hasown-2.0.2.tgz",
"integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
"license": "MIT",
"dependencies": {
"function-bind": "^1.1.2"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/http-errors": {
"version": "2.0.0",
"resolved": "https://registry.npmmirror.com/http-errors/-/http-errors-2.0.0.tgz",
"integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==",
"license": "MIT",
"dependencies": {
"depd": "2.0.0",
"inherits": "2.0.4",
"setprototypeof": "1.2.0",
"statuses": "2.0.1",
"toidentifier": "1.0.1"
},
"engines": {
"node": ">= 0.8"
}
},
"node_modules/inherits": {
"version": "2.0.4",
"resolved": "https://registry.npmmirror.com/inherits/-/inherits-2.0.4.tgz",
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
"license": "ISC"
},
"node_modules/math-intrinsics": {
"version": "1.1.0",
"resolved": "https://registry.npmmirror.com/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
"integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==",
"license": "MIT",
"engines": {
"node": ">= 0.4"
}
},
"node_modules/mime-db": {
"version": "1.52.0",
"resolved": "https://registry.npmmirror.com/mime-db/-/mime-db-1.52.0.tgz",
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
"license": "MIT",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/mime-types": {
"version": "2.1.35",
"resolved": "https://registry.npmmirror.com/mime-types/-/mime-types-2.1.35.tgz",
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
"license": "MIT",
"dependencies": {
"mime-db": "1.52.0"
},
"engines": {
"node": ">= 0.6"
}
},
"node_modules/node-fetch": {
"version": "2.7.0",
"resolved": "https://registry.npmmirror.com/node-fetch/-/node-fetch-2.7.0.tgz",
"integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==",
"license": "MIT",
"dependencies": {
"whatwg-url": "^5.0.0"
},
"engines": {
"node": "4.x || >=6.0.0"
},
"peerDependencies": {
"encoding": "^0.1.0"
},
"peerDependenciesMeta": {
"encoding": {
"optional": true
}
}
},
"node_modules/proxy-from-env": {
"version": "1.1.0",
"resolved": "https://registry.npmmirror.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==",
"license": "MIT"
},
"node_modules/setprototypeof": {
"version": "1.2.0",
"resolved": "https://registry.npmmirror.com/setprototypeof/-/setprototypeof-1.2.0.tgz",
"integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==",
"license": "ISC"
},
"node_modules/statuses": {
"version": "2.0.1",
"resolved": "https://registry.npmmirror.com/statuses/-/statuses-2.0.1.tgz",
"integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==",
"license": "MIT",
"engines": {
"node": ">= 0.8"
}
},
"node_modules/toidentifier": {
"version": "1.0.1",
"resolved": "https://registry.npmmirror.com/toidentifier/-/toidentifier-1.0.1.tgz",
"integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==",
"license": "MIT",
"engines": {
"node": ">=0.6"
}
},
"node_modules/tr46": {
"version": "0.0.3",
"resolved": "https://registry.npmmirror.com/tr46/-/tr46-0.0.3.tgz",
"integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==",
"license": "MIT"
},
"node_modules/typescript": {
"version": "5.8.2",
"resolved": "https://registry.npmmirror.com/typescript/-/typescript-5.8.2.tgz",
"integrity": "sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ==",
"dev": true,
"license": "Apache-2.0",
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
},
"engines": {
"node": ">=14.17"
}
},
"node_modules/undici-types": {
"version": "6.19.8",
"resolved": "https://registry.npmmirror.com/undici-types/-/undici-types-6.19.8.tgz",
"integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==",
"dev": true,
"license": "MIT"
},
"node_modules/webidl-conversions": {
"version": "3.0.1",
"resolved": "https://registry.npmmirror.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
"integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==",
"license": "BSD-2-Clause"
},
"node_modules/whatwg-url": {
"version": "5.0.0",
"resolved": "https://registry.npmmirror.com/whatwg-url/-/whatwg-url-5.0.0.tgz",
"integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
"license": "MIT",
"dependencies": {
"tr46": "~0.0.3",
"webidl-conversions": "^3.0.0"
}
}
}
}

109
package.json Normal file
View File

@ -0,0 +1,109 @@
{
"name": "vscode-translate-plugin",
"displayName": "中英文变量名翻译",
"description": "VSCode中英文变量名翻译插件支持中英互译和变量命名规范化",
"version": "0.0.1",
"publisher": "tianjianyong",
"engines": {
"vscode": "^1.60.0"
},
"categories": [
"Other"
],
"activationEvents": [
"onCommand:translate.toEnglish",
"onCommand:translate.toChinese"
],
"main": "./out/extension.js",
"contributes": {
"commands": [
{
"command": "translate.toEnglish",
"title": "翻译为英文变量名"
},
{
"command": "translate.toChinese",
"title": "翻译为中文"
}
],
"menus": {
"editor/context": [
{
"when": "editorHasSelection",
"command": "translate.toEnglish",
"group": "translation"
},
{
"when": "editorHasSelection",
"command": "translate.toChinese",
"group": "translation"
}
]
},
"configuration": {
"title": "中英文变量名翻译",
"properties": {
"translate.namingConvention": {
"type": "string",
"default": "camelCase",
"enum": [
"camelCase",
"PascalCase",
"snake_case"
],
"description": "变量命名规范"
},
"translate.translationService": {
"type": "string",
"default": "google",
"enum": [
"google",
"baidu"
],
"description": "翻译服务提供商"
},
"translate.baiduAppId": {
"type": "string",
"default": "",
"description": "百度翻译API的AppID"
},
"translate.baiduSecretKey": {
"type": "string",
"default": "",
"description": "百度翻译API的密钥"
}
}
},
"keybindings": [
{
"command": "translate.toEnglish",
"key": "ctrl+alt+e",
"mac": "cmd+alt+e",
"when": "editorHasSelection"
},
{
"command": "translate.toChinese",
"key": "ctrl+alt+c",
"mac": "cmd+alt+c",
"when": "editorHasSelection"
}
]
},
"scripts": {
"vscode:prepublish": "npm run compile",
"compile": "tsc -p ./",
"watch": "tsc -watch -p ./"
},
"devDependencies": {
"@types/node": "^20.10.5",
"@types/node-fetch": "^2.6.12",
"@types/vscode": "^1.85.0",
"typescript": "^5.3.3"
},
"dependencies": {
"@types/axios": "^0.9.36",
"@vitalets/google-translate-api": "^9.2.0",
"axios": "^1.8.2",
"crypto": "^1.0.1"
}
}

92
src/extension.ts Normal file
View File

@ -0,0 +1,92 @@
import * as vscode from 'vscode';
// 从翻译服务模块导入翻译函数
// 从翻译服务模块导入翻译函数
import { translateToChinese, translateToEnglish } from './translationService';
// 导入命名格式化工具函数
import { formatVariableName } from './namingFormatter';
export function activate(context: vscode.ExtensionContext) {
console.log('中英文变量名翻译插件已激活');
// 注册翻译为英文变量名命令
let toEnglishDisposable = vscode.commands.registerCommand('translate.toEnglish', async () => {
const editor = vscode.window.activeTextEditor;
if (!editor) {
return;
}
const selection = editor.selection;
if (selection.isEmpty) {
vscode.window.showInformationMessage('请先选择要翻译的文本');
return;
}
const text = editor.document.getText(selection);
try {
// 显示状态栏加载信息
vscode.window.setStatusBarMessage('正在翻译...', 2000);
// 调用翻译服务
const translatedText = await translateToEnglish(text);
// 获取用户配置的命名规范
const config = vscode.workspace.getConfiguration('translate');
const namingConvention = config.get<string>('namingConvention', 'camelCase');
// 格式化变量名
const formattedName = formatVariableName(translatedText, namingConvention);
// 替换选中文本
editor.edit(editBuilder => {
editBuilder.replace(selection, formattedName);
});
vscode.window.setStatusBarMessage(`已翻译: ${formattedName}`, 3000);
} catch (error) {
vscode.window.showErrorMessage(`翻译失败: ${error instanceof Error ? error.message : String(error)}`);
}
});
// 注册翻译为中文命令
let toChineseDisposable = vscode.commands.registerCommand('translate.toChinese', async () => {
const editor = vscode.window.activeTextEditor;
if (!editor) {
return;
}
const selection = editor.selection;
if (selection.isEmpty) {
vscode.window.showInformationMessage('请先选择要翻译的文本');
return;
}
const text = editor.document.getText(selection);
try {
// 显示状态栏加载信息
vscode.window.setStatusBarMessage('正在翻译...', 2000);
// 调用翻译服务
const translatedText = await translateToChinese(text);
// 显示翻译结果
const showResult = await vscode.window.showInformationMessage(
`翻译结果: ${translatedText}`,
'替换选中文本',
'关闭'
);
// 如果用户选择替换,则替换选中文本
if (showResult === '替换选中文本') {
editor.edit(editBuilder => {
editBuilder.replace(selection, translatedText);
});
}
} catch (error) {
vscode.window.showErrorMessage(`翻译失败: ${error instanceof Error ? error.message : String(error)}`);
}
});
context.subscriptions.push(toEnglishDisposable, toChineseDisposable);
}
export function deactivate() {}

55
src/namingFormatter.ts Normal file
View File

@ -0,0 +1,55 @@
/**
*
*
*/
/**
*
* @param text
* @param convention camelCasePascalCasesnake_case
* @returns
*/
export function formatVariableName(text: string, convention: string): string {
// 清理文本,移除特殊字符和多余空格
let cleanedText = text
.trim()
.replace(/[^\w\s]/g, ' ') // 将特殊字符替换为空格
.replace(/\s+/g, ' '); // 将多个空格替换为单个空格
// 分割单词
const words = cleanedText.split(' ');
// 根据不同命名规范格式化变量名
switch (convention) {
case 'camelCase':
return words
.map((word, index) => {
if (index === 0) {
return word.toLowerCase();
}
return word.charAt(0).toUpperCase() + word.slice(1).toLowerCase();
})
.join('');
case 'PascalCase':
return words
.map(word => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())
.join('');
case 'snake_case':
return words
.map(word => word.toLowerCase())
.join('_');
default:
// 默认使用驼峰命名法
return words
.map((word, index) => {
if (index === 0) {
return word.toLowerCase();
}
return word.charAt(0).toUpperCase() + word.slice(1).toLowerCase();
})
.join('');
}
}

141
src/translationService.ts Normal file
View File

@ -0,0 +1,141 @@
import { translate } from '@vitalets/google-translate-api';
import axios from 'axios';
import * as crypto from 'crypto';
import * as vscode from 'vscode';
// 翻译服务类型
type TranslationService = 'google' | 'baidu';
/**
*
* @returns
*/
function getTranslationService(): TranslationService {
const config = vscode.workspace.getConfiguration('translate');
return config.get<TranslationService>('translationService', 'google');
}
/**
* API配置
* @returns API的appId和密钥
*/
function getBaiduApiConfig(): { appId: string; secretKey: string } {
const config = vscode.workspace.getConfiguration('translate');
const appId = config.get<string>('baiduAppId', '');
const secretKey = config.get<string>('baiduSecretKey', '');
return { appId, secretKey };
}
/**
* 使API进行翻译
* @param text
* @param from
* @param to
* @returns
*/
async function baiduTranslate(text: string, from: string, to: string): Promise<string> {
const { appId, secretKey } = getBaiduApiConfig();
if (!appId || !secretKey) {
throw new Error('请先在设置中配置百度翻译API的appId和密钥');
}
const salt = Date.now().toString();
const sign = crypto.createHash('md5').update(appId + text + salt + secretKey).digest('hex');
try {
const response = await axios.get('https://api.fanyi.baidu.com/api/trans/vip/translate', {
params: {
q: text,
from,
to,
appid: appId,
salt,
sign
}
});
// 定义百度翻译API响应的接口类型
interface BaiduTranslateResponse {
trans_result?: Array<{
dst: string;
}>;
}
const translationData = response.data as BaiduTranslateResponse;
if (translationData.trans_result && translationData.trans_result.length > 0) {
return translationData.trans_result[0].dst;
} else {
throw new Error('翻译结果解析失败');
}
} catch (error) {
console.error('百度翻译API请求失败:', error);
throw new Error('百度翻译服务出错请检查API配置或网络连接');
}
}
/**
* 使Google翻译API进行翻译
* @param text
* @param to
* @returns
*/
async function googleTranslate(text: string, to: string): Promise<string> {
try {
const result = await translate(text, { to });
return result.text;
} catch (error) {
console.error('Google翻译API请求失败:', error);
throw new Error('Google翻译服务出错请稍后再试');
}
}
/**
*
* @param text
* @returns
*/
export async function translateToEnglish(text: string): Promise<string> {
try {
// 检查文本是否包含中文字符
if (!/[\u4e00-\u9fa5]/.test(text)) {
return text; // 如果不包含中文,直接返回原文本
}
const service = getTranslationService();
if (service === 'baidu') {
return await baiduTranslate(text, 'zh', 'en');
} else {
return await googleTranslate(text, 'en');
}
} catch (error) {
console.error('翻译为英文失败:', error);
throw new Error(`翻译服务出错: ${error instanceof Error ? error.message : '请稍后再试'}`);
}
}
/**
*
* @param text
* @returns
*/
export async function translateToChinese(text: string): Promise<string> {
try {
// 检查文本是否全是中文字符
if (/^[\u4e00-\u9fa5]+$/.test(text)) {
return text; // 如果全是中文,直接返回原文本
}
const service = getTranslationService();
if (service === 'baidu') {
return await baiduTranslate(text, 'en', 'zh');
} else {
return await googleTranslate(text, 'zh-CN');
}
} catch (error) {
console.error('翻译为中文失败:', error);
throw new Error(`翻译服务出错: ${error instanceof Error ? error.message : '请稍后再试'}`);
}
}

13
tsconfig.json Normal file
View File

@ -0,0 +1,13 @@
{
"compilerOptions": {
"module": "commonjs",
"target": "ES2020",
"outDir": "out",
"lib": ["ES2020"],
"sourceMap": true,
"rootDir": "src",
"strict": true,
"esModuleInterop": true
},
"exclude": ["node_modules", ".vscode-test"]
}