gpt-po 1.1.2 → 1.2.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.
@@ -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
@@ -81,3 +80,14 @@ Options:
81
80
  -rc, --reference-contains <text> remove entries whose reference contains text, text can be a regular expression like /text/ig
82
81
  -h, --help display help for command
83
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] 显示命令帮助
@@ -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,6 +1,6 @@
1
1
  {
2
2
  "name": "gpt-po",
3
- "version": "1.1.2",
3
+ "version": "1.2.0",
4
4
  "description": "command tool for translate po files by gpt",
5
5
  "main": "lib/src/index.js",
6
6
  "type": "module",
@@ -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,4 +1,4 @@
1
- #!/usr/bin/env node
1
+ #!/usr/bin/env node --no-warnings=ExperimentalWarning
2
2
  import { Command, Option } from "commander";
3
3
  import path from "path";
4
4
  import { fileURLToPath } from "url";
@@ -16,7 +16,7 @@ program
16
16
  .description("translate po file (default command)")
17
17
  .addOption(new Option("-k, --key <key>", "openai api key").env("OPENAI_API_KEY"))
18
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"))
19
+ .addOption(new Option("--model <model>", "openai model").env("OPENAI_MODEL").default("gpt-4o-mini"))
20
20
  .addOption(new Option("--po <file>", "po file path").conflicts("dir"))
21
21
  .addOption(new Option("--dir <dir>", "po file directory").conflicts("po"))
22
22
  .option("-src, --source <lang>", "source language (ISO 639-1)", "en")
@@ -57,39 +57,24 @@ program
57
57
  .action(async ({ po, pot }) => {
58
58
  await sync(po, pot);
59
59
  });
60
- // program command `systemprompt` with help text `open/edit system prompt`
61
- program
62
- .command("systemprompt")
63
- .description("open/edit system prompt")
64
- .option("--reset", "reset system prompt to default")
65
- .action((args) => {
66
- const { reset } = args;
67
- // open `systemprompt.txt` file by system text default editor
68
- const copyFile = __dirname + "/systemprompt.txt";
69
- // user home path
70
- const promptFile = findConfig("systemprompt.txt");
71
- copyFileIfNotExists(promptFile, copyFile, reset);
72
- if (reset) {
73
- console.log("systemprompt.txt reset to default");
74
- }
75
- openFileByDefault(promptFile);
76
- });
77
60
  // program command `userdict` with help text `open/edit user dictionary`
78
61
  program
79
62
  .command("userdict")
80
63
  .description("open/edit user dictionary")
81
64
  .option("--explore", "open user dictionary directory")
65
+ .option("-l, --lang <lang>", "target language (ISO 639-1)")
82
66
  .action((args) => {
83
- const { explore } = args;
67
+ const { explore, lang } = args;
84
68
  // open `dictionary.json` file by system text default editor
85
69
  const copyFile = __dirname + "/dictionary.json";
86
- // user home path
87
- const dictFile = findConfig("dictionary.json");
70
+ // find from user home path
71
+ const dictFile = findConfig(`dictionary${lang ? "-" + lang : ""}.json`);
88
72
  if (explore) {
89
73
  // open user dictionary directory
90
74
  return openFileExplorer(dictFile);
91
75
  }
92
- copyFileIfNotExists(dictFile, copyFile);
76
+ if (!lang)
77
+ copyFileIfNotExists(dictFile, copyFile);
93
78
  openFileByDefault(dictFile);
94
79
  });
95
80
  // program command `remove` with help text `remove po entries by options`
@@ -113,7 +98,7 @@ program
113
98
  translated,
114
99
  translatedNotFuzzy,
115
100
  fuzzyTranslated,
116
- referenceContains,
101
+ referenceContains
117
102
  };
118
103
  const output = args.output || po;
119
104
  const translations = await parsePo(po);
@@ -1,31 +1 @@
1
- You are a language translation expert. You will translate text from one language to another, following these guidelines:
2
-
3
- 1. **Language Codes**:
4
- - If provided with an ISO 639 two-letter language code (e.g., `de`), use the language’s main dialect (e.g., `de` is equivalent to `de_DE`).
5
- - If provided with both an ISO 639 language code and an ISO 3166 country code (e.g., `es_MX`), translate into that specific regional dialect.
6
-
7
- 2. **Placeholder Handling**:
8
- - Maintain the positions of placeholders (e.g., %s, %d, {example}) in the translated text. Do not translate placeholders.
9
-
10
- 3. **Formatting**:
11
- - Preserve the formatting of untranslatable portions.
12
- - Retain any whitespace at the beginning or end of the message.
13
- - Add or omit a period (.) at the end of your translation to match the incoming message.
14
-
15
- 4. **XML Tags**:
16
- - Input messages will be wrapped in `<translate>` XML tags.
17
- - Respond with the translated message wrapped in `<translated>` XML tags.
18
-
19
- 5. **Quality**:
20
- - Translate in a colloquial, professional, and elegant manner without sounding like a machine translation.
21
-
22
- 6. **Error Handling**:
23
- - If you cannot reliably translate a message, respond without `<translated>` XML tags and provide a short reason why.
24
-
25
- **Examples**:
26
- - Input: `<translate>This is a message. </translate>`
27
- - Output: `<translated>Este es un mensaje. </translated>`
28
- - Input: `<translate> Hello %s</translate>`
29
- - Output: `<translated> Hola %s</translated>`
30
-
31
- Do not answer questions or explain concepts. Only provide translations within `<translated>` XML tags unless you need to respond with a short error reason.
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
2
  import { OpenAI } from "openai";
3
3
  export declare function init(force?: boolean): OpenAI;
4
- export declare function translate(text: string, src: string, lang: string, model: string, comments: GetTextTranslation["comments"] | undefined, contextFile: string): import("openai/core.mjs").APIPromise<OpenAI.Chat.Completions.ChatCompletion>;
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>;
@@ -8,47 +8,59 @@ const __filename = fileURLToPath(import.meta.url);
8
8
  const __dirname = path.dirname(__filename);
9
9
  let _openai;
10
10
  let _systemprompt;
11
+ let _userprompt;
11
12
  let _userdict;
12
13
  export function init(force) {
13
14
  if (!_openai || force) {
14
15
  let configuration = {
15
- apiKey: process.env.OPENAI_API_KEY,
16
+ apiKey: process.env.OPENAI_API_KEY
16
17
  };
17
18
  _openai = new OpenAI(configuration);
18
19
  if (process.env.OPENAI_API_HOST) {
19
20
  _openai.baseURL = process.env.OPENAI_API_HOST.replace(/\/+$/, "") + "/v1";
20
21
  }
21
22
  }
22
- // load systemprompt.txt from homedir
23
+ // load systemprompt.txt from project
23
24
  if (!_systemprompt || force) {
24
- const systemprompt = findConfig("systemprompt.txt");
25
- copyFileIfNotExists(systemprompt, path.join(__dirname, "systemprompt.txt"));
26
- _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");
27
30
  }
28
31
  // load dictionary.json from homedir
29
32
  if (!_userdict || force) {
30
33
  const userdict = findConfig("dictionary.json");
31
34
  copyFileIfNotExists(userdict, path.join(__dirname, "dictionary.json"));
32
- _userdict = { "default": JSON.parse(fs.readFileSync(userdict, "utf-8")) };
35
+ _userdict = { default: JSON.parse(fs.readFileSync(userdict, "utf-8")) };
33
36
  }
34
37
  return _openai;
35
38
  }
36
- export function translate(text, src, lang, model, comments, contextFile) {
37
- const lang_code = lang.toLowerCase().trim().replace(/[\W_]+/g, "-");
38
- const dicts = Object.entries(_userdict[lang_code] || _userdict["default"])
39
- .filter(([k, _]) => text.toLowerCase().includes(k.toLowerCase()))
40
- .map(([k, v]) => [
41
- { role: "user", content: k },
42
- { role: "assistant", content: v },
43
- ])
44
- .flat();
45
- var notes = "";
46
- if (comments != undefined && comments.extracted != undefined)
47
- notes = comments.extracted;
48
- var context = "";
49
- if (contextFile !== undefined)
50
- context = "\n\n" + fs.readFileSync(contextFile, "utf-8");
51
- return _openai.chat.completions.create({
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({
52
64
  model: model,
53
65
  temperature: 0.1,
54
66
  messages: [
@@ -58,21 +70,41 @@ export function translate(text, src, lang, model, comments, contextFile) {
58
70
  },
59
71
  {
60
72
  role: "user",
61
- 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
62
75
  },
63
76
  {
64
77
  role: "assistant",
65
- 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.`
66
79
  },
67
- // add userdict here
68
- ...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
69
88
  {
70
89
  role: "user",
71
- content: "<translate>" + text + "</translate>"
72
- },
73
- ],
90
+ content: translationsContent
91
+ }
92
+ ]
74
93
  }, {
75
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
+ }
76
108
  });
77
109
  }
78
110
  export async function translatePo(model, po, source, lang, verbose, output, contextFile) {
@@ -84,7 +116,10 @@ export async function translatePo(model, po, source, lang, verbose, output, cont
84
116
  return;
85
117
  }
86
118
  // try to load dictionary by lang-code if it not loaded
87
- const lang_code = lang.toLowerCase().trim().replace(/[\W_]+/g, "-");
119
+ const lang_code = lang
120
+ .toLowerCase()
121
+ .trim()
122
+ .replace(/[\W_]+/g, "-");
88
123
  if (!_userdict[lang_code]) {
89
124
  const lang_dic_file = findConfig(`dictionary-${lang_code}.json`);
90
125
  if (fs.existsSync(lang_dic_file)) {
@@ -117,9 +152,9 @@ export async function translatePo(model, po, source, lang, verbose, output, cont
117
152
  return;
118
153
  }
119
154
  potrans.headers["Last-Translator"] = `gpt-po v${pkg.version}`;
155
+ const translations = [];
120
156
  let err429 = false;
121
- let modified = false;
122
- for (let i = 0; i < list.length; i++) {
157
+ for (let i = 0, c = 0; i < list.length; i++) {
123
158
  if (i == 0)
124
159
  printProgress(i, list.length);
125
160
  if (err429) {
@@ -127,40 +162,43 @@ export async function translatePo(model, po, source, lang, verbose, output, cont
127
162
  await new Promise((resolve) => setTimeout(resolve, 20000));
128
163
  }
129
164
  const trans = list[i];
130
- try {
131
- const res = await translate(trans.msgid, source, lang, model, trans.comments, contextFile);
132
- var translated = res.choices[0].message?.content || trans.msgstr[0];
133
- if (!translated.startsWith('<translated>') && !translated.endsWith('</translated>')) {
134
- // We got an error response
135
- console.log("Error: Unable to translate string [" + trans.msgid + "]. Bot says [" + translated + "]");
136
- continue;
137
- }
138
- // We got a valid translation response
139
- trans.msgstr[0] = translated.replace('<translated>', '').replace('</translated>', '');
140
- modified = true;
141
- if (verbose) {
142
- console.log(trans.msgid);
143
- console.log(trans.msgstr[0]);
144
- }
145
- printProgress(i + 1, list.length);
146
- await compilePo(potrans, output || po);
165
+ if (c < 2000) {
166
+ translations.push(trans);
167
+ c += trans.msgid.length;
147
168
  }
148
- catch (error) {
149
- if (error.response) {
150
- if (error.response.status == 429) {
151
- // caused by rate limit exceeded, should sleep for 20 seconds.
152
- err429 = true;
153
- --i;
154
- }
155
- else {
156
- console.error(error.response.status);
157
- console.log(error.response.data);
169
+ if (c >= 2000 || i == list.length - 1) {
170
+ try {
171
+ await translate(source, lang, model, translations, contextFile);
172
+ if (verbose) {
173
+ translations.forEach((trans) => {
174
+ console.log(trans.msgid);
175
+ console.log(trans.msgstr[0]);
176
+ });
158
177
  }
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);
159
184
  }
160
- else {
161
- console.error(error.message);
162
- if (error.code == "ECONNABORTED") {
163
- console.log('you may need to set "HTTPS_PROXY" to reach openai api.');
185
+ catch (error) {
186
+ if (error.response) {
187
+ if (error.response.status == 429) {
188
+ // caused by rate limit exceeded, should sleep for 20 seconds.
189
+ err429 = true;
190
+ --i;
191
+ }
192
+ else {
193
+ console.error(error.response.status);
194
+ console.log(error.response.data);
195
+ }
196
+ }
197
+ else {
198
+ console.error(error.message);
199
+ if (error.code == "ECONNABORTED") {
200
+ console.log('you may need to set "HTTPS_PROXY" to reach openai api.');
201
+ }
164
202
  }
165
203
  }
166
204
  }
@@ -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
@@ -36,13 +36,13 @@ export function parsePo(poFile, defaultCharset) {
36
36
  fs.readFile(poFile, (err, buffer) => {
37
37
  if (err)
38
38
  reject(err);
39
- var result = po.parse(buffer, defaultCharset ?? "utf-8");
39
+ const result = po.parse(buffer, defaultCharset ?? "utf-8");
40
40
  resolve(result);
41
41
  });
42
42
  });
43
43
  }
44
- export function compilePo(data, poFile) {
45
- const buffer = 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);
46
46
  return new Promise((resolve, reject) => {
47
47
  fs.writeFile(poFile, buffer, (err) => {
48
48
  if (err)
@@ -95,7 +95,7 @@ export function findConfig(fileName) {
95
95
  path.join(currentDir, ".gpt-po", fileName),
96
96
  path.join(currentDir, fileName),
97
97
  path.join(gitDir, ".gpt-po", fileName),
98
- path.join(homeDir, ".gpt-po", fileName)
98
+ path.join(homeDir, ".gpt-po", fileName),
99
99
  ];
100
100
  // check if file exists and return the first one
101
101
  for (const filePath of filePaths) {
@@ -111,10 +111,10 @@ export function findConfig(fileName) {
111
111
  * @param location folder or file path
112
112
  */
113
113
  export function openFileExplorer(location) {
114
- if (platform() === 'win32') {
114
+ if (platform() === "win32") {
115
115
  exec(`explorer.exe "${path.dirname(location)}"`);
116
116
  }
117
- else if (platform() === 'darwin') {
117
+ else if (platform() === "darwin") {
118
118
  exec(`open "${path.dirname(location)}"`);
119
119
  }
120
120
  else {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gpt-po",
3
- "version": "1.1.2",
3
+ "version": "1.2.0",
4
4
  "description": "command tool for translate po files by gpt",
5
5
  "main": "lib/src/index.js",
6
6
  "type": "module",