gpt-po 1.0.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 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
+ }