babaofan-translate-cli 1.0.0 → 1.0.2-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +31 -42
  2. package/package.json +12 -3
  3. package/utils.js +244 -0
package/README.md CHANGED
@@ -1,5 +1,25 @@
1
1
  # babaofan-translate-cli
2
2
 
3
+ > 当前版本为 **Beta 测试版**。功能还在快速迭代,存在已知问题与兼容性风险,生产项目请先使用 `--dry-run` 验证,再决定是否正式改写源码。
4
+ >
5
+ > Beta 安装方式:
6
+ >
7
+ > ```bash
8
+ > npm install -D babaofan-translate-cli@beta
9
+ > ```
10
+ >
11
+ > Beta 临时执行方式:
12
+ >
13
+ > ```bash
14
+ > npx babaofan-translate-cli@beta create --languages zh-cn,en --files "src/**/*.vue,src/**/*.ts" --dry-run
15
+ > ```
16
+ >
17
+ > GitHub 仓库地址:
18
+ >
19
+ > ```text
20
+ > https://github.com/2285907229/babaofan-translate-cli
21
+ > ```
22
+
3
23
  一个本地运行的 i18n 翻译 CLI。
4
24
 
5
25
  它的目标很直接:扫描前端项目中的 `t("...")`、`$t("...")` 这类国际化调用,把中文词条提取出来,自动生成稳定的 i18n key,把源码里的中文调用改写成 key 调用,然后直接在本地通过 Google AI Studio 的 Gemini 模型完成翻译,最后生成对应的多语言文件。
@@ -89,56 +109,19 @@ npm install
89
109
  - 已安装当前项目依赖
90
110
  - 能访问 Google AI Studio / Gemini 接口
91
111
 
92
- ## 发布到 npm
93
-
94
- 发布前建议先确认:
95
-
96
- - [package.json](./package.json) 中的 `name`、`version`、`description` 已经正确
97
- - [config.js](./config.js) 里不要保留你自己的真实 API Key
98
- - 本地已经执行过测试命令
99
-
100
- ### 1. 登录 npm
101
-
102
- ```bash
103
- npm login
104
- ```
105
-
106
- ### 2. 检查最终会发布哪些文件
107
-
108
- ```bash
109
- npm pack --dry-run
110
- ```
111
-
112
- ### 3. 发布
113
-
114
- 首次发布:
115
-
116
- ```bash
117
- npm publish
118
- ```
119
112
 
120
- 如果后续发新版本,先改 `version`,再发布:
121
-
122
- ```bash
123
- npm version patch
124
- npm publish
125
- ```
113
+ ### 安装
126
114
 
127
- 你也可以按需使用:
115
+ 建议作为开发依赖安装:
128
116
 
129
117
  ```bash
130
- npm version minor
131
- npm version major
118
+ npm install -D babaofan-translate-cli
132
119
  ```
133
120
 
134
- ## 在别的项目里使用
135
-
136
- ### 安装
137
-
138
- 建议作为开发依赖安装:
121
+ 如果你想明确安装测试版,建议直接指定 `beta` tag:
139
122
 
140
123
  ```bash
141
- npm install -D babaofan-translate-cli
124
+ npm install -D babaofan-translate-cli@beta
142
125
  ```
143
126
 
144
127
  或者:
@@ -159,6 +142,12 @@ yarn add -D babaofan-translate-cli
159
142
  npx babaofan-translate create --languages zh-cn,en --files "src/**/*.vue,src/**/*.tsx" --dry-run
160
143
  ```
161
144
 
145
+ 如果你想强制使用 Beta 版本测试:
146
+
147
+ ```bash
148
+ npx babaofan-translate-cli@beta create --languages zh-cn,en --files "src/**/*.vue,src/**/*.tsx" --dry-run
149
+ ```
150
+
162
151
  ### 方式 2:写进项目 scripts
163
152
 
164
153
  在目标项目的 `package.json` 里加:
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "private": false,
3
3
  "name": "babaofan-translate-cli",
4
- "version": "1.0.0",
5
- "description": "A local CLI for scanning i18n calls, generating semantic keys, translating with Google AI Studio, and updating locale files.",
4
+ "version": "1.0.2-beta.0",
5
+ "description": "Beta local CLI for scanning i18n calls, generating semantic keys, translating with Google AI Studio, and updating locale files.",
6
6
  "type": "module",
7
7
  "bin": {
8
8
  "babaofan-translate": "./bin/i18n.js"
@@ -13,7 +13,8 @@
13
13
  "files": [
14
14
  "bin",
15
15
  "config.js",
16
- "README.md"
16
+ "README.md",
17
+ "utils.js"
17
18
  ],
18
19
  "keywords": [
19
20
  "i18n",
@@ -28,6 +29,14 @@
28
29
  ],
29
30
  "author": "",
30
31
  "license": "MIT",
32
+ "homepage": "https://github.com/2285907229/babaofan-translate-cli#readme",
33
+ "bugs": {
34
+ "url": "https://github.com/2285907229/babaofan-translate-cli/issues"
35
+ },
36
+ "repository": {
37
+ "type": "git",
38
+ "url": "git+https://github.com/2285907229/babaofan-translate-cli.git"
39
+ },
31
40
  "dependencies": {
32
41
  "@google/genai": "^1.24.0",
33
42
  "@babel/parser": "^7.28.6",
package/utils.js ADDED
@@ -0,0 +1,244 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * 公共工具函数模块
5
+ * 提供跨脚本使用的通用功能
6
+ */
7
+
8
+ import chalk from "chalk";
9
+ import path from "path";
10
+ import fs from "fs";
11
+ import { execSync } from "child_process";
12
+ import os from "os";
13
+
14
+ // ============================================================================
15
+ // 路径工具
16
+ // ============================================================================
17
+
18
+ /**
19
+ * 获取项目根目录
20
+ * @returns {string} 项目根目录路径
21
+ */
22
+ function getProjectRoot() {
23
+ // return "/Users/jiangshuai/Desktop/coding/cool/uniapp/cool-unix";
24
+ return process.cwd();
25
+ }
26
+
27
+ /**
28
+ * 获取相对于项目根目录的路径
29
+ * @param {string} absolutePath - 绝对路径
30
+ * @param {string} projectRoot - 项目根目录(可选)
31
+ * @returns {string} 相对路径
32
+ */
33
+ function getRelativePath(absolutePath, projectRoot = getProjectRoot()) {
34
+ return absolutePath.replace(projectRoot, "").replace(/^\//, "");
35
+ }
36
+
37
+ // ============================================================================
38
+ // 文件系统工具
39
+ // ============================================================================
40
+
41
+ /**
42
+ * 确保目录存在,不存在则创建
43
+ * @param {string} filePath - 文件路径或目录路径
44
+ */
45
+ function ensureDirectoryExists(filePath) {
46
+ const dirPath = path.dirname(filePath);
47
+ if (!fs.existsSync(dirPath)) {
48
+ fs.mkdirSync(dirPath, { recursive: true });
49
+ }
50
+ }
51
+
52
+ /**
53
+ * 递归复制目录/文件(覆盖模式)
54
+ * @param {string} src - 源路径
55
+ * @param {string} dest - 目标路径
56
+ */
57
+ function copyRecursive(src, dest) {
58
+ const stat = fs.statSync(src);
59
+
60
+ if (fs.existsSync(dest)) {
61
+ fs.rmSync(dest, { recursive: true, force: true });
62
+ }
63
+
64
+ if (stat.isDirectory()) {
65
+ fs.mkdirSync(dest, { recursive: true });
66
+ const items = fs.readdirSync(src);
67
+ for (const item of items) {
68
+ const srcPath = path.join(src, item);
69
+ const destPath = path.join(dest, item);
70
+ copyRecursive(srcPath, destPath);
71
+ }
72
+ } else {
73
+ fs.copyFileSync(src, dest);
74
+ }
75
+ }
76
+
77
+ /**
78
+ * 清理目录
79
+ * @param {string} dirPath - 目录路径
80
+ * @returns {boolean} 是否成功清理
81
+ */
82
+ function cleanDirectory(dirPath) {
83
+ if (fs.existsSync(dirPath)) {
84
+ fs.rmSync(dirPath, { recursive: true, force: true });
85
+ return true;
86
+ }
87
+ return false;
88
+ }
89
+
90
+ // ============================================================================
91
+ // 终端日志工具
92
+ // ============================================================================
93
+
94
+ /**
95
+ * 统一的日志工具类
96
+ */
97
+ const logger = {
98
+ /**
99
+ * 打印标题
100
+ * @param {string} text - 标题文本
101
+ */
102
+ title(text) {
103
+ console.log();
104
+ console.log(chalk.white.bold(text));
105
+ console.log(chalk.gray("─".repeat(50)));
106
+ },
107
+
108
+ /**
109
+ * 打印信息
110
+ * @param {string} label - 标签
111
+ * @param {string} value - 值
112
+ */
113
+ info(label, value) {
114
+ console.log(chalk.gray(" ●"), chalk.white(label), chalk.cyan(value));
115
+ },
116
+
117
+ /**
118
+ * 打印成功消息
119
+ * @param {string} text - 消息文本
120
+ */
121
+ success(text) {
122
+ console.log(chalk.green(" ✓"), chalk.white(text));
123
+ },
124
+
125
+ /**
126
+ * 打印警告消息
127
+ * @param {string} text - 警告文本
128
+ */
129
+ warn(text) {
130
+ console.log(chalk.yellow(" ⚠"), chalk.white(text));
131
+ },
132
+
133
+ /**
134
+ * 打印错误消息
135
+ * @param {string} text - 错误文本
136
+ */
137
+ error(text) {
138
+ console.error(chalk.red(" ✗"), chalk.white(text));
139
+ },
140
+
141
+ /**
142
+ * 打印文件路径
143
+ * @param {string} filePath - 文件路径
144
+ * @param {string} projectRoot - 项目根目录(可选)
145
+ */
146
+ file(filePath, projectRoot = getProjectRoot()) {
147
+ const relativePath = getRelativePath(filePath, projectRoot);
148
+ console.log(chalk.gray(" +"), chalk.green(relativePath));
149
+ },
150
+
151
+ /**
152
+ * 打印分隔线
153
+ */
154
+ divider() {
155
+ console.log(chalk.gray("─".repeat(50)));
156
+ },
157
+
158
+ /**
159
+ * 打印空行
160
+ */
161
+ newline() {
162
+ console.log();
163
+ }
164
+ };
165
+
166
+ // ============================================================================
167
+ // 命令行工具
168
+ // ============================================================================
169
+
170
+ /**
171
+ * 跨平台检测命令是否存在
172
+ * @param {string} command - 要检测的命令
173
+ * @returns {boolean} 命令是否存在
174
+ */
175
+ function commandExists(command) {
176
+ const isWindows = os.platform() === "win32";
177
+
178
+ try {
179
+ if (isWindows) {
180
+ try {
181
+ execSync(`where ${command}`, { stdio: "ignore", shell: "cmd.exe" });
182
+ return true;
183
+ } catch {
184
+ execSync(`${command} --version`, {
185
+ stdio: "ignore",
186
+ shell: "cmd.exe",
187
+ timeout: 3000
188
+ });
189
+ return true;
190
+ }
191
+ } else {
192
+ try {
193
+ execSync(`which ${command}`, { stdio: "ignore" });
194
+ return true;
195
+ } catch {
196
+ execSync(`${command} --version`, {
197
+ stdio: "ignore",
198
+ timeout: 3000
199
+ });
200
+ return true;
201
+ }
202
+ }
203
+ } catch {
204
+ return false;
205
+ }
206
+ }
207
+
208
+ // ============================================================================
209
+ // 字符串工具
210
+ // ============================================================================
211
+
212
+ /**
213
+ * 将连字符命名转换为驼峰命名
214
+ * @param {string} str - 连字符字符串
215
+ * @returns {string} 驼峰命名字符串
216
+ */
217
+ function toCamelCase(str) {
218
+ return str.replace(/-([a-z])/g, (_match, letter) => letter.toUpperCase());
219
+ }
220
+
221
+ /**
222
+ * 将驼峰命名转换为连字符命名
223
+ * @param {string} str - 驼峰字符串
224
+ * @returns {string} 连字符命名字符串
225
+ */
226
+ function toKebabCase(str) {
227
+ return str.replace(/([a-z])([A-Z])/g, "$1-$2").toLowerCase();
228
+ }
229
+
230
+ // ============================================================================
231
+ // 导出
232
+ // ============================================================================
233
+
234
+ export {
235
+ getProjectRoot,
236
+ getRelativePath,
237
+ ensureDirectoryExists,
238
+ copyRecursive,
239
+ cleanDirectory,
240
+ logger,
241
+ commandExists,
242
+ toCamelCase,
243
+ toKebabCase
244
+ };