gpt-po 1.1.1 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1 @@
1
+ buy_me_a_coffee: ryanhex
package/CHANGELOG.md ADDED
@@ -0,0 +1,17 @@
1
+ # Changelog
2
+
3
+ ## [1.2.0] - 2024-11-26
4
+ - Submit multiple entries per chat to boost speed and reduce tokens
5
+ - Command `systemprompt` has been removed
6
+ - Bug fixes
7
+
8
+ ## [1.1.2] - 2024-11-12
9
+ - Update command options for OpenAI model
10
+ - Dependency updates, target es2022, module(Nodejs 18+)
11
+
12
+ ## [1.0.11] - 2023-10-26
13
+ - Add `gpt-po remove` command
14
+ - improve prompt for translation
15
+
16
+ ## [1.0.9] - 2023-09-08
17
+ - Can add dictionaries for each languages
package/README.md CHANGED
@@ -7,6 +7,8 @@ Translation tool for gettext (po) files that supports custom system prompts and
7
7
 
8
8
  Read in other languages: English | [简体中文](./README_zh-CN.md)
9
9
 
10
+ <a href="https://buymeacoffee.com/ryanhex" target="_blank"><img src="https://cdn.buymeacoffee.com/buttons/default-red.png" alt="Buy Me A Coffee" height="41" width="174"></a>
11
+
10
12
  ## Installation
11
13
 
12
14
  ```
@@ -25,8 +27,6 @@ Set `OPENAI_API_KEY` before using this tool.
25
27
  - `gpt-po --dir .` Translate all po files in current directory to a designated target language.
26
28
  - `gpt-po userdict` Modify or view user dictionaries
27
29
  - `gpt-po userdict --explore` Explore user dictionaries, if you want add new dictionaries or modify existing dictionaries. dictionaries can be named as `dictionary-<lang>.json`, for example, `dictionary-zh.json` is the dictionary for Simplified Chinese.
28
- - `gpt-po systemprompt` Modify or view system prompts, if you are not sure how to use it, you can leave it alone
29
- - `gpt-po systemprompt --reset` Reset system prompts
30
30
 
31
31
  ```
32
32
  Usage: gpt-po [options] [command]
@@ -40,7 +40,6 @@ Options:
40
40
  Commands:
41
41
  translate [options] translate po file (default command)
42
42
  sync [options] update po from pot file
43
- systemprompt [options] open/edit system prompt
44
43
  userdict [options] open/edit user dictionary
45
44
  remove [options] remove po entries by options
46
45
  help [command] display help for command
@@ -54,8 +53,7 @@ translate po file (default command)
54
53
  Options:
55
54
  -k, --key <key> openai api key (env: OPENAI_API_KEY)
56
55
  --host <host> openai api host (env: OPENAI_API_HOST)
57
- --model <model> openai model (choices: "gpt-4o", "gpt-4-turbo", "gpt-4", "gpt-4-0314", "gpt-4-32k", "gpt-4-32k-0314", "gpt-3.5-turbo", "gpt-3.5-turbo-0301",
58
- default: "gpt-4o")
56
+ --model <model> openai model (default: "gpt-4o-mini", env: OPENAI_MODEL)
59
57
  --po <file> po file path
60
58
  --dir <dir> po file directory
61
59
  -src, --source <lang> source language (default: "english")
@@ -82,3 +80,14 @@ Options:
82
80
  -rc, --reference-contains <text> remove entries whose reference contains text, text can be a regular expression like /text/ig
83
81
  -h, --help display help for command
84
82
  ```
83
+
84
+ ```
85
+ Usage: gpt-po sync [options]
86
+
87
+ update po from pot file
88
+
89
+ Options:
90
+ --po <file> po file path
91
+ --pot <file> pot file path
92
+ -h, --help display help for command
93
+ ```
package/README_zh-CN.md CHANGED
@@ -7,6 +7,8 @@ gettext(po)文件翻译工具,支持自定义系统提示词和用户字典,
7
7
 
8
8
  使用其他语言阅读:[English](./README.md) | 简体中文
9
9
 
10
+ <a href="https://buymeacoffee.com/ryanhex" target="_blank"><img src="https://cdn.buymeacoffee.com/buttons/default-red.png" alt="请我喝杯咖啡" height="41" width="174"></a>
11
+
10
12
  ## 安装
11
13
 
12
14
  ```
@@ -27,8 +29,6 @@ npm install gpt-po
27
29
  - `gpt-po --dir .` 将当前目录下的所有 po 文件翻译成目标语言。
28
30
  - `gpt-po userdict` 修改或查看用户词典。
29
31
  - `gpt-po userdict --explore` 浏览用户词典,如果您想添加新词典或修改现有词典,词典可以命名为 `dictionary-<lang>.json`,例如 `dictionary-zh.json` 是简体中文词典。
30
- - `gpt-po systemprompt` 修改或查看系统提示,如果您不确定如何使用它,可以忽略。
31
- - `gpt-po systemprompt --reset` 重置系统提示。
32
32
 
33
33
  ```
34
34
  用法: gpt-po [options] [command]
@@ -42,7 +42,6 @@ npm install gpt-po
42
42
  命令:
43
43
  translate [options] 翻译 po 文件(默认命令)
44
44
  sync [options] 根据 pot 文件更新 po 文件
45
- systemprompt [options] 打开/编辑系统提示
46
45
  userdict [options] 打开/编辑用户词典
47
46
  remove [options] 通过选项删除 po 条目
48
47
  help [command] 显示命令帮助
@@ -56,7 +55,7 @@ npm install gpt-po
56
55
  选项:
57
56
  -k, --key <key> openai api key (环境变量: OPENAI_API_KEY)
58
57
  --host <host> openai api host (环境变量: OPENAI_API_HOST)
59
- --model <model> openai 模型 (选项: "gpt-4o", "gpt-4-turbo", "gpt-4", "gpt-4-0314", "gpt-4-32k", "gpt-4-32k-0314", "gpt-3.5-turbo", "gpt-3.5-turbo-0301", 默认: "gpt-4o")
58
+ --model <model> openai 模型 (默认: "gpt-4o-mini", 环境变量: OPENAI_MODEL)
60
59
  --po <file> po 文件路径
61
60
  --dir <dir> po 文件目录
62
61
  -src, --source <lang> 源语言 (默认: "english")
@@ -83,3 +82,14 @@ npm install gpt-po
83
82
  -rc, --reference-contains <text> 删除引用包含文本的条目,文本可以是正则表达式,例如 /text/ig
84
83
  -h, --help 显示命令帮助
85
84
  ```
85
+
86
+ ```
87
+ 用法: gpt-po sync [options]
88
+
89
+ 从 pot 文件中更新条目到 po 文件
90
+
91
+ Options:
92
+ --po <file> po 文件路径
93
+ --pot <file> pot 文件路径
94
+ -h, --help 显示命令帮助
95
+ ```
package/lib/package.json CHANGED
@@ -1,8 +1,9 @@
1
1
  {
2
2
  "name": "gpt-po",
3
- "version": "1.1.1",
3
+ "version": "1.2.0",
4
4
  "description": "command tool for translate po files by gpt",
5
5
  "main": "lib/src/index.js",
6
+ "type": "module",
6
7
  "bin": {
7
8
  "gpt-po": "lib/src/index.js"
8
9
  },
@@ -33,23 +34,23 @@
33
34
  "openai"
34
35
  ],
35
36
  "devDependencies": {
36
- "@types/gettext-parser": "^4.0.2",
37
- "@types/jest": "^29.5.1",
38
- "jest": "^29.5.0",
37
+ "@types/gettext-parser": "^4.0.4",
38
+ "@types/jest": "^29.5.12",
39
+ "jest": "^29.7.0",
39
40
  "ncp": "^2.0.0",
40
- "prettier": "^3.0.3",
41
- "rimraf": "^5.0.0",
42
- "ts-jest": "^29.1.0",
41
+ "prettier": "^3.3.3",
42
+ "rimraf": "^6.0.1",
43
+ "ts-jest": "^29.2.5",
43
44
  "tslint": "^6.1.3",
44
45
  "tslint-config-prettier": "^1.18.0",
45
- "typescript": "^5.0.4"
46
+ "typescript": "^5.5.4"
46
47
  },
47
48
  "dependencies": {
48
- "commander": "^10.0.1",
49
- "gettext-parser": "^6.0.0",
50
- "openai": "^3.2.1"
49
+ "commander": "^12.1.0",
50
+ "gettext-parser": "^8.0.0",
51
+ "openai": "^4.56.0"
51
52
  },
52
53
  "engines": {
53
- "node": ">=12.0.0"
54
+ "node": ">=18.0.0"
54
55
  }
55
56
  }
@@ -1,2 +1,2 @@
1
- #!/usr/bin/env node
1
+ #!/usr/bin/env node --no-warnings=ExperimentalWarning
2
2
  export {};
package/lib/src/index.js CHANGED
@@ -1,48 +1,30 @@
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 pkg = require("../package.json");
15
- const sync_1 = require("./sync");
16
- const translate_1 = require("./translate");
17
- const utils_1 = require("./utils");
18
- const manipulate_1 = require("./manipulate");
19
- const program = new commander_1.Command();
1
+ #!/usr/bin/env node --no-warnings=ExperimentalWarning
2
+ import { Command, Option } from "commander";
3
+ import path from "path";
4
+ import { fileURLToPath } from "url";
5
+ import pkg from "../package.json" with { type: "json" };
6
+ import { sync } from "./sync.js";
7
+ import { init, translatePo, translatePoDir } from "./translate.js";
8
+ import { copyFileIfNotExists, compilePo, findConfig, openFileByDefault, openFileExplorer, parsePo } from "./utils.js";
9
+ import { removeByOptions } from "./manipulate.js";
10
+ const __filename = fileURLToPath(import.meta.url);
11
+ const __dirname = path.dirname(__filename);
12
+ const program = new Command();
20
13
  program.name(pkg.name).version(pkg.version).description(pkg.description);
21
14
  program
22
15
  .command("translate", { isDefault: true })
23
16
  .description("translate po file (default command)")
24
- .addOption(new commander_1.Option("-k, --key <key>", "openai api key").env("OPENAI_API_KEY"))
25
- .addOption(new commander_1.Option("--host <host>", "openai api host").env("OPENAI_API_HOST"))
26
- .addOption(new commander_1.Option("--model <model>", "openai model")
27
- .default("gpt-4o")
28
- .choices([
29
- "gpt-4o",
30
- "gpt-4-turbo",
31
- "gpt-4",
32
- "gpt-4-0314",
33
- "gpt-4-32k",
34
- "gpt-4-32k-0314",
35
- "gpt-3.5-turbo",
36
- "gpt-3.5-turbo-0301",
37
- ]))
38
- .addOption(new commander_1.Option("--po <file>", "po file path").conflicts("dir"))
39
- .addOption(new commander_1.Option("--dir <dir>", "po file directory").conflicts("po"))
17
+ .addOption(new Option("-k, --key <key>", "openai api key").env("OPENAI_API_KEY"))
18
+ .addOption(new Option("--host <host>", "openai api host").env("OPENAI_API_HOST"))
19
+ .addOption(new Option("--model <model>", "openai model").env("OPENAI_MODEL").default("gpt-4o-mini"))
20
+ .addOption(new Option("--po <file>", "po file path").conflicts("dir"))
21
+ .addOption(new Option("--dir <dir>", "po file directory").conflicts("po"))
40
22
  .option("-src, --source <lang>", "source language (ISO 639-1)", "en")
41
23
  .option("-l, --lang <lang>", "target language (ISO 639-1)")
42
24
  .option("--verbose", "print verbose log")
43
25
  .option("--context <file>", "text file that provides the bot additional context")
44
- .addOption(new commander_1.Option("-o, --output <file>", "output file path, overwirte po file by default").conflicts("dir"))
45
- .action((args) => __awaiter(void 0, void 0, void 0, function* () {
26
+ .addOption(new Option("-o, --output <file>", "output file path, overwirte po file by default").conflicts("dir"))
27
+ .action(async (args) => {
46
28
  const { key, host, model, po, dir, source, lang, verbose, output, context } = args;
47
29
  if (host) {
48
30
  process.env.OPENAI_API_HOST = host;
@@ -55,60 +37,45 @@ program
55
37
  console.error("OPENAI_API_KEY is required");
56
38
  process.exit(1);
57
39
  }
58
- (0, translate_1.init)();
40
+ init();
59
41
  if (po) {
60
- yield (0, translate_1.translatePo)(model, po, source, lang, verbose, output, context);
42
+ await translatePo(model, po, source, lang, verbose, output, context);
61
43
  }
62
44
  else if (dir) {
63
- yield (0, translate_1.translatePoDir)(model, dir, source, lang, verbose, context);
45
+ await translatePoDir(model, dir, source, lang, verbose, context);
64
46
  }
65
47
  else {
66
48
  console.error("po file or directory is required");
67
49
  process.exit(1);
68
50
  }
69
- }));
51
+ });
70
52
  program
71
53
  .command("sync")
72
54
  .description("update po from pot file")
73
55
  .requiredOption("--po <file>", "po file path")
74
56
  .requiredOption("--pot <file>", "pot file path")
75
- .action(({ po, pot }) => __awaiter(void 0, void 0, void 0, function* () {
76
- yield (0, sync_1.sync)(po, pot);
77
- }));
78
- // program command `systemprompt` with help text `open/edit system prompt`
79
- program
80
- .command("systemprompt")
81
- .description("open/edit system prompt")
82
- .option("--reset", "reset system prompt to default")
83
- .action((args) => {
84
- const { reset } = args;
85
- // open `systemprompt.txt` file by system text default editor
86
- const copyFile = __dirname + "/systemprompt.txt";
87
- // user home path
88
- const promptFile = (0, utils_1.findConfig)("systemprompt.txt");
89
- (0, utils_1.copyFileIfNotExists)(promptFile, copyFile, reset);
90
- if (reset) {
91
- console.log("systemprompt.txt reset to default");
92
- }
93
- (0, utils_1.openFileByDefault)(promptFile);
57
+ .action(async ({ po, pot }) => {
58
+ await sync(po, pot);
94
59
  });
95
60
  // program command `userdict` with help text `open/edit user dictionary`
96
61
  program
97
62
  .command("userdict")
98
63
  .description("open/edit user dictionary")
99
64
  .option("--explore", "open user dictionary directory")
65
+ .option("-l, --lang <lang>", "target language (ISO 639-1)")
100
66
  .action((args) => {
101
- const { explore } = args;
67
+ const { explore, lang } = args;
102
68
  // open `dictionary.json` file by system text default editor
103
69
  const copyFile = __dirname + "/dictionary.json";
104
- // user home path
105
- const dictFile = (0, utils_1.findConfig)("dictionary.json");
70
+ // find from user home path
71
+ const dictFile = findConfig(`dictionary${lang ? "-" + lang : ""}.json`);
106
72
  if (explore) {
107
73
  // open user dictionary directory
108
- return (0, utils_1.openFileExplorer)(dictFile);
74
+ return openFileExplorer(dictFile);
109
75
  }
110
- (0, utils_1.copyFileIfNotExists)(dictFile, copyFile);
111
- (0, utils_1.openFileByDefault)(dictFile);
76
+ if (!lang)
77
+ copyFileIfNotExists(dictFile, copyFile);
78
+ openFileByDefault(dictFile);
112
79
  });
113
80
  // program command `remove` with help text `remove po entries by options`
114
81
  program
@@ -122,7 +89,7 @@ program
122
89
  .option("-tnf, --translated-not-fuzzy", "remove translated not fuzzy entries")
123
90
  .option("-ft, --fuzzy-translated", "remove fuzzy translated entries")
124
91
  .option("-rc, --reference-contains <text>", "remove entries whose reference contains text, text can be a regular expression like /text/ig")
125
- .action((args) => __awaiter(void 0, void 0, void 0, function* () {
92
+ .action(async (args) => {
126
93
  const { po, fuzzy, obsolete, untranslated, translated, translatedNotFuzzy, fuzzyTranslated, referenceContains } = args;
127
94
  const options = {
128
95
  fuzzy,
@@ -131,12 +98,12 @@ program
131
98
  translated,
132
99
  translatedNotFuzzy,
133
100
  fuzzyTranslated,
134
- referenceContains,
101
+ referenceContains
135
102
  };
136
103
  const output = args.output || po;
137
- const translations = yield (0, utils_1.parsePo)(po);
138
- yield (0, utils_1.compilePo)((0, manipulate_1.removeByOptions)(translations, options), output);
104
+ const translations = await parsePo(po);
105
+ await compilePo(removeByOptions(translations, options), output);
139
106
  console.log("done");
140
- }));
107
+ });
141
108
  program.parse(process.argv);
142
109
  //# sourceMappingURL=index.js.map
@@ -1,52 +1,48 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.removeByOptions = void 0;
4
1
  /**
5
2
  * remove entity by options
6
3
  */
7
- function removeByOptions(potrans, options) {
8
- var _a, _b, _c, _d, _e, _f, _g, _h;
4
+ export function removeByOptions(potrans, options) {
9
5
  const fuzzyRegx = /\bfuzzy\b/;
10
6
  const obsoleteRegx = /\bobsolete\b/;
11
- const refRegMatch = (options === null || options === void 0 ? void 0 : options.referenceContains)
12
- ? /^\/([^\/]+)\/([igmsuy]*)/.exec(options === null || options === void 0 ? void 0 : options.referenceContains)
7
+ const refRegMatch = options?.referenceContains
8
+ ? /^\/([^\/]+)\/([igmsuy]*)/.exec(options?.referenceContains)
13
9
  : null;
14
10
  const refRegx = refRegMatch ? new RegExp(refRegMatch[1], refRegMatch[2]) : null;
15
11
  for (const [ctx, entries] of Object.entries(potrans.translations)) {
16
12
  for (const [msgid, entry] of Object.entries(entries)) {
17
13
  const msgstr = entry.msgstr.join("\n");
18
14
  // remove fuzzy
19
- if ((options === null || options === void 0 ? void 0 : options.fuzzy) && fuzzyRegx.test(((_a = entry.comments) === null || _a === void 0 ? void 0 : _a.flag) || "")) {
15
+ if (options?.fuzzy && fuzzyRegx.test(entry.comments?.flag || "")) {
20
16
  delete potrans.translations[ctx][msgid];
21
17
  }
22
18
  // remove obsolete
23
- if ((options === null || options === void 0 ? void 0 : options.obsolete) && obsoleteRegx.test(((_b = entry.comments) === null || _b === void 0 ? void 0 : _b.flag) || "")) {
19
+ if (options?.obsolete && obsoleteRegx.test(entry.comments?.flag || "")) {
24
20
  delete potrans.translations[ctx][msgid];
25
21
  }
26
22
  // remove untranslated
27
- if ((options === null || options === void 0 ? void 0 : options.untranslated) && msgstr.length === 0) {
23
+ if (options?.untranslated && msgstr.length === 0) {
28
24
  delete potrans.translations[ctx][msgid];
29
25
  }
30
26
  // remove translated
31
- if ((options === null || options === void 0 ? void 0 : options.translated) && msgstr.length > 0) {
27
+ if (options?.translated && msgstr.length > 0) {
32
28
  delete potrans.translations[ctx][msgid];
33
29
  }
34
30
  // remove translated not fuzzy
35
- if ((options === null || options === void 0 ? void 0 : options.translatedNotFuzzy) && msgstr.length > 0 && !fuzzyRegx.test(((_c = entry.comments) === null || _c === void 0 ? void 0 : _c.flag) || "")) {
31
+ if (options?.translatedNotFuzzy && msgstr.length > 0 && !fuzzyRegx.test(entry.comments?.flag || "")) {
36
32
  delete potrans.translations[ctx][msgid];
37
33
  }
38
34
  // remove fuzzy translated
39
- if ((options === null || options === void 0 ? void 0 : options.fuzzyTranslated) && msgstr.length > 0 && fuzzyRegx.test(((_d = entry.comments) === null || _d === void 0 ? void 0 : _d.flag) || "")) {
35
+ if (options?.fuzzyTranslated && msgstr.length > 0 && fuzzyRegx.test(entry.comments?.flag || "")) {
40
36
  delete potrans.translations[ctx][msgid];
41
37
  }
42
38
  // remove reference contains
43
- if (options === null || options === void 0 ? void 0 : options.referenceContains) {
39
+ if (options?.referenceContains) {
44
40
  if (refRegx) {
45
- if (((_e = entry.comments) === null || _e === void 0 ? void 0 : _e.reference) && refRegx.test((_f = entry.comments) === null || _f === void 0 ? void 0 : _f.reference)) {
41
+ if (entry.comments?.reference && refRegx.test(entry.comments?.reference)) {
46
42
  delete potrans.translations[ctx][msgid];
47
43
  }
48
44
  }
49
- else if ((_h = (_g = entry.comments) === null || _g === void 0 ? void 0 : _g.reference) === null || _h === void 0 ? void 0 : _h.includes(options === null || options === void 0 ? void 0 : options.referenceContains)) {
45
+ else if (entry.comments?.reference?.includes(options?.referenceContains)) {
50
46
  delete potrans.translations[ctx][msgid];
51
47
  }
52
48
  }
@@ -54,5 +50,4 @@ function removeByOptions(potrans, options) {
54
50
  }
55
51
  return potrans;
56
52
  }
57
- exports.removeByOptions = removeByOptions;
58
53
  //# sourceMappingURL=manipulate.js.map
package/lib/src/sync.js CHANGED
@@ -1,33 +1,18 @@
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
- }
1
+ import { compilePo, parsePo } from "./utils.js";
2
+ export async function sync(po, pot) {
3
+ const potrans = await parsePo(po);
4
+ const potrans2 = await parsePo(pot);
5
+ for (const [ctx, entries] of Object.entries(potrans2.translations)) {
6
+ // copy msgstr from potrans to potrans2
7
+ for (const [msgid, _] of Object.entries(entries)) {
8
+ if (potrans.translations[ctx] &&
9
+ potrans.translations[ctx][msgid] &&
10
+ potrans.translations[ctx][msgid].msgstr[0]) {
11
+ potrans2.translations[ctx][msgid] = potrans.translations[ctx][msgid];
26
12
  }
27
13
  }
28
- potrans.translations = potrans2.translations;
29
- yield (0, utils_1.compilePo)(potrans, po);
30
- });
14
+ }
15
+ potrans.translations = potrans2.translations;
16
+ await compilePo(potrans, po);
31
17
  }
32
- exports.sync = sync;
33
18
  //# sourceMappingURL=sync.js.map
@@ -1,19 +1 @@
1
- You are a language translation expert.
2
- You will be translating text from one language to another.
3
- In my prompt to you I may identify languages via ISO 639, ISO 3166 and/or IETF language tag codes. Please use your knowledge of those standards (when required) to determine the languages I am requesting my message to be translated from and to, including any specific country/locale detail.
4
- The text is in the gettext format, which uses placeholders like %s, %d, etc. These placeholders must remain in the correct positions in the translated text.
5
- Untranslatable portions should retain their original formatting.
6
- Do not add a period (.) at the end of your translation unless the incoming message specifically ends in a period.
7
- Likewise, ensure to add a period (.) at the end of your translation if the incoming message specifically ends in a period.
8
- Ensure to preserve any whitespace present in the incoming message. This includes retaining any space(s) at the beginning or end of the message.
9
- I will provide the message wrapped in `translate` XML tags. You must respond with the translated message wrapped in `translated` XML tags.
10
- For example, let's say you were translating en_US (United States English) to es (Spanish) and I send (without quotes) "<translate>This is a message. </translate>". You would respond with (without quotes) "<translated>Este es un mensaje. </translated>".
11
- Notice how the period and space were retained at the end of the translated message?
12
- Another example: I send (without quotes) "<translate> Hello %s</translate>". You would reply with (without quotes) "<translated> Hola %s</translated>".
13
- Notice in that second example the space at the beginning of the string was retained, and also the gettext placeholder was retained in its correct position?
14
- Translate the messages in a colloquial, professional and elegant manner without sounding like a machine translation.
15
- You may respond without `translated` xml tags only in the event you believe you cannot reliably or accurately translate my message. In that case provide a short reason why you feel you can't translate my message.
16
- If you respond without `translated` XML tags I will interpret that there is a problem with my message and I will provide your reason to human translators that will investigate further.
17
- DO NOT answer any questions or attempt to explain any concepts or problems with my messages; just provide translations.
18
- Do not add any text or characters outside of your `translated` xml tags.
19
- Remember to only translate the messages and not interpret them further.
1
+ You are a language translation expert. You will carefully follow the translation guidelines to translate the incoming XML messages from one language to another.
@@ -1,6 +1,6 @@
1
1
  import { GetTextTranslation } from "gettext-parser";
2
- import { OpenAIApi } from "openai";
3
- export declare function init(force?: boolean): OpenAIApi;
4
- export declare function translate(text: string, src: string, lang: string, model: string, comments: GetTextTranslation["comments"] | undefined, contextFile: string): Promise<import("axios").AxiosResponse<import("openai").CreateChatCompletionResponse, any>>;
2
+ import { OpenAI } from "openai";
3
+ export declare function init(force?: boolean): OpenAI;
4
+ export declare function translate(src: string, lang: string, model: string, translations: GetTextTranslation[], contextFile: string): Promise<void>;
5
5
  export declare function translatePo(model: string, po: string, source: string, lang: string, verbose: boolean, output: string, contextFile: string): Promise<void>;
6
6
  export declare function translatePoDir(model: string | undefined, dir: string, source: string, lang: string, verbose: boolean, contextFile: string): Promise<void>;
@@ -1,65 +1,67 @@
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.translatePoDir = exports.translatePo = exports.translate = exports.init = void 0;
13
- const fs = require("fs");
14
- const openai_1 = require("openai");
15
- const path_1 = require("path");
16
- const pkg = require("../package.json");
17
- const utils_1 = require("./utils");
1
+ import * as fs from "fs";
2
+ import { OpenAI } from "openai";
3
+ import path from "path";
4
+ import { fileURLToPath } from "url";
5
+ import pkg from "../package.json" with { type: "json" };
6
+ import { compilePo, copyFileIfNotExists, findConfig, parsePo, printProgress } from "./utils.js";
7
+ const __filename = fileURLToPath(import.meta.url);
8
+ const __dirname = path.dirname(__filename);
18
9
  let _openai;
19
10
  let _systemprompt;
11
+ let _userprompt;
20
12
  let _userdict;
21
- function init(force) {
13
+ export function init(force) {
22
14
  if (!_openai || force) {
23
- const configuration = new openai_1.Configuration({
24
- apiKey: process.env.OPENAI_API_KEY,
25
- });
15
+ let configuration = {
16
+ apiKey: process.env.OPENAI_API_KEY
17
+ };
18
+ _openai = new OpenAI(configuration);
26
19
  if (process.env.OPENAI_API_HOST) {
27
- configuration.basePath = process.env.OPENAI_API_HOST.replace(/\/+$/, "") + "/v1";
20
+ _openai.baseURL = process.env.OPENAI_API_HOST.replace(/\/+$/, "") + "/v1";
28
21
  }
29
- _openai = new openai_1.OpenAIApi(configuration);
30
22
  }
31
- // load systemprompt.txt from homedir
23
+ // load systemprompt.txt from project
32
24
  if (!_systemprompt || force) {
33
- const systemprompt = (0, utils_1.findConfig)("systemprompt.txt");
34
- (0, utils_1.copyFileIfNotExists)(systemprompt, (0, path_1.join)(__dirname, "systemprompt.txt"));
35
- _systemprompt = fs.readFileSync(systemprompt, "utf-8");
25
+ _systemprompt = fs.readFileSync(path.join(__dirname, "systemprompt.txt"), "utf-8");
26
+ }
27
+ // load userprompt.txt from project
28
+ if (!_userprompt || force) {
29
+ _userprompt = fs.readFileSync(path.join(__dirname, "userprompt.txt"), "utf-8");
36
30
  }
37
31
  // load dictionary.json from homedir
38
32
  if (!_userdict || force) {
39
- const userdict = (0, utils_1.findConfig)("dictionary.json");
40
- (0, utils_1.copyFileIfNotExists)(userdict, (0, path_1.join)(__dirname, "dictionary-template.json"));
41
- _userdict = { "default": JSON.parse(fs.readFileSync(userdict, "utf-8")) };
33
+ const userdict = findConfig("dictionary.json");
34
+ copyFileIfNotExists(userdict, path.join(__dirname, "dictionary.json"));
35
+ _userdict = { default: JSON.parse(fs.readFileSync(userdict, "utf-8")) };
42
36
  }
43
37
  return _openai;
44
38
  }
45
- exports.init = init;
46
- function translate(text, src, lang, model, comments, contextFile) {
47
- const lang_code = lang.toLowerCase().trim().replace(/[\W_]+/g, "-");
48
- const dicts = Object.entries(_userdict[lang_code] || _userdict["default"])
49
- .filter(([k, _]) => text.toLowerCase().includes(k.toLowerCase()))
50
- .map(([k, v]) => [
51
- { role: "user", content: k },
52
- { role: "assistant", content: v },
53
- ])
54
- .flat();
55
- var notes = "";
56
- if (comments != undefined && comments.extracted != undefined)
57
- notes = comments.extracted;
58
- var context = "";
59
- if (contextFile !== undefined)
60
- context = "\n\n" + fs.readFileSync(contextFile, "utf-8");
61
- return _openai.createChatCompletion({
62
- model,
39
+ export async function translate(src, lang, model, translations, contextFile) {
40
+ const lang_code = lang
41
+ .toLowerCase()
42
+ .trim()
43
+ .replace(/[\W_]+/g, "-");
44
+ const dicts = Object.entries(_userdict[lang_code] || _userdict["default"]).reduce((acc, [k, v], idx) => {
45
+ if (translations.some((tr) => tr.msgid.toLowerCase().includes(k.toLowerCase()))) {
46
+ acc.user.push(`<translate index="${idx + 1}">${k}</translate>`);
47
+ acc.assistant.push(`<translated index="${idx + 1}">${v}</translated>`);
48
+ }
49
+ return acc;
50
+ }, { user: [], assistant: [] });
51
+ const notes = translations
52
+ .reduce((acc, tr) => {
53
+ if (tr.comments?.extracted) {
54
+ acc.push(tr.comments?.extracted);
55
+ }
56
+ return acc;
57
+ }, [])
58
+ .join("\n");
59
+ const context = contextFile ? "\n\nContext: " + fs.readFileSync(contextFile, "utf-8") : "";
60
+ const translationsContent = translations
61
+ .map((tr, idx) => `<translate index="${idx + dicts.user.length + 1}">${tr.msgid}</translate>`)
62
+ .join("\n");
63
+ const res = await _openai.chat.completions.create({
64
+ model: model,
63
65
  temperature: 0.1,
64
66
  messages: [
65
67
  {
@@ -68,95 +70,117 @@ function translate(text, src, lang, model, comments, contextFile) {
68
70
  },
69
71
  {
70
72
  role: "user",
71
- content: `Wait for my incoming message in "${src}" and translate it into "${lang}", carefully following your system prompt. ` + notes
73
+ content: `${_userprompt}\n\nWait for my incoming message in "${src}" and translate it into "${lang}"(a language code and an optional region code). ` +
74
+ notes
72
75
  },
73
76
  {
74
77
  role: "assistant",
75
- content: `Understood, I will translate your incoming "${src}" message into "${lang}", carefully following my system prompt. Please go ahead and send your message for translation.`
78
+ content: `Understood, I will translate your incoming "${src}" message into "${lang}", carefully following guidelines. Please go ahead and send your message for translation.`
76
79
  },
77
- // add userdict here
78
- ...dicts,
80
+ // add userdict
81
+ ...(dicts.user.length > 0
82
+ ? [
83
+ { role: "user", content: dicts.user.join("\n") },
84
+ { role: "assistant", content: dicts.assistant.join("\n") }
85
+ ]
86
+ : []),
87
+ // add user translations
79
88
  {
80
89
  role: "user",
81
- content: "<translate>" + text + "</translate>"
82
- },
83
- ],
90
+ content: translationsContent
91
+ }
92
+ ]
84
93
  }, {
85
94
  timeout: 20000,
95
+ stream: false
96
+ });
97
+ const content = res.choices[0].message.content ?? "";
98
+ translations.forEach((trans, idx) => {
99
+ const tag = `<translated index="${idx + dicts.user.length + 1}">`;
100
+ const s = content.indexOf(tag);
101
+ if (s > -1) {
102
+ const e = content.indexOf("</translated>", s);
103
+ trans.msgstr[0] = content.slice(s + tag.length, e);
104
+ }
105
+ else {
106
+ console.error("Error: Unable to find translation for string [" + trans.msgid + "]");
107
+ }
86
108
  });
87
109
  }
88
- exports.translate = translate;
89
- function translatePo(model, po, source, lang, verbose, output, contextFile) {
90
- var _a;
91
- return __awaiter(this, void 0, void 0, function* () {
92
- const potrans = yield (0, utils_1.parsePo)(po);
93
- if (!lang)
94
- lang = potrans.headers["Language"];
95
- if (!lang) {
96
- console.error("No language specified via po file or args");
97
- return;
110
+ export async function translatePo(model, po, source, lang, verbose, output, contextFile) {
111
+ const potrans = await parsePo(po);
112
+ if (!lang)
113
+ lang = potrans.headers["Language"];
114
+ if (!lang) {
115
+ console.error("No language specified via po file or args");
116
+ return;
117
+ }
118
+ // try to load dictionary by lang-code if it not loaded
119
+ const lang_code = lang
120
+ .toLowerCase()
121
+ .trim()
122
+ .replace(/[\W_]+/g, "-");
123
+ if (!_userdict[lang_code]) {
124
+ const lang_dic_file = findConfig(`dictionary-${lang_code}.json`);
125
+ if (fs.existsSync(lang_dic_file)) {
126
+ _userdict[lang_code] = JSON.parse(fs.readFileSync(lang_dic_file, "utf-8"));
127
+ console.log(`dictionary-${lang_code}.json is loaded.`);
98
128
  }
99
- // try to load dictionary by lang-code if it not loaded
100
- const lang_code = lang.toLowerCase().trim().replace(/[\W_]+/g, "-");
101
- if (!_userdict[lang_code]) {
102
- const lang_dic_file = (0, utils_1.findConfig)(`dictionary-${lang_code}.json`);
103
- if (fs.existsSync(lang_dic_file)) {
104
- _userdict[lang_code] = JSON.parse(fs.readFileSync(lang_dic_file, "utf-8"));
105
- console.log(`dictionary-${lang_code}.json is loaded.`);
129
+ }
130
+ const list = [];
131
+ const trimRegx = /(?:^ )|(?: $)/;
132
+ let trimed = false;
133
+ for (const [ctx, entries] of Object.entries(potrans.translations)) {
134
+ for (const [msgid, trans] of Object.entries(entries)) {
135
+ if (msgid == "")
136
+ continue;
137
+ if (!trans.msgstr[0]) {
138
+ list.push(trans);
139
+ continue;
106
140
  }
107
- }
108
- const list = [];
109
- const trimRegx = /(?:^ )|(?: $)/;
110
- let trimed = false;
111
- for (const [ctx, entries] of Object.entries(potrans.translations)) {
112
- for (const [msgid, trans] of Object.entries(entries)) {
113
- if (msgid == "")
114
- continue;
115
- if (!trans.msgstr[0]) {
116
- list.push(trans);
117
- continue;
118
- }
119
- else if (trimRegx.test(trans.msgstr[0])) {
120
- trimed = true;
121
- trans.msgstr[0] = trans.msgstr[0].trim();
122
- }
141
+ else if (trimRegx.test(trans.msgstr[0])) {
142
+ trimed = true;
143
+ trans.msgstr[0] = trans.msgstr[0].trim();
123
144
  }
124
145
  }
125
- if (trimed) {
126
- yield (0, utils_1.compilePo)(potrans, po);
146
+ }
147
+ if (trimed) {
148
+ await compilePo(potrans, po);
149
+ }
150
+ if (list.length == 0) {
151
+ console.log("done.");
152
+ return;
153
+ }
154
+ potrans.headers["Last-Translator"] = `gpt-po v${pkg.version}`;
155
+ const translations = [];
156
+ let err429 = false;
157
+ for (let i = 0, c = 0; i < list.length; i++) {
158
+ if (i == 0)
159
+ printProgress(i, list.length);
160
+ if (err429) {
161
+ // sleep for 20 seconds.
162
+ await new Promise((resolve) => setTimeout(resolve, 20000));
127
163
  }
128
- if (list.length == 0) {
129
- console.log("done.");
130
- return;
164
+ const trans = list[i];
165
+ if (c < 2000) {
166
+ translations.push(trans);
167
+ c += trans.msgid.length;
131
168
  }
132
- potrans.headers["Last-Translator"] = `gpt-po v${pkg.version}`;
133
- let err429 = false;
134
- let modified = false;
135
- for (let i = 0; i < list.length; i++) {
136
- if (i == 0)
137
- (0, utils_1.printProgress)(i, list.length);
138
- if (err429) {
139
- // sleep for 20 seconds.
140
- yield new Promise((resolve) => setTimeout(resolve, 20000));
141
- }
142
- const trans = list[i];
169
+ if (c >= 2000 || i == list.length - 1) {
143
170
  try {
144
- const res = yield translate(trans.msgid, source, lang, model, trans.comments, contextFile);
145
- var translated = ((_a = res.data.choices[0].message) === null || _a === void 0 ? void 0 : _a.content) || trans.msgstr[0];
146
- if (!translated.startsWith('<translated>') && !translated.endsWith('</translated>')) {
147
- // We got an error response
148
- console.log("Error: Unable to translate string [" + trans.msgid + "]. Bot says [" + translated + "]");
149
- continue;
150
- }
151
- // We got a valid translation response
152
- trans.msgstr[0] = translated.replace('<translated>', '').replace('</translated>', '');
153
- modified = true;
171
+ await translate(source, lang, model, translations, contextFile);
154
172
  if (verbose) {
155
- console.log(trans.msgid);
156
- console.log(trans.msgstr[0]);
173
+ translations.forEach((trans) => {
174
+ console.log(trans.msgid);
175
+ console.log(trans.msgstr[0]);
176
+ });
157
177
  }
158
- (0, utils_1.printProgress)(i + 1, list.length);
159
- yield (0, utils_1.compilePo)(potrans, output || po);
178
+ translations.length = 0;
179
+ c = 0;
180
+ // update progress
181
+ printProgress(i + 1, list.length);
182
+ // save po file after each 2000 characters
183
+ await compilePo(potrans, output || po);
160
184
  }
161
185
  catch (error) {
162
186
  if (error.response) {
@@ -178,21 +202,17 @@ function translatePo(model, po, source, lang, verbose, output, contextFile) {
178
202
  }
179
203
  }
180
204
  }
181
- console.log("done.");
182
- });
205
+ }
206
+ console.log("done.");
183
207
  }
184
- exports.translatePo = translatePo;
185
- function translatePoDir(model = "gpt-3.5-turbo", dir, source, lang, verbose, contextFile) {
186
- return __awaiter(this, void 0, void 0, function* () {
187
- const files = fs.readdirSync(dir);
188
- for (const file of files) {
189
- if (file.endsWith(".po")) {
190
- const po = (0, path_1.join)(dir, file);
191
- console.log(`translating ${po}`);
192
- yield translatePo(model, po, source, lang, verbose, po, contextFile);
193
- }
208
+ export async function translatePoDir(model = "gpt-3.5-turbo", dir, source, lang, verbose, contextFile) {
209
+ const files = fs.readdirSync(dir);
210
+ for (const file of files) {
211
+ if (file.endsWith(".po")) {
212
+ const po = path.join(dir, file);
213
+ console.log(`translating ${po}`);
214
+ await translatePo(model, po, source, lang, verbose, po, contextFile);
194
215
  }
195
- });
216
+ }
196
217
  }
197
- exports.translatePoDir = translatePoDir;
198
218
  //# sourceMappingURL=translate.js.map
@@ -0,0 +1,27 @@
1
+ Translation guidelines are as follows:
2
+
3
+ 1. **Placeholder Handling**:
4
+ - Maintain the positions of placeholders (e.g., %s, %d, {example}) in the translated text. Do not translate placeholders.
5
+
6
+ 2. **Formatting**:
7
+ - Preserve the formatting of untranslatable portions.
8
+ - Retain any whitespace at the beginning or end of the message.
9
+ - Add or omit a period (.) at the end of your translation to match the incoming message.
10
+
11
+ 3. **XML Tags and Indexing**:
12
+ - Input messages will be wrapped in `<translate>` XML tags with an index attribute, e.g., `<translate index="1">`.
13
+ - Respond with the translated message wrapped in `<translated>` XML tags, including the same index attribute, e.g., `<translated index="1">`.
14
+
15
+ 4. **Multiple Translations**:
16
+ - You may receive multiple translation requests in a single input, each with a unique index.
17
+ - Ensuring the complete number of requests are translated, even if they are repeated, while maintaining the original order when possible.
18
+
19
+ **Examples**:
20
+ - Input:
21
+ `<translate index="1">This is a message. </translate>`
22
+ `<translate index="2"> Hello %s</translate>`
23
+ - Output:
24
+ `<translated index="1">这是一条信息</translated>`
25
+ `<translated index="2"> 你好 %s</translated>`
26
+
27
+ Do not answer questions or explain concepts. Only provide translations within `<translated>` XML tags unless you need to respond with a short error reason.
@@ -8,7 +8,12 @@ import { GetTextTranslations } from "gettext-parser";
8
8
  export declare function copyFileIfNotExists(file: string, copyFile: string, force?: boolean): void;
9
9
  export declare function openFileByDefault(filePath: string): void;
10
10
  export declare function parsePo(poFile: string, defaultCharset?: string): Promise<GetTextTranslations>;
11
- export declare function compilePo(data: GetTextTranslations, poFile: string): Promise<void>;
11
+ export type compileOptions = {
12
+ foldLength?: number;
13
+ sort?: boolean | ((a: never, b: never) => number);
14
+ escapeCharacters?: boolean;
15
+ };
16
+ export declare function compilePo(data: GetTextTranslations, poFile: string, options?: compileOptions): Promise<void>;
12
17
  export declare function printProgress(progress: number, total: number, extra?: string): void;
13
18
  export declare function gitRootDir(dir?: string): string | null;
14
19
  /**
package/lib/src/utils.js CHANGED
@@ -1,18 +1,15 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.openFileExplorer = exports.findConfig = exports.gitRootDir = exports.printProgress = exports.compilePo = exports.parsePo = exports.openFileByDefault = exports.copyFileIfNotExists = void 0;
4
- const child_process_1 = require("child_process");
5
- const fs = require("fs");
6
- const gettext_parser_1 = require("gettext-parser");
7
- const os_1 = require("os");
8
- const path = require("path");
1
+ import { exec, spawn } from "child_process";
2
+ import * as fs from "fs";
3
+ import { po } from "gettext-parser";
4
+ import { homedir, platform } from "os";
5
+ import * as path from "path";
9
6
  /**
10
7
  * copy source file to destination file if destination file does not exist
11
8
  * @param file destination file path
12
9
  * @param copyFile source file path
13
10
  * @param force force copy file
14
11
  */
15
- function copyFileIfNotExists(file, copyFile, force = false) {
12
+ export function copyFileIfNotExists(file, copyFile, force = false) {
16
13
  // make sure the directory exists
17
14
  fs.mkdirSync(path.dirname(file), { recursive: true });
18
15
  // check if file exists else create it
@@ -27,28 +24,25 @@ function copyFileIfNotExists(file, copyFile, force = false) {
27
24
  fs.copyFileSync(copyFile, file);
28
25
  }
29
26
  }
30
- exports.copyFileIfNotExists = copyFileIfNotExists;
31
- function openFileByDefault(filePath) {
27
+ export function openFileByDefault(filePath) {
32
28
  // Use the 'open' command on macOS or 'start' command on Windows to open the file with the default system editor
33
29
  const command = process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open";
34
30
  // Spawn a new process for the default editor and pass the file name as an argument
35
- (0, child_process_1.spawn)(command, [filePath], { shell: true });
31
+ spawn(command, [filePath], { shell: true });
36
32
  }
37
- exports.openFileByDefault = openFileByDefault;
38
- function parsePo(poFile, defaultCharset) {
33
+ export function parsePo(poFile, defaultCharset) {
39
34
  // read poFile as buffer, then parse it
40
35
  return new Promise((resolve, reject) => {
41
36
  fs.readFile(poFile, (err, buffer) => {
42
37
  if (err)
43
38
  reject(err);
44
- var result = gettext_parser_1.po.parse(buffer, defaultCharset !== null && defaultCharset !== void 0 ? defaultCharset : "utf-8");
39
+ const result = po.parse(buffer, defaultCharset ?? "utf-8");
45
40
  resolve(result);
46
41
  });
47
42
  });
48
43
  }
49
- exports.parsePo = parsePo;
50
- function compilePo(data, poFile) {
51
- const buffer = gettext_parser_1.po.compile(data, { foldLength: 120 });
44
+ export function compilePo(data, poFile, options = { foldLength: 120, sort: false, escapeCharacters: true }) {
45
+ const buffer = po.compile(data, options);
52
46
  return new Promise((resolve, reject) => {
53
47
  fs.writeFile(poFile, buffer, (err) => {
54
48
  if (err)
@@ -57,8 +51,7 @@ function compilePo(data, poFile) {
57
51
  });
58
52
  });
59
53
  }
60
- exports.compilePo = compilePo;
61
- function printProgress(progress, total, extra) {
54
+ export function printProgress(progress, total, extra) {
62
55
  const percent = Math.floor((progress / total) * 100);
63
56
  const bar = Array(Math.floor(percent / 5))
64
57
  .fill("█")
@@ -68,8 +61,7 @@ function printProgress(progress, total, extra) {
68
61
  .join("");
69
62
  process.stdout.write(`\r${bar}${dots} ${percent}% ${progress}/${total} ${extra || ""}`);
70
63
  }
71
- exports.printProgress = printProgress;
72
- function gitRootDir(dir) {
64
+ export function gitRootDir(dir) {
73
65
  // if dir is not provided, use current working directory
74
66
  dir = dir || process.cwd();
75
67
  // check if dir is a git repository
@@ -87,7 +79,6 @@ function gitRootDir(dir) {
87
79
  }
88
80
  }
89
81
  }
90
- exports.gitRootDir = gitRootDir;
91
82
  /**
92
83
  * find config file in the following order:
93
84
  * 1. current working directory of the Node.js process
@@ -96,15 +87,15 @@ exports.gitRootDir = gitRootDir;
96
87
  * @param fileName
97
88
  * @returns full path of the config file
98
89
  */
99
- function findConfig(fileName) {
90
+ export function findConfig(fileName) {
100
91
  const currentDir = process.cwd();
101
92
  const gitDir = gitRootDir() || currentDir;
102
- const homeDir = (0, os_1.homedir)();
93
+ const homeDir = homedir();
103
94
  const filePaths = [
104
95
  path.join(currentDir, ".gpt-po", fileName),
105
96
  path.join(currentDir, fileName),
106
97
  path.join(gitDir, ".gpt-po", fileName),
107
- path.join(homeDir, ".gpt-po", fileName)
98
+ path.join(homeDir, ".gpt-po", fileName),
108
99
  ];
109
100
  // check if file exists and return the first one
110
101
  for (const filePath of filePaths) {
@@ -115,22 +106,20 @@ function findConfig(fileName) {
115
106
  // if no file exists, return the default one
116
107
  return path.join(homeDir, ".gpt-po", fileName);
117
108
  }
118
- exports.findConfig = findConfig;
119
109
  /**
120
110
  * open file explorer by platform
121
111
  * @param location folder or file path
122
112
  */
123
- function openFileExplorer(location) {
124
- if ((0, os_1.platform)() === 'win32') {
125
- (0, child_process_1.exec)(`explorer.exe "${path.dirname(location)}"`);
113
+ export function openFileExplorer(location) {
114
+ if (platform() === "win32") {
115
+ exec(`explorer.exe "${path.dirname(location)}"`);
126
116
  }
127
- else if ((0, os_1.platform)() === 'darwin') {
128
- (0, child_process_1.exec)(`open "${path.dirname(location)}"`);
117
+ else if (platform() === "darwin") {
118
+ exec(`open "${path.dirname(location)}"`);
129
119
  }
130
120
  else {
131
121
  // Assuming a Linux-based system
132
- (0, child_process_1.exec)(`xdg-open "${path.dirname(location)}"`);
122
+ exec(`xdg-open "${path.dirname(location)}"`);
133
123
  }
134
124
  }
135
- exports.openFileExplorer = openFileExplorer;
136
125
  //# sourceMappingURL=utils.js.map
package/package.json CHANGED
@@ -1,8 +1,9 @@
1
1
  {
2
2
  "name": "gpt-po",
3
- "version": "1.1.1",
3
+ "version": "1.2.0",
4
4
  "description": "command tool for translate po files by gpt",
5
5
  "main": "lib/src/index.js",
6
+ "type": "module",
6
7
  "bin": {
7
8
  "gpt-po": "lib/src/index.js"
8
9
  },
@@ -33,23 +34,23 @@
33
34
  "openai"
34
35
  ],
35
36
  "devDependencies": {
36
- "@types/gettext-parser": "^4.0.2",
37
- "@types/jest": "^29.5.1",
38
- "jest": "^29.5.0",
37
+ "@types/gettext-parser": "^4.0.4",
38
+ "@types/jest": "^29.5.12",
39
+ "jest": "^29.7.0",
39
40
  "ncp": "^2.0.0",
40
- "prettier": "^3.0.3",
41
- "rimraf": "^5.0.0",
42
- "ts-jest": "^29.1.0",
41
+ "prettier": "^3.3.3",
42
+ "rimraf": "^6.0.1",
43
+ "ts-jest": "^29.2.5",
43
44
  "tslint": "^6.1.3",
44
45
  "tslint-config-prettier": "^1.18.0",
45
- "typescript": "^5.0.4"
46
+ "typescript": "^5.5.4"
46
47
  },
47
48
  "dependencies": {
48
- "commander": "^10.0.1",
49
- "gettext-parser": "^6.0.0",
50
- "openai": "^3.2.1"
49
+ "commander": "^12.1.0",
50
+ "gettext-parser": "^8.0.0",
51
+ "openai": "^4.56.0"
51
52
  },
52
53
  "engines": {
53
- "node": ">=12.0.0"
54
+ "node": ">=18.0.0"
54
55
  }
55
56
  }