cc-translate 0.4.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.
- package/README.md +0 -0
- package/index.d.ts +48 -0
- package/index.d.ts.map +1 -0
- package/index.js +274 -0
- package/lib/cache/index.d.ts +20 -0
- package/lib/cache/index.d.ts.map +1 -0
- package/lib/cache/index.js +66 -0
- package/lib/log/index.d.ts +3 -0
- package/lib/log/index.d.ts.map +1 -0
- package/lib/log/index.js +17 -0
- package/lib/support.d.ts +3 -0
- package/lib/support.d.ts.map +1 -0
- package/lib/support.js +102 -0
- package/lib/utils.d.ts +25 -0
- package/lib/utils.d.ts.map +1 -0
- package/lib/utils.js +75 -0
- package/package.json +46 -0
- package/src/fine-tuning/test.jsonl +0 -0
- package/src/index.ts +361 -0
- package/src/lib/cache/index.ts +70 -0
- package/src/lib/log/index.ts +19 -0
- package/src/lib/support.ts +104 -0
- package/src/lib/utils.ts +74 -0
- package/src/types/index.ts +117 -0
- package/tsconfig.json +121 -0
- package/types/index.d.ts +78 -0
- package/types/index.d.ts.map +1 -0
- package/types/index.js +1 -0
package/README.md
ADDED
|
File without changes
|
package/index.d.ts
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { OpenAI } from "openai";
|
|
2
|
+
import { ICwalletTranslateParams, IJson, IOpenaiConfig, IOutputLanguageFile, ISingleTranslate, ITranslateChat, ITranslateChatResponse, SupportLanguageType } from "./types";
|
|
3
|
+
export declare class CwalletTranslate {
|
|
4
|
+
private OPENAI_KEY;
|
|
5
|
+
CACHE_ROOT_PATH: string;
|
|
6
|
+
ENTRY_ROOT_PATH: string;
|
|
7
|
+
SOURCE_LANGUAGE: SupportLanguageType;
|
|
8
|
+
OUTPUT_ROOT_PATH: string | undefined;
|
|
9
|
+
languages: SupportLanguageType[];
|
|
10
|
+
client: OpenAI | null;
|
|
11
|
+
openaiConfig: IOpenaiConfig;
|
|
12
|
+
fineTune: string[];
|
|
13
|
+
constructor(params: ICwalletTranslateParams);
|
|
14
|
+
get supportLanguages(): import("./types").ILanguage[];
|
|
15
|
+
get outputPath(): string;
|
|
16
|
+
searchLanguage(code: SupportLanguageType): import("./types").ILanguage | undefined;
|
|
17
|
+
createOpenAIClient: () => void;
|
|
18
|
+
/** 翻译入口文件的所有支持的语言文件夹和其中的文件 */
|
|
19
|
+
translate: () => Promise<void>;
|
|
20
|
+
/**
|
|
21
|
+
* 翻译单个文件
|
|
22
|
+
* @param params
|
|
23
|
+
* @returns
|
|
24
|
+
*/
|
|
25
|
+
singleTranslate: (params: ISingleTranslate) => Promise<void>;
|
|
26
|
+
/**
|
|
27
|
+
* 使用open ai 进行翻译
|
|
28
|
+
* @param {string} key
|
|
29
|
+
* @param {string} value
|
|
30
|
+
* @param {OpenAI} client
|
|
31
|
+
* @param {string} language
|
|
32
|
+
* @returns
|
|
33
|
+
*/
|
|
34
|
+
translateChat: (params: ITranslateChat) => Promise<ITranslateChatResponse>;
|
|
35
|
+
/**
|
|
36
|
+
* 对比缓存文件 获取需要翻译的内容
|
|
37
|
+
* @param language
|
|
38
|
+
* @param fileName
|
|
39
|
+
* @returns
|
|
40
|
+
*/
|
|
41
|
+
getTranslateContent: (language: SupportLanguageType, fileName: string) => Promise<IJson | undefined>;
|
|
42
|
+
/**
|
|
43
|
+
* 输出语言文件
|
|
44
|
+
* @param {Object} jsonMap
|
|
45
|
+
*/
|
|
46
|
+
outputLanguageFile: (params: IOutputLanguageFile) => Promise<void>;
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=index.d.ts.map
|
package/index.d.ts.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["src/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAEhC,OAAO,EACL,uBAAuB,EACvB,KAAK,EACL,aAAa,EACb,mBAAmB,EACnB,gBAAgB,EAChB,cAAc,EACd,sBAAsB,EACtB,mBAAmB,EACpB,MAAM,SAAS,CAAC;AAsBjB,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,UAAU,CAAS;IAC3B,eAAe,EAAE,MAAM,CAAC;IACxB,eAAe,EAAE,MAAM,CAAC;IACxB,eAAe,EAAE,mBAAmB,CAAC;IACrC,gBAAgB,EAAE,MAAM,GAAG,SAAS,CAAC;IACrC,SAAS,EAAE,mBAAmB,EAAE,CAAC;IACjC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAQ;IAC7B,YAAY,EAAE,aAAa,CAAC;IAC5B,QAAQ,EAAE,MAAM,EAAE,CAAC;gBAEP,MAAM,EAAE,uBAAuB;IAc3C,IAAI,gBAAgB,kCAOnB;IAED,IAAI,UAAU,WAEb;IAED,cAAc,CAAC,IAAI,EAAE,mBAAmB;IAIxC,kBAAkB,aAOhB;IACF,8BAA8B;IAC9B,SAAS,sBAyDP;IACF;;;;OAIG;IACH,eAAe,WAAkB,gBAAgB,mBA4D/C;IAEF;;;;;;;OAOG;IACH,aAAa,WAAY,cAAc,KAAG,OAAO,CAAC,sBAAsB,CAAC,CA2DvE;IACF;;;;;OAKG;IACH,mBAAmB,aACP,mBAAmB,YACnB,MAAM,KACf,OAAO,CAAC,KAAK,GAAG,SAAS,CAAC,CA8B3B;IAEF;;;OAGG;IACH,kBAAkB,WAAkB,mBAAmB,mBAsCrD;CACH"}
|
package/index.js
ADDED
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
import path from "path";
|
|
11
|
+
import fs from "fs";
|
|
12
|
+
import colors from "ansi-colors";
|
|
13
|
+
import { OpenAI } from "openai";
|
|
14
|
+
import cliProgress from "cli-progress";
|
|
15
|
+
import { chunkArray, getRandomNumber, notExistsToCreateFile, readFileOfDirSync, readJsonFileSync, } from "./lib/utils.js";
|
|
16
|
+
import { getCacheFileSync, registerLanguageCacheFile, translateJSONDiffToJson, } from "./lib/cache/index.js";
|
|
17
|
+
import { logErrorToFile } from "./lib/log/index.js";
|
|
18
|
+
import { SUPPORT_LANGUAGE_MAP } from "./lib/support.js";
|
|
19
|
+
const __dirname = process.cwd();
|
|
20
|
+
const DEFAULT_OPENAI_CONFIG = {
|
|
21
|
+
model: "gpt-4o",
|
|
22
|
+
};
|
|
23
|
+
export class CwalletTranslate {
|
|
24
|
+
constructor(params) {
|
|
25
|
+
var _a, _b, _c;
|
|
26
|
+
this.client = null;
|
|
27
|
+
this.createOpenAIClient = () => {
|
|
28
|
+
/** 初始化openAi */
|
|
29
|
+
const client = new OpenAI({
|
|
30
|
+
apiKey: this.OPENAI_KEY,
|
|
31
|
+
});
|
|
32
|
+
this.client = client;
|
|
33
|
+
};
|
|
34
|
+
/** 翻译入口文件的所有支持的语言文件夹和其中的文件 */
|
|
35
|
+
this.translate = () => __awaiter(this, void 0, void 0, function* () {
|
|
36
|
+
console.log("🚀 开始翻译");
|
|
37
|
+
console.log(`🚀 使用的模型: ${this.openaiConfig.model} 🚀`);
|
|
38
|
+
console.log(`🚀 微调: ${this.fineTune} 🚀`);
|
|
39
|
+
const translateFolderPath = path.join(this.ENTRY_ROOT_PATH, this.SOURCE_LANGUAGE);
|
|
40
|
+
// 翻译源语言问价夹下的所有json文件
|
|
41
|
+
const translateFolders = yield readFileOfDirSync(translateFolderPath);
|
|
42
|
+
// 创建进度条
|
|
43
|
+
const multiBar = new cliProgress.MultiBar({
|
|
44
|
+
clearOnComplete: false,
|
|
45
|
+
hideCursor: true,
|
|
46
|
+
format: colors.cyan("{bar}") +
|
|
47
|
+
"| {percentage}% || {filename} {value}/{total} ",
|
|
48
|
+
}, cliProgress.Presets.legacy);
|
|
49
|
+
let promises = [];
|
|
50
|
+
const arr = [];
|
|
51
|
+
for (const item of this.supportLanguages) {
|
|
52
|
+
// 源语言不翻译
|
|
53
|
+
if (item.code === this.SOURCE_LANGUAGE)
|
|
54
|
+
continue;
|
|
55
|
+
for (const fileName of translateFolders) {
|
|
56
|
+
const translateJson = yield this.getTranslateContent(item.code, fileName);
|
|
57
|
+
if (!translateJson) {
|
|
58
|
+
console.log(`${item.code}:${fileName} 没有需要翻译的内容`);
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
arr.push(() => this.singleTranslate({
|
|
62
|
+
language: item.code,
|
|
63
|
+
fileName,
|
|
64
|
+
multiBar,
|
|
65
|
+
translateJson,
|
|
66
|
+
}));
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
promises = chunkArray(arr, 8);
|
|
70
|
+
for (const chunk of promises) {
|
|
71
|
+
yield Promise.all(chunk.map((fn) => fn()));
|
|
72
|
+
}
|
|
73
|
+
multiBar.stop();
|
|
74
|
+
console.log("🚀 翻译完毕");
|
|
75
|
+
});
|
|
76
|
+
/**
|
|
77
|
+
* 翻译单个文件
|
|
78
|
+
* @param params
|
|
79
|
+
* @returns
|
|
80
|
+
*/
|
|
81
|
+
this.singleTranslate = (params) => __awaiter(this, void 0, void 0, function* () {
|
|
82
|
+
const {
|
|
83
|
+
/** 待翻译的语言 */
|
|
84
|
+
language,
|
|
85
|
+
/** 待翻译的文件名 */
|
|
86
|
+
fileName, translateJson, multiBar, callback, } = params;
|
|
87
|
+
try {
|
|
88
|
+
/** 待翻译的文件路径 */
|
|
89
|
+
const translateFilePath = path.join(this.ENTRY_ROOT_PATH, language, fileName);
|
|
90
|
+
// 等待翻译的数组
|
|
91
|
+
const jsonMap = {};
|
|
92
|
+
// 生成chat循环代码
|
|
93
|
+
const promiseList = Object.entries(translateJson).map(([key, value], index) => () => this.translateChat({
|
|
94
|
+
key,
|
|
95
|
+
value,
|
|
96
|
+
language,
|
|
97
|
+
index,
|
|
98
|
+
fileName,
|
|
99
|
+
}));
|
|
100
|
+
const progressBar = multiBar.create(promiseList.length, 0);
|
|
101
|
+
for (const fn of promiseList) {
|
|
102
|
+
const result = yield fn();
|
|
103
|
+
jsonMap[result.key] = result.value;
|
|
104
|
+
progressBar.update(result.index + 1, {
|
|
105
|
+
filename: `${language}:${fileName}`,
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
this.outputLanguageFile({
|
|
109
|
+
jsonMap,
|
|
110
|
+
folderName: language,
|
|
111
|
+
fileName,
|
|
112
|
+
translateFilePath,
|
|
113
|
+
});
|
|
114
|
+
callback && callback();
|
|
115
|
+
}
|
|
116
|
+
catch (error) {
|
|
117
|
+
logErrorToFile({
|
|
118
|
+
error: error,
|
|
119
|
+
language,
|
|
120
|
+
fileName,
|
|
121
|
+
key: "",
|
|
122
|
+
});
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
});
|
|
126
|
+
/**
|
|
127
|
+
* 使用open ai 进行翻译
|
|
128
|
+
* @param {string} key
|
|
129
|
+
* @param {string} value
|
|
130
|
+
* @param {OpenAI} client
|
|
131
|
+
* @param {string} language
|
|
132
|
+
* @returns
|
|
133
|
+
*/
|
|
134
|
+
this.translateChat = (params) => {
|
|
135
|
+
return new Promise((resolve) => {
|
|
136
|
+
const { key, value, language, index, fileName } = params;
|
|
137
|
+
try {
|
|
138
|
+
if (!this.client)
|
|
139
|
+
throw new Error("Connection failed");
|
|
140
|
+
const targetLanguage = this.searchLanguage(language);
|
|
141
|
+
const originLanguage = this.searchLanguage(this.SOURCE_LANGUAGE);
|
|
142
|
+
if (!targetLanguage) {
|
|
143
|
+
throw new Error(`不支持的语言:${language}`);
|
|
144
|
+
}
|
|
145
|
+
if (!originLanguage) {
|
|
146
|
+
throw new Error(`不支持的语言:${this.SOURCE_LANGUAGE}`);
|
|
147
|
+
}
|
|
148
|
+
setTimeout(() => __awaiter(this, void 0, void 0, function* () {
|
|
149
|
+
var _a, _b, _c;
|
|
150
|
+
const chatCompletion = yield this.client.chat.completions.create({
|
|
151
|
+
model: (_a = this.openaiConfig) === null || _a === void 0 ? void 0 : _a.model,
|
|
152
|
+
messages: [
|
|
153
|
+
...this.fineTune.map((val) => ({
|
|
154
|
+
role: "system",
|
|
155
|
+
content: val,
|
|
156
|
+
})),
|
|
157
|
+
{
|
|
158
|
+
role: "system",
|
|
159
|
+
content: `请将${originLanguage.name}翻译成${targetLanguage.name}`,
|
|
160
|
+
},
|
|
161
|
+
{
|
|
162
|
+
role: "system",
|
|
163
|
+
content: `翻译完成直接输出后对应意思的内容不要携带任何无关内容`,
|
|
164
|
+
},
|
|
165
|
+
{
|
|
166
|
+
role: "user",
|
|
167
|
+
content: value,
|
|
168
|
+
},
|
|
169
|
+
],
|
|
170
|
+
});
|
|
171
|
+
resolve({
|
|
172
|
+
key,
|
|
173
|
+
value: (_c = (_b = chatCompletion === null || chatCompletion === void 0 ? void 0 : chatCompletion.choices[0]) === null || _b === void 0 ? void 0 : _b.message.content) !== null && _c !== void 0 ? _c : value,
|
|
174
|
+
index,
|
|
175
|
+
});
|
|
176
|
+
}), getRandomNumber(200, 300));
|
|
177
|
+
}
|
|
178
|
+
catch (error) {
|
|
179
|
+
logErrorToFile({ error: error, key, fileName, language });
|
|
180
|
+
resolve({
|
|
181
|
+
key,
|
|
182
|
+
value,
|
|
183
|
+
index,
|
|
184
|
+
error: error,
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
});
|
|
188
|
+
};
|
|
189
|
+
/**
|
|
190
|
+
* 对比缓存文件 获取需要翻译的内容
|
|
191
|
+
* @param language
|
|
192
|
+
* @param fileName
|
|
193
|
+
* @returns
|
|
194
|
+
*/
|
|
195
|
+
this.getTranslateContent = (language, fileName) => __awaiter(this, void 0, void 0, function* () {
|
|
196
|
+
const translateFilePath = path.join(this.ENTRY_ROOT_PATH, this.SOURCE_LANGUAGE, fileName);
|
|
197
|
+
/** 缓存文件路径 */
|
|
198
|
+
const cacheFilePath = path.join(this.CACHE_ROOT_PATH, language, fileName);
|
|
199
|
+
if (!fs.existsSync(translateFilePath)) {
|
|
200
|
+
console.dir(`File not found: ${translateFilePath}`);
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
const translateFileObject = yield readJsonFileSync(translateFilePath);
|
|
204
|
+
const cacheObject = yield getCacheFileSync(cacheFilePath);
|
|
205
|
+
const diffObject = translateJSONDiffToJson(cacheObject, translateFileObject);
|
|
206
|
+
if (Object.values(diffObject).length === 0) {
|
|
207
|
+
if (Object.keys(translateFileObject).length === 0) {
|
|
208
|
+
this.outputLanguageFile({
|
|
209
|
+
jsonMap: {},
|
|
210
|
+
folderName: language,
|
|
211
|
+
fileName,
|
|
212
|
+
translateFilePath,
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
217
|
+
return diffObject;
|
|
218
|
+
});
|
|
219
|
+
/**
|
|
220
|
+
* 输出语言文件
|
|
221
|
+
* @param {Object} jsonMap
|
|
222
|
+
*/
|
|
223
|
+
this.outputLanguageFile = (params) => __awaiter(this, void 0, void 0, function* () {
|
|
224
|
+
const { folderName, fileName, jsonMap, translateFilePath } = params;
|
|
225
|
+
const outputFilePath = path.join(this.outputPath, folderName, fileName);
|
|
226
|
+
//创建输出文件夹
|
|
227
|
+
notExistsToCreateFile(this.outputPath);
|
|
228
|
+
//创建输出的语言文件夹
|
|
229
|
+
notExistsToCreateFile(`${this.outputPath}/${folderName}`);
|
|
230
|
+
let oldJsonData = "";
|
|
231
|
+
// 检查是否存在文件
|
|
232
|
+
if (!fs.existsSync(outputFilePath)) {
|
|
233
|
+
oldJsonData = yield fs.readFileSync(path.join(this.ENTRY_ROOT_PATH, this.SOURCE_LANGUAGE, fileName), "utf8");
|
|
234
|
+
}
|
|
235
|
+
else {
|
|
236
|
+
oldJsonData = yield fs.readFileSync(outputFilePath, "utf8");
|
|
237
|
+
}
|
|
238
|
+
const oldJsonMap = JSON.parse(oldJsonData);
|
|
239
|
+
const newJsonMap = Object.assign(oldJsonMap, jsonMap);
|
|
240
|
+
yield fs.writeFileSync(path.resolve(outputFilePath), JSON.stringify(newJsonMap, null, 2), "utf8");
|
|
241
|
+
// 注册缓存
|
|
242
|
+
registerLanguageCacheFile({
|
|
243
|
+
sourceFilePath: path.join(this.ENTRY_ROOT_PATH, this.SOURCE_LANGUAGE, fileName),
|
|
244
|
+
jsonMap: newJsonMap,
|
|
245
|
+
fileName,
|
|
246
|
+
language: folderName,
|
|
247
|
+
folderName: this.CACHE_ROOT_PATH,
|
|
248
|
+
});
|
|
249
|
+
});
|
|
250
|
+
this.OPENAI_KEY = params.key;
|
|
251
|
+
this.CACHE_ROOT_PATH = path.resolve(__dirname, params.cacheFileRootPath);
|
|
252
|
+
this.ENTRY_ROOT_PATH = path.resolve(__dirname, params.fileRootPath);
|
|
253
|
+
this.openaiConfig = (_a = params.openaiConfig) !== null && _a !== void 0 ? _a : DEFAULT_OPENAI_CONFIG;
|
|
254
|
+
this.SOURCE_LANGUAGE = (_b = params.sourceLanguage) !== null && _b !== void 0 ? _b : "en";
|
|
255
|
+
this.OUTPUT_ROOT_PATH = params.outputRootPath
|
|
256
|
+
? path.resolve(__dirname, params.outputRootPath)
|
|
257
|
+
: undefined;
|
|
258
|
+
this.fineTune = params.fineTune;
|
|
259
|
+
this.languages = (_c = params.languages) !== null && _c !== void 0 ? _c : [];
|
|
260
|
+
this.createOpenAIClient();
|
|
261
|
+
}
|
|
262
|
+
get supportLanguages() {
|
|
263
|
+
return Object.entries(SUPPORT_LANGUAGE_MAP)
|
|
264
|
+
.map(([key, val]) => val)
|
|
265
|
+
.filter(({ code }) => this.languages.includes(code) || code === this.SOURCE_LANGUAGE);
|
|
266
|
+
}
|
|
267
|
+
get outputPath() {
|
|
268
|
+
var _a;
|
|
269
|
+
return (_a = this.OUTPUT_ROOT_PATH) !== null && _a !== void 0 ? _a : this.ENTRY_ROOT_PATH;
|
|
270
|
+
}
|
|
271
|
+
searchLanguage(code) {
|
|
272
|
+
return this.supportLanguages.find((item) => item.code === code);
|
|
273
|
+
}
|
|
274
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { IJson, IRegisterLanguageCacheFile } from "../../types";
|
|
2
|
+
/**
|
|
3
|
+
* 和翻译缓存json文件对比 返回存在更改的json文件
|
|
4
|
+
* @param {object} cacheObject 已经缓存的对象
|
|
5
|
+
* @param {object} translateObject 需要翻译的对象
|
|
6
|
+
* @returns {object} 存在修改的对象
|
|
7
|
+
*/
|
|
8
|
+
export declare const translateJSONDiffToJson: (cacheObject: IJson, translateObject: IJson) => IJson;
|
|
9
|
+
/**
|
|
10
|
+
* 获取缓存文件
|
|
11
|
+
* @param {string} filePath 缓存文件路径
|
|
12
|
+
* @returns {Promise<{key:value}>}
|
|
13
|
+
*/
|
|
14
|
+
export declare const getCacheFileSync: (filePath: string) => Promise<IJson>;
|
|
15
|
+
/**
|
|
16
|
+
* 注册语言缓存文件
|
|
17
|
+
* @param {string} language
|
|
18
|
+
*/
|
|
19
|
+
export declare const registerLanguageCacheFile: (params: IRegisterLanguageCacheFile) => Promise<void>;
|
|
20
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/lib/cache/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,EAAE,0BAA0B,EAAE,MAAM,aAAa,CAAC;AAEhE;;;;;GAKG;AACH,eAAO,MAAM,uBAAuB,gBACrB,KAAK,mBACD,KAAK,UAiBvB,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,aAAoB,MAAM,KAAG,OAAO,CAAC,KAAK,CAMtE,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,yBAAyB,WAC5B,0BAA0B,kBAmBnC,CAAC"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
import path from "path";
|
|
11
|
+
import fs from "fs";
|
|
12
|
+
import { notExistsToCreateFile, readJsonFileSync } from "../utils.js";
|
|
13
|
+
/**
|
|
14
|
+
* 和翻译缓存json文件对比 返回存在更改的json文件
|
|
15
|
+
* @param {object} cacheObject 已经缓存的对象
|
|
16
|
+
* @param {object} translateObject 需要翻译的对象
|
|
17
|
+
* @returns {object} 存在修改的对象
|
|
18
|
+
*/
|
|
19
|
+
export const translateJSONDiffToJson = (cacheObject, translateObject) => {
|
|
20
|
+
if (Object.values(cacheObject).length === 0)
|
|
21
|
+
return translateObject;
|
|
22
|
+
// json文件内容diff
|
|
23
|
+
const pendingTranslateMap = {};
|
|
24
|
+
Object.entries(translateObject).forEach(([key, value]) => {
|
|
25
|
+
//不存在该key 是新增的key
|
|
26
|
+
if (!cacheObject[key]) {
|
|
27
|
+
pendingTranslateMap[key] = value;
|
|
28
|
+
}
|
|
29
|
+
// 存在缓存key但是内容不一样 需要重新翻译
|
|
30
|
+
else if (translateObject[key] !== cacheObject[key]) {
|
|
31
|
+
pendingTranslateMap[key] = value;
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
return pendingTranslateMap;
|
|
35
|
+
};
|
|
36
|
+
/**
|
|
37
|
+
* 获取缓存文件
|
|
38
|
+
* @param {string} filePath 缓存文件路径
|
|
39
|
+
* @returns {Promise<{key:value}>}
|
|
40
|
+
*/
|
|
41
|
+
export const getCacheFileSync = (filePath) => __awaiter(void 0, void 0, void 0, function* () {
|
|
42
|
+
if (fs.existsSync(filePath)) {
|
|
43
|
+
return yield readJsonFileSync(filePath);
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
return {};
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
/**
|
|
50
|
+
* 注册语言缓存文件
|
|
51
|
+
* @param {string} language
|
|
52
|
+
*/
|
|
53
|
+
export const registerLanguageCacheFile = (params) => __awaiter(void 0, void 0, void 0, function* () {
|
|
54
|
+
const { jsonMap, sourceFilePath, fileName, language, folderName } = params;
|
|
55
|
+
const cacheFilePath = path.join(folderName, language, fileName);
|
|
56
|
+
const sourceObject = yield readJsonFileSync(sourceFilePath);
|
|
57
|
+
const cacheObject = yield readJsonFileSync(cacheFilePath);
|
|
58
|
+
Object.entries(jsonMap).forEach(([key, value]) => {
|
|
59
|
+
cacheObject[key] = sourceObject[key];
|
|
60
|
+
});
|
|
61
|
+
if (Object.values(jsonMap).length === 0)
|
|
62
|
+
return;
|
|
63
|
+
notExistsToCreateFile(folderName);
|
|
64
|
+
notExistsToCreateFile(`${folderName}/${language}`);
|
|
65
|
+
yield fs.writeFileSync(cacheFilePath, JSON.stringify(cacheObject, null, 2), "utf8");
|
|
66
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/lib/log/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAGjD,wBAAgB,cAAc,CAAC,MAAM,EAAE,kBAAkB,QAexD"}
|
package/lib/log/index.js
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import fs from "fs";
|
|
2
|
+
export function logErrorToFile(params) {
|
|
3
|
+
const { error, key, language, fileName } = params;
|
|
4
|
+
const logMessage = `${new Date().toISOString()} - Error: ${error.message}
|
|
5
|
+
\nLanguage: ${language}
|
|
6
|
+
\nFileName: ${fileName}
|
|
7
|
+
\nkey:${key}
|
|
8
|
+
\nStack: ${error.stack}\n\n`;
|
|
9
|
+
fs.appendFile("error.log", logMessage, (err) => {
|
|
10
|
+
if (err) {
|
|
11
|
+
console.error("无法写入日志文件:", err);
|
|
12
|
+
}
|
|
13
|
+
else {
|
|
14
|
+
console.log("错误日志已写入 error.log 文件");
|
|
15
|
+
}
|
|
16
|
+
});
|
|
17
|
+
}
|
package/lib/support.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"support.d.ts","sourceRoot":"","sources":["../src/lib/support.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAC;AAE9C,eAAO,MAAM,oBAAoB,EAAE,kBAqGlC,CAAC"}
|
package/lib/support.js
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
export const SUPPORT_LANGUAGE_MAP = {
|
|
2
|
+
en: {
|
|
3
|
+
code: "en",
|
|
4
|
+
name: "英语",
|
|
5
|
+
},
|
|
6
|
+
["zh-CN"]: {
|
|
7
|
+
code: "zh-CN",
|
|
8
|
+
name: "简体中文",
|
|
9
|
+
},
|
|
10
|
+
["zh-TW"]: {
|
|
11
|
+
code: "zh-TW",
|
|
12
|
+
name: "繁体中文",
|
|
13
|
+
},
|
|
14
|
+
ja: {
|
|
15
|
+
code: "ja",
|
|
16
|
+
name: "日语",
|
|
17
|
+
},
|
|
18
|
+
ar: {
|
|
19
|
+
code: "ar",
|
|
20
|
+
name: "阿拉伯语",
|
|
21
|
+
},
|
|
22
|
+
bn: {
|
|
23
|
+
code: "bn",
|
|
24
|
+
name: "孟加拉语",
|
|
25
|
+
},
|
|
26
|
+
de: {
|
|
27
|
+
code: "de",
|
|
28
|
+
name: "德语",
|
|
29
|
+
},
|
|
30
|
+
["es-ES"]: {
|
|
31
|
+
code: "es-ES",
|
|
32
|
+
name: "西班牙语",
|
|
33
|
+
},
|
|
34
|
+
fr: {
|
|
35
|
+
code: "fr",
|
|
36
|
+
name: "法语",
|
|
37
|
+
},
|
|
38
|
+
hi: {
|
|
39
|
+
code: "hi",
|
|
40
|
+
name: "印地语",
|
|
41
|
+
},
|
|
42
|
+
id: {
|
|
43
|
+
code: "id",
|
|
44
|
+
name: "印度尼西亚语",
|
|
45
|
+
},
|
|
46
|
+
it: {
|
|
47
|
+
code: "it",
|
|
48
|
+
name: "意大利语",
|
|
49
|
+
},
|
|
50
|
+
ko: {
|
|
51
|
+
code: "ko",
|
|
52
|
+
name: "韩语",
|
|
53
|
+
},
|
|
54
|
+
ms: {
|
|
55
|
+
code: "ms",
|
|
56
|
+
name: "马来语",
|
|
57
|
+
},
|
|
58
|
+
my: {
|
|
59
|
+
code: "my",
|
|
60
|
+
name: "缅甸语",
|
|
61
|
+
},
|
|
62
|
+
["ne-NP"]: {
|
|
63
|
+
code: "ne-NP",
|
|
64
|
+
name: "尼泊尔语",
|
|
65
|
+
},
|
|
66
|
+
nl: {
|
|
67
|
+
code: "nl",
|
|
68
|
+
name: "荷兰语",
|
|
69
|
+
},
|
|
70
|
+
pl: {
|
|
71
|
+
code: "pl",
|
|
72
|
+
name: "波兰语",
|
|
73
|
+
},
|
|
74
|
+
["pt-PT"]: {
|
|
75
|
+
code: "pt-PT",
|
|
76
|
+
name: "葡萄牙语",
|
|
77
|
+
},
|
|
78
|
+
ru: {
|
|
79
|
+
code: "ru",
|
|
80
|
+
name: "俄罗斯语",
|
|
81
|
+
},
|
|
82
|
+
tl: {
|
|
83
|
+
code: "tl",
|
|
84
|
+
name: "菲律宾语",
|
|
85
|
+
},
|
|
86
|
+
tr: {
|
|
87
|
+
code: "tr",
|
|
88
|
+
name: "土耳其语",
|
|
89
|
+
},
|
|
90
|
+
vi: {
|
|
91
|
+
code: "vi",
|
|
92
|
+
name: "越南语",
|
|
93
|
+
},
|
|
94
|
+
uk: {
|
|
95
|
+
code: "uk",
|
|
96
|
+
name: "乌克兰语",
|
|
97
|
+
},
|
|
98
|
+
["ur-PK"]: {
|
|
99
|
+
code: "ur-PK",
|
|
100
|
+
name: "乌尔都语",
|
|
101
|
+
},
|
|
102
|
+
};
|
package/lib/utils.d.ts
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { ICreateJsonFileParams } from "../types";
|
|
2
|
+
/**
|
|
3
|
+
* 不存在的文件夹则创建
|
|
4
|
+
* @param {string} path
|
|
5
|
+
*/
|
|
6
|
+
export declare const notExistsToCreateFile: (path: string) => void;
|
|
7
|
+
/**
|
|
8
|
+
* 获取json文件 并返回 [[key,value],[key,value]...]]
|
|
9
|
+
* @param {*} path
|
|
10
|
+
* @returns
|
|
11
|
+
*/
|
|
12
|
+
export declare const readJsonFileSync: (path: string) => Promise<any>;
|
|
13
|
+
/**
|
|
14
|
+
* 创建json文件
|
|
15
|
+
* @param {string} fileName 文件名
|
|
16
|
+
* @param {string} folderName 文件夹名
|
|
17
|
+
* @param {string} language 语言环境
|
|
18
|
+
* @param {object} jsonData 文件数据
|
|
19
|
+
*/
|
|
20
|
+
export declare const createJsonFile: (params: ICreateJsonFileParams) => void;
|
|
21
|
+
export declare const getRandomNumber: (min: number, max: number) => number;
|
|
22
|
+
export declare const isDirectoryPath: (path: string) => boolean;
|
|
23
|
+
export declare const readFileOfDirSync: (dirPath: string) => string[];
|
|
24
|
+
export declare function chunkArray<T extends object>(array: T[], chunkSize: number): T[][];
|
|
25
|
+
//# sourceMappingURL=utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/lib/utils.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,qBAAqB,EAAE,MAAM,UAAU,CAAC;AAEjD;;;GAGG;AACH,eAAO,MAAM,qBAAqB,SAAU,MAAM,SAGjD,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,SAAgB,MAAM,iBAUlD,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,cAAc,WAAY,qBAAqB,SAS3D,CAAC;AAEF,eAAO,MAAM,eAAe,QAAS,MAAM,OAAO,MAAM,WAEvD,CAAC;AAEF,eAAO,MAAM,eAAe,SAAU,MAAM,YAG3C,CAAC;AAEF,eAAO,MAAM,iBAAiB,YAAa,MAAM,aAKhD,CAAC;AAEF,wBAAgB,UAAU,CAAC,CAAC,SAAS,MAAM,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE,SAAS,EAAE,MAAM,SASzE"}
|
package/lib/utils.js
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
import path from "path";
|
|
11
|
+
import fs from "fs";
|
|
12
|
+
/**
|
|
13
|
+
* 不存在的文件夹则创建
|
|
14
|
+
* @param {string} path
|
|
15
|
+
*/
|
|
16
|
+
export const notExistsToCreateFile = (path) => {
|
|
17
|
+
if (fs.existsSync(path))
|
|
18
|
+
return;
|
|
19
|
+
fs.mkdirSync(path);
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* 获取json文件 并返回 [[key,value],[key,value]...]]
|
|
23
|
+
* @param {*} path
|
|
24
|
+
* @returns
|
|
25
|
+
*/
|
|
26
|
+
export const readJsonFileSync = (path) => __awaiter(void 0, void 0, void 0, function* () {
|
|
27
|
+
try {
|
|
28
|
+
if (!fs.existsSync(path))
|
|
29
|
+
return {};
|
|
30
|
+
const jsonStr = yield fs.readFileSync(path, "utf8");
|
|
31
|
+
// 将JSON字符串解析为对象
|
|
32
|
+
return JSON.parse(jsonStr);
|
|
33
|
+
}
|
|
34
|
+
catch (error) {
|
|
35
|
+
console.error("解析JSON时出错:", error);
|
|
36
|
+
return {};
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
/**
|
|
40
|
+
* 创建json文件
|
|
41
|
+
* @param {string} fileName 文件名
|
|
42
|
+
* @param {string} folderName 文件夹名
|
|
43
|
+
* @param {string} language 语言环境
|
|
44
|
+
* @param {object} jsonData 文件数据
|
|
45
|
+
*/
|
|
46
|
+
export const createJsonFile = (params) => {
|
|
47
|
+
const { fileName, folderName, jsonData, language } = params;
|
|
48
|
+
notExistsToCreateFile(folderName);
|
|
49
|
+
notExistsToCreateFile(path.resolve(`${folderName}/${language}`));
|
|
50
|
+
fs.writeFileSync(path.resolve(`${folderName}/${language}/${fileName}`), JSON.stringify(jsonData, null, 2), "utf8");
|
|
51
|
+
};
|
|
52
|
+
export const getRandomNumber = (min, max) => {
|
|
53
|
+
return Math.floor(Math.random() * (max - min + 1)) + min;
|
|
54
|
+
};
|
|
55
|
+
export const isDirectoryPath = (path) => {
|
|
56
|
+
if (!fs.existsSync(path))
|
|
57
|
+
return false;
|
|
58
|
+
return fs.statSync(path).isDirectory();
|
|
59
|
+
};
|
|
60
|
+
export const readFileOfDirSync = (dirPath) => {
|
|
61
|
+
if (!isDirectoryPath(dirPath))
|
|
62
|
+
return [];
|
|
63
|
+
const files = fs.readdirSync(dirPath);
|
|
64
|
+
// 筛选出所有文件夹
|
|
65
|
+
return files.filter((file) => path.extname(file) === ".json");
|
|
66
|
+
};
|
|
67
|
+
export function chunkArray(array, chunkSize) {
|
|
68
|
+
const result = [];
|
|
69
|
+
let index = 0;
|
|
70
|
+
while (index < array.length) {
|
|
71
|
+
result.push(array.slice(index, index + chunkSize));
|
|
72
|
+
index += chunkSize;
|
|
73
|
+
}
|
|
74
|
+
return result;
|
|
75
|
+
}
|