gpt-po 1.1.2 → 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
@@ -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",