gpt-po 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
package/README.md ADDED
@@ -0,0 +1,55 @@
1
+ # PO File Translation Tool for ChatGPT
2
+
3
+ Translation tool for gettext (po) files that supports custom system prompts and user dictionaries. It also supports translating specified po files to a designated target language and updating po files based on pot files.
4
+
5
+ Read in other languages: English | [简体中文](./Readme_zh-CN.md)
6
+
7
+ ## Installation
8
+
9
+ ```
10
+ npm install openai
11
+ ```
12
+
13
+ Set `OPENAI_API_KEY` before using this tool.
14
+
15
+ **It is recommended to use the paid OpenAI API to improve translation speed, as the free OpenAI API is slower (only 3 translations per minute) and has usage restrictions.**
16
+
17
+ ## Usage Scenarios
18
+
19
+ - `gpt-po sync --po <file> --pot <file>` to update po files based on pot files. First update the po file and then translate it.
20
+ - `gpt-po --po <file>` to translate specified po files to a designated target language. By default, the target language is Simplified Chinese.
21
+ - `gpt-po userdict` to modify or view user dictionaries
22
+ - `gpt-po systemprompt` to modify or view system prompts, if you are not sure how to use it, you can leave it alone
23
+
24
+ ```
25
+ Usage: gpt-po [command] [options]
26
+
27
+ command tool for translate po files by gpt
28
+
29
+ Options:
30
+ -V, --version output the version number
31
+ -h, --help display help for command
32
+
33
+ Commands:
34
+ translate [options] translate po file (default command)
35
+ sync [options] update po from pot file
36
+ systemprompt open/edit system prompt
37
+ userdict open/edit user dictionary
38
+ help [command] display help for command
39
+ ```
40
+
41
+ ```
42
+ Usage: gpt-po [options]
43
+
44
+ translate po file (default command)
45
+
46
+ Options:
47
+ -k, --key <key> openai api key (env: OPENAI_API_KEY)
48
+ --host <host> openai api host (env: OPENAI_API_HOST)
49
+ --model <model> openai model (choices: "gpt-4", "gpt-4-0314", "gpt-4-32k", "gpt-4-32k-0314", "gpt-3.5-turbo", "gpt-3.5-turbo-0301",
50
+ default: "gpt-3.5-turbo")
51
+ --po <file> po file path
52
+ -l, --lang <lang> target language (default: "simplified chinese")
53
+ -o, --output <file> output file path, overwirte po file by default
54
+ -h, --help display help for command
55
+ ```
@@ -0,0 +1,58 @@
1
+ {
2
+ "name": "gpt-po",
3
+ "version": "1.0.0",
4
+ "description": "command tool for translate po files by gpt",
5
+ "main": "lib/src/index.js",
6
+ "bin": {
7
+ "gpt-po": "lib/src/index.js"
8
+ },
9
+ "scripts": {
10
+ "start": "node lib/src/index.js",
11
+ "test": "echo \"Error: no test specified\" && exit 1",
12
+ "prebuild": "rimraf ./lib",
13
+ "build": "tsc",
14
+ "postbuild": "ncp ./src/ ./lib/src/ \"--filter=^(?!.*\\.ts$).*$\"",
15
+ "format": "prettier --write \"src/**/*.ts\" \"src/**/*.js\"",
16
+ "lint": "tslint -p tsconfig.json"
17
+ },
18
+ "repository": {
19
+ "type": "git",
20
+ "url": "git+https://github.com/ryanhex53/gpt-po.git"
21
+ },
22
+ "author": "Ryan",
23
+ "license": "MIT",
24
+ "bugs": {
25
+ "url": "https://github.com/ryanhex53/gpt-po/issues"
26
+ },
27
+ "files": [
28
+ "lib/**/*"
29
+ ],
30
+ "homepage": "https://github.com/ryanhex53/gpt-po#readme",
31
+ "keywords": [
32
+ "gettext",
33
+ "po",
34
+ "pot",
35
+ "chatgpt",
36
+ "openai"
37
+ ],
38
+ "devDependencies": {
39
+ "@types/gettext-parser": "^4.0.2",
40
+ "@types/jest": "^29.5.1",
41
+ "jest": "^29.5.0",
42
+ "ncp": "^2.0.0",
43
+ "prettier": "^3.0.0-alpha.7-for-vscode",
44
+ "rimraf": "^5.0.0",
45
+ "ts-jest": "^29.1.0",
46
+ "tslint": "^6.1.3",
47
+ "tslint-config-prettier": "^1.18.0",
48
+ "typescript": "^5.0.4"
49
+ },
50
+ "dependencies": {
51
+ "commander": "^10.0.1",
52
+ "gettext-parser": "^6.0.0",
53
+ "openai": "^3.2.1"
54
+ },
55
+ "engines": {
56
+ "node": ">=12.0.0"
57
+ }
58
+ }
@@ -0,0 +1,3 @@
1
+ {
2
+ "example" : "示例"
3
+ }
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
@@ -0,0 +1,83 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
4
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
5
+ return new (P || (P = Promise))(function (resolve, reject) {
6
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
7
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
8
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
9
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
10
+ });
11
+ };
12
+ Object.defineProperty(exports, "__esModule", { value: true });
13
+ const commander_1 = require("commander");
14
+ const os_1 = require("os");
15
+ const path_1 = require("path");
16
+ const pkg = require("../package.json");
17
+ const sync_1 = require("./sync");
18
+ const translate_1 = require("./translate");
19
+ const utils_1 = require("./utils");
20
+ const program = new commander_1.Command();
21
+ program.name(pkg.name).version(pkg.version).description(pkg.description);
22
+ program
23
+ .command("translate", { isDefault: true })
24
+ .description("translate po file (default command)")
25
+ .addOption(new commander_1.Option("-k, --key <key>", "openai api key").env("OPENAI_API_KEY"))
26
+ .addOption(new commander_1.Option("--host <host>", "openai api host").env("OPENAI_API_HOST"))
27
+ .addOption(new commander_1.Option("--model <model>", "openai model")
28
+ .default("gpt-3.5-turbo")
29
+ .choices([
30
+ "gpt-4",
31
+ "gpt-4-0314",
32
+ "gpt-4-32k",
33
+ "gpt-4-32k-0314",
34
+ "gpt-3.5-turbo",
35
+ "gpt-3.5-turbo-0301",
36
+ ]))
37
+ .requiredOption("--po <file>", "po file path")
38
+ .option("-src, --source <lang>", "source language", "english")
39
+ .requiredOption("-l, --lang <lang>", "target language", "simplified chinese")
40
+ .option("-o, --output <file>", "output file path, overwirte po file by default")
41
+ .action(({ key, host, model, po, source, lang, output }) => __awaiter(void 0, void 0, void 0, function* () {
42
+ if (host) {
43
+ process.env.OPENAI_API_HOST = host;
44
+ }
45
+ if (key) {
46
+ process.env.OPENAI_API_KEY = key;
47
+ }
48
+ yield (0, translate_1.translatePo)(model, po, source, lang, output);
49
+ }));
50
+ program
51
+ .command("sync")
52
+ .description("update po from pot file")
53
+ .requiredOption("--po <file>", "po file path")
54
+ .requiredOption("--pot <file>", "pot file path")
55
+ .action(({ po, pot }) => __awaiter(void 0, void 0, void 0, function* () {
56
+ yield (0, sync_1.sync)(po, pot);
57
+ }));
58
+ // program command `systemprompt` with help text `open/edit system prompt`
59
+ program
60
+ .command("systemprompt")
61
+ .description("open/edit system prompt")
62
+ .action(() => {
63
+ // open `systemprompt.txt` file by system text default editor
64
+ const copyFile = __dirname + "/systemprompt.txt";
65
+ // user home path
66
+ const promptHome = (0, path_1.join)((0, os_1.homedir)(), "systemprompt.txt");
67
+ (0, utils_1.copyFileIfNotExists)(promptHome, copyFile);
68
+ (0, utils_1.openFileByDefault)(promptHome);
69
+ });
70
+ // program command `userdict` with help text `open/edit user dictionary`
71
+ program
72
+ .command("userdict")
73
+ .description("open/edit user dictionary")
74
+ .action(() => {
75
+ // open `dictionary.json` file by system text default editor
76
+ const copyFile = __dirname + "/dictionary.json";
77
+ // user home path
78
+ const dictHome = (0, path_1.join)((0, os_1.homedir)(), "dictionary.json");
79
+ (0, utils_1.copyFileIfNotExists)(dictHome, copyFile);
80
+ (0, utils_1.openFileByDefault)(dictHome);
81
+ });
82
+ program.parse(process.argv);
83
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export declare function sync(po: string, pot: string): Promise<void>;
@@ -0,0 +1,33 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.sync = void 0;
13
+ const utils_1 = require("./utils");
14
+ function sync(po, pot) {
15
+ return __awaiter(this, void 0, void 0, function* () {
16
+ const potrans = yield (0, utils_1.parsePo)(po);
17
+ const potrans2 = yield (0, utils_1.parsePo)(pot);
18
+ for (const [ctx, entries] of Object.entries(potrans2.translations)) {
19
+ // copy msgstr from potrans to potrans2
20
+ for (const [msgid, _] of Object.entries(entries)) {
21
+ if (potrans.translations[ctx] &&
22
+ potrans.translations[ctx][msgid] &&
23
+ potrans.translations[ctx][msgid].msgstr[0]) {
24
+ potrans2.translations[ctx][msgid] = potrans.translations[ctx][msgid];
25
+ }
26
+ }
27
+ }
28
+ potrans.translations = potrans2.translations;
29
+ yield (0, utils_1.compilePo)(potrans, po);
30
+ });
31
+ }
32
+ exports.sync = sync;
33
+ //# sourceMappingURL=sync.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sync.js","sourceRoot":"","sources":["../../src/sync.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,mCAA6C;AAE7C,SAAsB,IAAI,CAAC,EAAU,EAAE,GAAW;;QAChD,MAAM,OAAO,GAAG,MAAM,IAAA,eAAO,EAAC,EAAE,CAAC,CAAC;QAClC,MAAM,QAAQ,GAAG,MAAM,IAAA,eAAO,EAAC,GAAG,CAAC,CAAC;QAEpC,KAAK,MAAM,CAAC,GAAG,EAAE,OAAO,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAC,EAAE;YAClE,uCAAuC;YACvC,KAAK,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE;gBAChD,IACE,OAAO,CAAC,YAAY,CAAC,GAAG,CAAC;oBACzB,OAAO,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC;oBAChC,OAAO,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAC1C;oBACA,QAAQ,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,GAAG,OAAO,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC;iBACtE;aACF;SACF;QACD,OAAO,CAAC,YAAY,GAAG,QAAQ,CAAC,YAAY,CAAC;QAC7C,MAAM,IAAA,iBAAS,EAAC,OAAO,EAAE,EAAE,CAAC,CAAC;IAC/B,CAAC;CAAA;AAlBD,oBAkBC"}
@@ -0,0 +1 @@
1
+ You are a translation expert, follow the user's instructions carefully, translate the text in a colloquial, professional and elegant manner without sounding like a machine translation. Remember to only translate the text and not further interpret it.
@@ -0,0 +1,4 @@
1
+ import { OpenAIApi } from "openai";
2
+ export declare function init(force?: boolean): OpenAIApi;
3
+ export declare function translate(text: string, src: string, lang: string, model?: string): Promise<import("axios").AxiosResponse<import("openai").CreateChatCompletionResponse, any>>;
4
+ export declare function translatePo(model: string | undefined, po: string, source: string, lang: string, output: string): Promise<void>;
@@ -0,0 +1,134 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.translatePo = exports.translate = exports.init = void 0;
13
+ const fs = require("fs");
14
+ const openai_1 = require("openai");
15
+ const os_1 = require("os");
16
+ const path_1 = require("path");
17
+ const pkg = require("../package.json");
18
+ const utils_1 = require("./utils");
19
+ let _openai;
20
+ let _systemprompt;
21
+ let _userdict;
22
+ function init(force) {
23
+ if (!_openai || force) {
24
+ const configuration = new openai_1.Configuration({
25
+ apiKey: process.env.OPENAI_API_KEY,
26
+ });
27
+ if (process.env.OPENAI_API_HOST) {
28
+ configuration.basePath = process.env.OPENAI_API_HOST.replace(/\/+$/, "") + "/v1";
29
+ }
30
+ _openai = new openai_1.OpenAIApi(configuration);
31
+ }
32
+ // load systemprompt.txt from homedir
33
+ if (!_systemprompt || force) {
34
+ const systemprompt = (0, path_1.join)((0, os_1.homedir)(), "systemprompt.txt");
35
+ (0, utils_1.copyFileIfNotExists)(systemprompt, (0, path_1.join)(__dirname, "systemprompt.txt"));
36
+ _systemprompt = fs.readFileSync(systemprompt, "utf-8");
37
+ }
38
+ // load dictionary.json from homedir
39
+ if (!_userdict || force) {
40
+ const userdict = (0, path_1.join)((0, os_1.homedir)(), "dictionary.json");
41
+ (0, utils_1.copyFileIfNotExists)(userdict, (0, path_1.join)(__dirname, "dictionary.json"));
42
+ _userdict = JSON.parse(fs.readFileSync(userdict, "utf-8"));
43
+ }
44
+ return _openai;
45
+ }
46
+ exports.init = init;
47
+ function translate(text, src, lang, model = "gpt-3.5-turbo") {
48
+ const openai = init();
49
+ const dicts = Object.entries(_userdict)
50
+ .map(([k, v]) => [
51
+ { role: "user", content: k },
52
+ { role: "assistant", content: v },
53
+ ])
54
+ .flat();
55
+ return openai.createChatCompletion({
56
+ model,
57
+ temperature: 0.5,
58
+ n: 1,
59
+ messages: [
60
+ { role: "system", content: _systemprompt },
61
+ {
62
+ role: "user",
63
+ content: `Translate incoming ${src} content into ${lang}, only the translated content can be returned, don't ask question.`,
64
+ },
65
+ {
66
+ role: "assistant",
67
+ content: "Sure, Please send me the content that needs to be translated.",
68
+ },
69
+ // add userdict here
70
+ ...dicts,
71
+ { role: "user", content: text },
72
+ ],
73
+ }, {
74
+ timeout: 20000,
75
+ });
76
+ }
77
+ exports.translate = translate;
78
+ function translatePo(model = "gpt-3.5-turbo", po, source, lang, output) {
79
+ var _a;
80
+ return __awaiter(this, void 0, void 0, function* () {
81
+ const potrans = yield (0, utils_1.parsePo)(po);
82
+ const list = [];
83
+ for (const [ctx, entries] of Object.entries(potrans.translations)) {
84
+ for (const [msgid, trans] of Object.entries(entries)) {
85
+ if (!trans.msgstr[0]) {
86
+ list.push(trans);
87
+ }
88
+ }
89
+ }
90
+ if (list.length == 0) {
91
+ console.log("nothing needs translate");
92
+ return;
93
+ }
94
+ let err429 = false;
95
+ let modified = false;
96
+ for (let i = 0; i < list.length; i++) {
97
+ if (i == 0)
98
+ (0, utils_1.printProgress)(i, list.length);
99
+ if (err429) {
100
+ // sleep for 20 seconds.
101
+ yield new Promise((resolve) => setTimeout(resolve, 20000));
102
+ }
103
+ const trans = list[i];
104
+ try {
105
+ const res = yield translate(trans.msgid, source, lang, model);
106
+ trans.msgstr[0] = ((_a = res.data.choices[0].message) === null || _a === void 0 ? void 0 : _a.content) || trans.msgstr[0];
107
+ modified = true;
108
+ (0, utils_1.printProgress)(i + 1, list.length);
109
+ }
110
+ catch (error) {
111
+ if (error.response) {
112
+ if (error.response.status == 429) {
113
+ // caused by rate limit exceeded, should sleep for 20 seconds.
114
+ err429 = true;
115
+ --i;
116
+ }
117
+ else {
118
+ console.error(error.response.status);
119
+ // console.log(error.response.data);
120
+ }
121
+ }
122
+ else {
123
+ console.error(error.message);
124
+ }
125
+ }
126
+ }
127
+ if (modified) {
128
+ potrans.headers["Last-Translator"] = `gpt-po v${pkg.version}`;
129
+ yield (0, utils_1.compilePo)(potrans, output || po);
130
+ }
131
+ });
132
+ }
133
+ exports.translatePo = translatePo;
134
+ //# sourceMappingURL=translate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"translate.js","sourceRoot":"","sources":["../../src/translate.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ import { GetTextTranslations } from "gettext-parser";
2
+ export declare function copyFileIfNotExists(file: string, copyFile: string): void;
3
+ export declare function openFileByDefault(filePath: string): void;
4
+ export declare function parsePo(poFile: string, defaultCharset?: string): Promise<GetTextTranslations>;
5
+ export declare function compilePo(data: GetTextTranslations, poFile: string): Promise<void>;
6
+ export declare function printProgress(progress: number, total: number, extra?: string): void;
@@ -0,0 +1,60 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.printProgress = exports.compilePo = exports.parsePo = exports.openFileByDefault = exports.copyFileIfNotExists = void 0;
4
+ const fs = require("fs");
5
+ const child_process_1 = require("child_process");
6
+ const gettext_parser_1 = require("gettext-parser");
7
+ function copyFileIfNotExists(file, copyFile) {
8
+ // check if file exists else create it
9
+ try {
10
+ fs.accessSync(file, fs.constants.F_OK);
11
+ // check if the file is empty else copy the file
12
+ fs.statSync(file).size === 0 && fs.copyFileSync(copyFile, file);
13
+ }
14
+ catch (err) {
15
+ fs.copyFileSync(copyFile, file);
16
+ }
17
+ }
18
+ exports.copyFileIfNotExists = copyFileIfNotExists;
19
+ function openFileByDefault(filePath) {
20
+ // Use the 'open' command on macOS or 'start' command on Windows to open the file with the default system editor
21
+ const command = process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open";
22
+ // Spawn a new process for the default editor and pass the file name as an argument
23
+ (0, child_process_1.spawn)(command, [filePath], { shell: true });
24
+ }
25
+ exports.openFileByDefault = openFileByDefault;
26
+ function parsePo(poFile, defaultCharset) {
27
+ // read poFile as buffer, then parse it
28
+ return new Promise((resolve, reject) => {
29
+ fs.readFile(poFile, (err, buffer) => {
30
+ if (err)
31
+ reject(err);
32
+ var result = gettext_parser_1.po.parse(buffer, defaultCharset !== null && defaultCharset !== void 0 ? defaultCharset : "utf-8");
33
+ resolve(result);
34
+ });
35
+ });
36
+ }
37
+ exports.parsePo = parsePo;
38
+ function compilePo(data, poFile) {
39
+ const buffer = gettext_parser_1.po.compile(data);
40
+ return new Promise((resolve, reject) => {
41
+ fs.writeFile(poFile, buffer, (err) => {
42
+ if (err)
43
+ reject(err);
44
+ resolve();
45
+ });
46
+ });
47
+ }
48
+ exports.compilePo = compilePo;
49
+ function printProgress(progress, total, extra) {
50
+ const percent = Math.floor((progress / total) * 100);
51
+ const bar = Array(Math.floor(percent / 5))
52
+ .fill("█")
53
+ .join("");
54
+ const dots = Array(20 - Math.floor(percent / 5))
55
+ .fill("░")
56
+ .join("");
57
+ process.stdout.write(`\r${bar}${dots} ${percent}% ${extra || ""}`);
58
+ }
59
+ exports.printProgress = printProgress;
60
+ //# sourceMappingURL=utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.js","sourceRoot":"","sources":["../../src/utils.ts"],"names":[],"mappings":";;;AAAA,yBAAyB;AAEzB,iDAAsC;AACtC,mDAAyD;AAEzD,SAAgB,mBAAmB,CAAC,IAAY,EAAE,QAAgB;IAChE,sCAAsC;IACtC,IAAI;QACF,EAAE,CAAC,UAAU,CAAC,IAAI,EAAE,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;QACvC,gDAAgD;QAChD,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;KACjE;IAAC,OAAO,GAAG,EAAE;QACZ,EAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;KACjC;AACH,CAAC;AATD,kDASC;AAED,SAAgB,iBAAiB,CAAC,QAAgB;IAChD,gHAAgH;IAChH,MAAM,OAAO,GACX,OAAO,CAAC,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,UAAU,CAAC;IAC/F,mFAAmF;IACnF,IAAA,qBAAK,EAAC,OAAO,EAAE,CAAC,QAAQ,CAAC,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;AAC9C,CAAC;AAND,8CAMC;AAED,SAAgB,OAAO,CAAC,MAAc,EAAE,cAAuB;IAC7D,uCAAuC;IACvC,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,EAAE,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,EAAE;YAClC,IAAI,GAAG;gBAAE,MAAM,CAAC,GAAG,CAAC,CAAC;YACrB,IAAI,MAAM,GAAG,mBAAE,CAAC,KAAK,CAAC,MAAM,EAAE,cAAc,aAAd,cAAc,cAAd,cAAc,GAAI,OAAO,CAAC,CAAC;YACzD,OAAO,CAAC,MAAM,CAAC,CAAC;QAClB,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC;AATD,0BASC;AAED,SAAgB,SAAS,CAAC,IAAyB,EAAE,MAAc;IACjE,MAAM,MAAM,GAAG,mBAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IAChC,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,EAAE,CAAC,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,GAAG,EAAE,EAAE;YACnC,IAAI,GAAG;gBAAE,MAAM,CAAC,GAAG,CAAC,CAAC;YACrB,OAAO,EAAE,CAAC;QACZ,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC;AARD,8BAQC;AAED,SAAgB,aAAa,CAAC,QAAgB,EAAE,KAAa,EAAE,KAAc;IAC3E,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,QAAQ,GAAG,KAAK,CAAC,GAAG,GAAG,CAAC,CAAC;IACrD,MAAM,GAAG,GAAG,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,GAAG,CAAC,CAAC,CAAC;SACvC,IAAI,CAAC,GAAG,CAAC;SACT,IAAI,CAAC,EAAE,CAAC,CAAC;IACZ,MAAM,IAAI,GAAG,KAAK,CAAC,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,GAAG,CAAC,CAAC,CAAC;SAC7C,IAAI,CAAC,GAAG,CAAC;SACT,IAAI,CAAC,EAAE,CAAC,CAAC;IACZ,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,GAAG,GAAG,IAAI,IAAI,OAAO,KAAK,KAAK,IAAI,EAAE,EAAE,CAAC,CAAC;AACrE,CAAC;AATD,sCASC"}
package/package.json ADDED
@@ -0,0 +1,58 @@
1
+ {
2
+ "name": "gpt-po",
3
+ "version": "1.0.0",
4
+ "description": "command tool for translate po files by gpt",
5
+ "main": "lib/src/index.js",
6
+ "bin": {
7
+ "gpt-po": "lib/src/index.js"
8
+ },
9
+ "scripts": {
10
+ "start": "node lib/src/index.js",
11
+ "test": "echo \"Error: no test specified\" && exit 1",
12
+ "prebuild": "rimraf ./lib",
13
+ "build": "tsc",
14
+ "postbuild": "ncp ./src/ ./lib/src/ \"--filter=^(?!.*\\.ts$).*$\"",
15
+ "format": "prettier --write \"src/**/*.ts\" \"src/**/*.js\"",
16
+ "lint": "tslint -p tsconfig.json"
17
+ },
18
+ "repository": {
19
+ "type": "git",
20
+ "url": "git+https://github.com/ryanhex53/gpt-po.git"
21
+ },
22
+ "author": "Ryan",
23
+ "license": "MIT",
24
+ "bugs": {
25
+ "url": "https://github.com/ryanhex53/gpt-po/issues"
26
+ },
27
+ "files": [
28
+ "lib/**/*"
29
+ ],
30
+ "homepage": "https://github.com/ryanhex53/gpt-po#readme",
31
+ "keywords": [
32
+ "gettext",
33
+ "po",
34
+ "pot",
35
+ "chatgpt",
36
+ "openai"
37
+ ],
38
+ "devDependencies": {
39
+ "@types/gettext-parser": "^4.0.2",
40
+ "@types/jest": "^29.5.1",
41
+ "jest": "^29.5.0",
42
+ "ncp": "^2.0.0",
43
+ "prettier": "^3.0.0-alpha.7-for-vscode",
44
+ "rimraf": "^5.0.0",
45
+ "ts-jest": "^29.1.0",
46
+ "tslint": "^6.1.3",
47
+ "tslint-config-prettier": "^1.18.0",
48
+ "typescript": "^5.0.4"
49
+ },
50
+ "dependencies": {
51
+ "commander": "^10.0.1",
52
+ "gettext-parser": "^6.0.0",
53
+ "openai": "^3.2.1"
54
+ },
55
+ "engines": {
56
+ "node": ">=12.0.0"
57
+ }
58
+ }