gpt-po 1.2.0 → 1.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -60,7 +60,7 @@ Options:
60
60
  --verbose show verbose log
61
61
  -l, --lang <lang> target language (ISO 639-1 code)
62
62
  -o, --output <file> output file path, overwirte po file by default
63
- --context context file path (provides additional context to the bot)
63
+ --context <file> context file path (provides additional context to the bot)
64
64
  -h, --help display help for command
65
65
  ```
66
66
 
package/README_zh-CN.md CHANGED
@@ -62,7 +62,7 @@ npm install gpt-po
62
62
  --verbose 显示详细日志
63
63
  -l, --lang <lang> 目标语言 (ISO 639-1 代码)
64
64
  -o, --output <file> 输出文件路径,默认覆盖 po 文件
65
- --context 上下文文件路径(为机器人提供额外的上下文)
65
+ --context <file> 上下文文件路径(为机器人提供额外的上下文)
66
66
  -h, --help 显示命令帮助
67
67
  ```
68
68
 
package/lib/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gpt-po",
3
- "version": "1.2.0",
3
+ "version": "1.2.3",
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 --no-warnings=ExperimentalWarning
1
+ #!/usr/bin/env -S node --no-warnings=ExperimentalWarning
2
2
  export {};
package/lib/src/index.js CHANGED
@@ -1,18 +1,34 @@
1
- #!/usr/bin/env node --no-warnings=ExperimentalWarning
1
+ #!/usr/bin/env -S node --no-warnings=ExperimentalWarning
2
2
  import { Command, Option } from "commander";
3
3
  import path from "path";
4
4
  import { fileURLToPath } from "url";
5
5
  import pkg from "../package.json" with { type: "json" };
6
+ import { removeByOptions } from "./manipulate.js";
6
7
  import { sync } from "./sync.js";
7
8
  import { init, translatePo, translatePoDir } from "./translate.js";
8
- import { copyFileIfNotExists, compilePo, findConfig, openFileByDefault, openFileExplorer, parsePo } from "./utils.js";
9
- import { removeByOptions } from "./manipulate.js";
9
+ import { compilePo, copyFileIfNotExists, findConfig, openFileByDefault, openFileExplorer, parsePo } from "./utils.js";
10
10
  const __filename = fileURLToPath(import.meta.url);
11
11
  const __dirname = path.dirname(__filename);
12
12
  const program = new Command();
13
13
  program.name(pkg.name).version(pkg.version).description(pkg.description);
14
- program
15
- .command("translate", { isDefault: true })
14
+ const getCompileOptions = (args) => {
15
+ const foldLength = args.poFoldLen === "false" ? 0 : parseInt(args.poFoldLen);
16
+ const sort = args.poSort;
17
+ const escapeCharacters = args.poEscChars;
18
+ if (isNaN(foldLength)) {
19
+ console.error("--po-fold-len must be a number or false");
20
+ process.exit(1);
21
+ }
22
+ return { foldLength, sort, escapeCharacters };
23
+ };
24
+ class SharedOptionsCommand extends Command {
25
+ addCompileOptions() {
26
+ return this.option("--po-fold-len <length>", "a gettext compile option, the length at which to fold message strings into newlines, set to 0 or false to disable folding", "120")
27
+ .option("--po-sort", "a gettext compile option, sort entries by msgid", false)
28
+ .option("--po-esc-chars", "a gettext compile option, escape characters in output, if false, will skip escape newlines and quotes characters functionality", true);
29
+ }
30
+ }
31
+ const translateCommand = new SharedOptionsCommand("translate")
16
32
  .description("translate po file (default command)")
17
33
  .addOption(new Option("-k, --key <key>", "openai api key").env("OPENAI_API_KEY"))
18
34
  .addOption(new Option("--host <host>", "openai api host").env("OPENAI_API_HOST"))
@@ -24,6 +40,7 @@ program
24
40
  .option("--verbose", "print verbose log")
25
41
  .option("--context <file>", "text file that provides the bot additional context")
26
42
  .addOption(new Option("-o, --output <file>", "output file path, overwirte po file by default").conflicts("dir"))
43
+ .addCompileOptions()
27
44
  .action(async (args) => {
28
45
  const { key, host, model, po, dir, source, lang, verbose, output, context } = args;
29
46
  if (host) {
@@ -38,25 +55,30 @@ program
38
55
  process.exit(1);
39
56
  }
40
57
  init();
58
+ const compileOptions = getCompileOptions(args);
41
59
  if (po) {
42
- await translatePo(model, po, source, lang, verbose, output, context);
60
+ await translatePo(model, po, source, lang, verbose, output, context, compileOptions);
43
61
  }
44
62
  else if (dir) {
45
- await translatePoDir(model, dir, source, lang, verbose, context);
63
+ await translatePoDir(model, dir, source, lang, verbose, context, compileOptions);
46
64
  }
47
65
  else {
48
66
  console.error("po file or directory is required");
49
67
  process.exit(1);
50
68
  }
51
69
  });
52
- program
53
- .command("sync")
70
+ program.addCommand(translateCommand, { isDefault: true });
71
+ const syncCommand = new SharedOptionsCommand("sync")
54
72
  .description("update po from pot file")
55
73
  .requiredOption("--po <file>", "po file path")
56
74
  .requiredOption("--pot <file>", "pot file path")
57
- .action(async ({ po, pot }) => {
58
- await sync(po, pot);
75
+ .option("-o, --output <file>", "output file path, overwirte po file by default")
76
+ .addCompileOptions()
77
+ .action(async (args) => {
78
+ const { po, pot } = args;
79
+ await sync(po, pot, getCompileOptions(args));
59
80
  });
81
+ program.addCommand(syncCommand);
60
82
  // program command `userdict` with help text `open/edit user dictionary`
61
83
  program
62
84
  .command("userdict")
@@ -78,8 +100,7 @@ program
78
100
  openFileByDefault(dictFile);
79
101
  });
80
102
  // program command `remove` with help text `remove po entries by options`
81
- program
82
- .command("remove")
103
+ const removeCommand = new SharedOptionsCommand("remove")
83
104
  .description("remove po entries by options")
84
105
  .requiredOption("--po <file>", "po file path")
85
106
  .option("--fuzzy", "remove fuzzy entries")
@@ -89,7 +110,10 @@ program
89
110
  .option("-tnf, --translated-not-fuzzy", "remove translated not fuzzy entries")
90
111
  .option("-ft, --fuzzy-translated", "remove fuzzy translated entries")
91
112
  .option("-rc, --reference-contains <text>", "remove entries whose reference contains text, text can be a regular expression like /text/ig")
113
+ .option("-o, --output <file>", "output file path, overwirte po file by default")
114
+ .addCompileOptions()
92
115
  .action(async (args) => {
116
+ this;
93
117
  const { po, fuzzy, obsolete, untranslated, translated, translatedNotFuzzy, fuzzyTranslated, referenceContains } = args;
94
118
  const options = {
95
119
  fuzzy,
@@ -102,8 +126,9 @@ program
102
126
  };
103
127
  const output = args.output || po;
104
128
  const translations = await parsePo(po);
105
- await compilePo(removeByOptions(translations, options), output);
129
+ await compilePo(removeByOptions(translations, options), output, getCompileOptions(args));
106
130
  console.log("done");
107
131
  });
132
+ program.addCommand(removeCommand);
108
133
  program.parse(process.argv);
109
134
  //# sourceMappingURL=index.js.map
package/lib/src/sync.d.ts CHANGED
@@ -1 +1,2 @@
1
- export declare function sync(po: string, pot: string): Promise<void>;
1
+ import { CompileOptions } from "./utils.js";
2
+ export declare function sync(po: string, pot: string, compileOptions?: CompileOptions): Promise<void>;
package/lib/src/sync.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { compilePo, parsePo } from "./utils.js";
2
- export async function sync(po, pot) {
2
+ export async function sync(po, pot, compileOptions) {
3
3
  const potrans = await parsePo(po);
4
4
  const potrans2 = await parsePo(pot);
5
5
  for (const [ctx, entries] of Object.entries(potrans2.translations)) {
@@ -13,6 +13,6 @@ export async function sync(po, pot) {
13
13
  }
14
14
  }
15
15
  potrans.translations = potrans2.translations;
16
- await compilePo(potrans, po);
16
+ await compilePo(potrans, po, compileOptions);
17
17
  }
18
18
  //# sourceMappingURL=sync.js.map
@@ -1,6 +1,7 @@
1
1
  import { GetTextTranslation } from "gettext-parser";
2
2
  import { OpenAI } from "openai";
3
+ import { CompileOptions } from "./utils.js";
3
4
  export declare function init(force?: boolean): OpenAI;
4
5
  export declare function translate(src: string, lang: string, model: string, translations: GetTextTranslation[], contextFile: string): Promise<void>;
5
- export declare function translatePo(model: string, po: string, source: string, lang: string, verbose: boolean, output: string, contextFile: string): Promise<void>;
6
- export declare function translatePoDir(model: string | undefined, dir: string, source: string, lang: string, verbose: boolean, contextFile: string): Promise<void>;
6
+ export declare function translatePo(model: string, po: string, source: string, lang: string, verbose: boolean, output: string, contextFile: string, compileOptions?: CompileOptions): Promise<void>;
7
+ export declare function translatePoDir(model: string | undefined, dir: string, source: string, lang: string, verbose: boolean, contextFile: string, compileOptions?: CompileOptions): Promise<void>;
@@ -58,7 +58,10 @@ export async function translate(src, lang, model, translations, contextFile) {
58
58
  .join("\n");
59
59
  const context = contextFile ? "\n\nContext: " + fs.readFileSync(contextFile, "utf-8") : "";
60
60
  const translationsContent = translations
61
- .map((tr, idx) => `<translate index="${idx + dicts.user.length + 1}">${tr.msgid}</translate>`)
61
+ .map((tr, idx) => {
62
+ const contextAttr = tr.msgctxt ? ` context="${tr.msgctxt}"` : "";
63
+ return `<translate index="${idx + dicts.user.length + 1}"${contextAttr}>${tr.msgid}</translate>`;
64
+ })
62
65
  .join("\n");
63
66
  const res = await _openai.chat.completions.create({
64
67
  model: model,
@@ -107,7 +110,7 @@ export async function translate(src, lang, model, translations, contextFile) {
107
110
  }
108
111
  });
109
112
  }
110
- export async function translatePo(model, po, source, lang, verbose, output, contextFile) {
113
+ export async function translatePo(model, po, source, lang, verbose, output, contextFile, compileOptions) {
111
114
  const potrans = await parsePo(po);
112
115
  if (!lang)
113
116
  lang = potrans.headers["Language"];
@@ -132,11 +135,16 @@ export async function translatePo(model, po, source, lang, verbose, output, cont
132
135
  let trimed = false;
133
136
  for (const [ctx, entries] of Object.entries(potrans.translations)) {
134
137
  for (const [msgid, trans] of Object.entries(entries)) {
135
- if (msgid == "")
138
+ if (msgid === "")
136
139
  continue;
137
140
  if (!trans.msgstr[0]) {
138
- list.push(trans);
139
- continue;
141
+ list.push({
142
+ msgctxt: trans.msgctxt || ctx,
143
+ msgid,
144
+ msgid_plural: trans.msgid_plural,
145
+ msgstr: trans.msgstr,
146
+ comments: trans.comments
147
+ });
140
148
  }
141
149
  else if (trimRegx.test(trans.msgstr[0])) {
142
150
  trimed = true;
@@ -145,7 +153,7 @@ export async function translatePo(model, po, source, lang, verbose, output, cont
145
153
  }
146
154
  }
147
155
  if (trimed) {
148
- await compilePo(potrans, po);
156
+ await compilePo(potrans, po, compileOptions);
149
157
  }
150
158
  if (list.length == 0) {
151
159
  console.log("done.");
@@ -180,7 +188,7 @@ export async function translatePo(model, po, source, lang, verbose, output, cont
180
188
  // update progress
181
189
  printProgress(i + 1, list.length);
182
190
  // save po file after each 2000 characters
183
- await compilePo(potrans, output || po);
191
+ await compilePo(potrans, output || po, compileOptions);
184
192
  }
185
193
  catch (error) {
186
194
  if (error.response) {
@@ -205,13 +213,13 @@ export async function translatePo(model, po, source, lang, verbose, output, cont
205
213
  }
206
214
  console.log("done.");
207
215
  }
208
- export async function translatePoDir(model = "gpt-3.5-turbo", dir, source, lang, verbose, contextFile) {
216
+ export async function translatePoDir(model = "gpt-3.5-turbo", dir, source, lang, verbose, contextFile, compileOptions) {
209
217
  const files = fs.readdirSync(dir);
210
218
  for (const file of files) {
211
219
  if (file.endsWith(".po")) {
212
220
  const po = path.join(dir, file);
213
221
  console.log(`translating ${po}`);
214
- await translatePo(model, po, source, lang, verbose, po, contextFile);
222
+ await translatePo(model, po, source, lang, verbose, po, contextFile, compileOptions);
215
223
  }
216
224
  }
217
225
  }
@@ -12,7 +12,14 @@ Translation guidelines are as follows:
12
12
  - Input messages will be wrapped in `<translate>` XML tags with an index attribute, e.g., `<translate index="1">`.
13
13
  - Respond with the translated message wrapped in `<translated>` XML tags, including the same index attribute, e.g., `<translated index="1">`.
14
14
 
15
- 4. **Multiple Translations**:
15
+ 4. **Context Handling**:
16
+ - Some messages will include a context attribute in the translate tag, e.g., `<translate index="1" context="Menu">`.
17
+ - Use this context to inform your translation but only return the translated text.
18
+ - Example:
19
+ Input: `<translate index="1" context="Menu">File</translate>`
20
+ Output: `<translated index="1">Fichier</translated>`
21
+
22
+ 5. **Multiple Translations**:
16
23
  - You may receive multiple translation requests in a single input, each with a unique index.
17
24
  - Ensuring the complete number of requests are translated, even if they are repeated, while maintaining the original order when possible.
18
25
 
@@ -8,12 +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 type compileOptions = {
11
+ export type CompileOptions = {
12
12
  foldLength?: number;
13
13
  sort?: boolean | ((a: never, b: never) => number);
14
14
  escapeCharacters?: boolean;
15
15
  };
16
- export declare function compilePo(data: GetTextTranslations, poFile: string, options?: compileOptions): Promise<void>;
16
+ export declare function compilePo(data: GetTextTranslations, poFile: string, options?: CompileOptions): Promise<void>;
17
17
  export declare function printProgress(progress: number, total: number, extra?: string): void;
18
18
  export declare function gitRootDir(dir?: string): string | null;
19
19
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gpt-po",
3
- "version": "1.2.0",
3
+ "version": "1.2.3",
4
4
  "description": "command tool for translate po files by gpt",
5
5
  "main": "lib/src/index.js",
6
6
  "type": "module",