msgai-cli 1.0.0 → 1.0.1

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.
@@ -45,7 +45,7 @@ async function runTranslate(poFilePath, apiKey, sourceLang, includeFuzzy) {
45
45
  try {
46
46
  const poContent = node_fs_1.default.readFileSync(poFilePath, 'utf8');
47
47
  const parsedPo = (0, po_1.parsePoContent)(poContent);
48
- const { entries, keys } = (0, po_1.getEntriesToTranslate)(parsedPo, { includeFuzzy });
48
+ const { entries } = (0, po_1.getEntriesToTranslate)(parsedPo, { includeFuzzy });
49
49
  if (entries.length === 0) {
50
50
  console.log(`Nothing to translate in ${poFilePath}.`);
51
51
  return 0;
@@ -63,7 +63,6 @@ async function runTranslate(poFilePath, apiKey, sourceLang, includeFuzzy) {
63
63
  }
64
64
  }
65
65
  const options = { apiKey, sourceLanguage: sourceLang, formula, pluralSamples };
66
- const allResults = [];
67
66
  for (let i = 0; i < entries.length; i += TRANSLATE_BATCH_SIZE) {
68
67
  const batch = entries.slice(i, i + TRANSLATE_BATCH_SIZE);
69
68
  const batchNum = Math.floor(i / TRANSLATE_BATCH_SIZE) + 1;
@@ -78,13 +77,12 @@ async function runTranslate(poFilePath, apiKey, sourceLang, includeFuzzy) {
78
77
  console.log(` ${r.msgid_plural} (plural) => ${r.msgstr.join(' | ')}`);
79
78
  }
80
79
  }
81
- allResults.push(...batchResults);
82
- }
83
- (0, po_1.applyTranslations)(parsedPo, keys, allResults);
84
- if (includeFuzzy) {
85
- (0, po_1.clearFuzzyFromEntries)(parsedPo, keys);
80
+ (0, po_1.applyTranslations)(parsedPo, batchResults);
81
+ if (includeFuzzy) {
82
+ (0, po_1.clearFuzzyFromEntries)(parsedPo, batchResults);
83
+ }
84
+ node_fs_1.default.writeFileSync(poFilePath, (0, po_1.compilePo)(parsedPo));
86
85
  }
87
- node_fs_1.default.writeFileSync(poFilePath, (0, po_1.compilePo)(parsedPo), undefined);
88
86
  return 0;
89
87
  }
90
88
  catch (error) {
@@ -13,6 +13,6 @@ let loaded = false;
13
13
  function loadEnv() {
14
14
  if (loaded)
15
15
  return;
16
- dotenv_1.default.config({ path: node_path_1.default.resolve(process.cwd(), '.env') });
16
+ dotenv_1.default.config({ path: node_path_1.default.resolve(process.cwd(), '.env'), quiet: true });
17
17
  loaded = true;
18
18
  }
package/dist/src/po.js CHANGED
@@ -101,17 +101,17 @@ function getEntriesToTranslate(parsedPo, options) {
101
101
  /**
102
102
  * Applies translation results into the parsed PO (mutates parsedPo.translations).
103
103
  * Singular results become one-element msgstr; plural results stay as string[].
104
+ * Lookup is by result.msgctxt (default '') and result.msgid.
104
105
  */
105
- function applyTranslations(parsedPo, keys, results) {
106
- for (let i = 0; i < keys.length; i++) {
107
- const key = keys[i];
108
- const result = results[i];
106
+ function applyTranslations(parsedPo, results) {
107
+ for (const result of results) {
109
108
  if (result == null)
110
109
  continue;
111
- const contextEntries = parsedPo.translations[key.context];
110
+ const context = result.msgctxt ?? '';
111
+ const contextEntries = parsedPo.translations[context];
112
112
  if (contextEntries == null)
113
113
  continue;
114
- const entry = contextEntries[key.msgid];
114
+ const entry = contextEntries[result.msgid];
115
115
  if (entry == null)
116
116
  continue;
117
117
  if (typeof result.msgstr === 'string') {
@@ -123,15 +123,16 @@ function applyTranslations(parsedPo, keys, results) {
123
123
  }
124
124
  }
125
125
  /**
126
- * Removes the "fuzzy" flag from entries at the given keys (mutates parsedPo.translations).
127
- * Used after applying new translations so fuzzy entries are no longer marked fuzzy.
126
+ * Removes the "fuzzy" flag from entries corresponding to the given results (mutates parsedPo.translations).
127
+ * Lookup is by result.msgctxt (default '') and result.msgid.
128
128
  */
129
- function clearFuzzyFromEntries(parsedPo, keys) {
130
- for (const key of keys) {
131
- const contextEntries = parsedPo.translations[key.context];
129
+ function clearFuzzyFromEntries(parsedPo, results) {
130
+ for (const result of results) {
131
+ const context = result.msgctxt ?? '';
132
+ const contextEntries = parsedPo.translations[context];
132
133
  if (contextEntries == null)
133
134
  continue;
134
- const entry = contextEntries[key.msgid];
135
+ const entry = contextEntries[result.msgid];
135
136
  if (entry == null || !entry.comments?.flag)
136
137
  continue;
137
138
  const newFlag = entry.comments.flag
package/package.json CHANGED
@@ -1,13 +1,14 @@
1
1
  {
2
2
  "name": "msgai-cli",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "description": "CLI that automatically translates all untranslated strings in gettext (.po) files using AI (LLM)",
5
5
  "main": "dist/src/cli/index.js",
6
6
  "bin": {
7
7
  "msgai": "dist/src/cli/index.js"
8
8
  },
9
9
  "scripts": {
10
- "build": "tsc -p tsconfig.json",
10
+ "clean": "rm -rf dist",
11
+ "build": "npm run clean && tsc -p tsconfig.json",
11
12
  "test": "npm run build && jest",
12
13
  "test:integration": "npm run build && jest -c jest.integration.config.cjs",
13
14
  "test:watch": "npm run build && jest --watch",
package/dist/src/cli.js DELETED
@@ -1,169 +0,0 @@
1
- #!/usr/bin/env node
2
- "use strict";
3
- var __importDefault = (this && this.__importDefault) || function (mod) {
4
- return (mod && mod.__esModule) ? mod : { "default": mod };
5
- };
6
- Object.defineProperty(exports, "__esModule", { value: true });
7
- exports.runTranslate = runTranslate;
8
- const node_fs_1 = __importDefault(require("node:fs"));
9
- const yargs_1 = __importDefault(require("yargs/yargs"));
10
- const helpers_1 = require("yargs/helpers");
11
- const po_1 = require("./po");
12
- const translate_1 = require("./translate");
13
- const validate_source_lang_1 = require("./validate-source-lang");
14
- const TRANSLATE_BATCH_SIZE = 15;
15
- function parseArgs(argv) {
16
- try {
17
- const parsedArgs = (0, yargs_1.default)(argv)
18
- .scriptName('msgai')
19
- .usage('Usage: msgai <file.po> [--dry-run] [--api-key KEY] [--source-lang LANG]')
20
- .option('dry-run', {
21
- type: 'boolean',
22
- default: false,
23
- })
24
- .option('api-key', {
25
- type: 'string',
26
- description: 'OpenAI API key (otherwise read from OPENAI_API_KEY env)',
27
- })
28
- .option('source-lang', {
29
- type: 'string',
30
- description: 'Source language of msgid strings (ISO 639-1 code, e.g. en, uk). If omitted, the model will detect it.',
31
- })
32
- .option('help', {
33
- alias: 'h',
34
- type: 'boolean',
35
- default: false,
36
- })
37
- .strictOptions()
38
- .version(false)
39
- .exitProcess(false)
40
- .fail((message, error) => {
41
- if (error) {
42
- throw error;
43
- }
44
- throw new Error(message);
45
- })
46
- .parseSync();
47
- const positionalArgs = parsedArgs._.map(String);
48
- const sourceLangRaw = parsedArgs['source-lang'];
49
- const sourceLang = sourceLangRaw != null && String(sourceLangRaw).trim() !== ''
50
- ? String(sourceLangRaw).trim().toLowerCase()
51
- : undefined;
52
- if (positionalArgs.length > 1) {
53
- return {
54
- dryRun: Boolean(parsedArgs['dry-run']),
55
- help: Boolean(parsedArgs.help),
56
- apiKey: parsedArgs['api-key'],
57
- sourceLang,
58
- error: `Unexpected argument: ${positionalArgs[1]}`,
59
- };
60
- }
61
- return {
62
- poFilePath: positionalArgs[0],
63
- dryRun: Boolean(parsedArgs['dry-run']),
64
- help: Boolean(parsedArgs.help),
65
- apiKey: parsedArgs['api-key'],
66
- sourceLang,
67
- };
68
- }
69
- catch (error) {
70
- const message = error instanceof Error ? error.message : String(error);
71
- return { dryRun: false, help: false, error: message };
72
- }
73
- }
74
- async function runTranslate(poFilePath, apiKey, sourceLang) {
75
- try {
76
- const poContent = node_fs_1.default.readFileSync(poFilePath, 'utf8');
77
- const parsedPo = (0, po_1.parsePoContent)(poContent);
78
- const { entries, keys } = (0, po_1.getEntriesToTranslate)(parsedPo);
79
- if (entries.length === 0) {
80
- console.log(`Nothing to translate in ${poFilePath}.`);
81
- return 0;
82
- }
83
- const targetLanguage = (0, po_1.getLanguage)(parsedPo) ?? 'en';
84
- const formula = (0, po_1.getPluralForms)(parsedPo) ?? '';
85
- const options = { apiKey, sourceLanguage: sourceLang, formula };
86
- const allResults = [];
87
- for (let i = 0; i < entries.length; i += TRANSLATE_BATCH_SIZE) {
88
- const batch = entries.slice(i, i + TRANSLATE_BATCH_SIZE);
89
- const batchNum = Math.floor(i / TRANSLATE_BATCH_SIZE) + 1;
90
- const totalBatches = Math.ceil(entries.length / TRANSLATE_BATCH_SIZE);
91
- console.log(`Translating batch ${batchNum}/${totalBatches} (${batch.length} phrase${batch.length === 1 ? '' : 's'})...`);
92
- const batchResults = await (0, translate_1.translateStrings)(batch, targetLanguage, options);
93
- for (const r of batchResults) {
94
- if (typeof r.msgstr === 'string') {
95
- console.log(` ${r.msgid} => ${r.msgstr}`);
96
- }
97
- else {
98
- console.log(` ${r.msgid_plural} (plural) => ${r.msgstr.join(' | ')}`);
99
- }
100
- }
101
- allResults.push(...batchResults);
102
- }
103
- (0, po_1.applyTranslations)(parsedPo, keys, allResults);
104
- node_fs_1.default.writeFileSync(poFilePath, (0, po_1.compilePo)(parsedPo), undefined);
105
- return 0;
106
- }
107
- catch (error) {
108
- const message = error instanceof Error ? error.message : String(error);
109
- console.error(`Failed to process PO file: ${message}`);
110
- return 1;
111
- }
112
- }
113
- function main(argv) {
114
- const args = parseArgs(argv);
115
- if (args.error) {
116
- console.error(args.error);
117
- console.error('Usage: msgai <file.po> [--dry-run] [--api-key KEY] [--source-lang LANG]');
118
- return 1;
119
- }
120
- if (args.help) {
121
- console.log('Usage: msgai <file.po> [--dry-run] [--api-key KEY] [--source-lang LANG]');
122
- return 0;
123
- }
124
- if (!args.poFilePath) {
125
- console.error('Usage: msgai <file.po> [--dry-run] [--api-key KEY] [--source-lang LANG]');
126
- return 1;
127
- }
128
- if (args.sourceLang != null) {
129
- try {
130
- (0, validate_source_lang_1.validateSourceLang)(args.sourceLang);
131
- }
132
- catch (error) {
133
- const message = error instanceof Error ? error.message : String(error);
134
- console.error(message);
135
- return 1;
136
- }
137
- }
138
- if (!args.dryRun) {
139
- let resultApiKey;
140
- try {
141
- resultApiKey = (0, translate_1.resolveApiKey)(args.apiKey);
142
- }
143
- catch (error) {
144
- const message = error instanceof Error ? error.message : String(error);
145
- console.error(message.replace('pass apiKey in options', 'pass --api-key'));
146
- return 1;
147
- }
148
- runTranslate(args.poFilePath, resultApiKey, args.sourceLang).then((code) => process.exit(code));
149
- return undefined;
150
- }
151
- try {
152
- const poContent = node_fs_1.default.readFileSync(args.poFilePath, 'utf8');
153
- const parsedPo = (0, po_1.parsePoContent)(poContent);
154
- const untranslatedMsgids = (0, po_1.getUntranslatedMsgids)(parsedPo);
155
- for (const msgid of untranslatedMsgids) {
156
- console.log(msgid);
157
- }
158
- }
159
- catch (error) {
160
- const message = error instanceof Error ? error.message : String(error);
161
- console.error(`Failed to process PO file: ${message}`);
162
- return 1;
163
- }
164
- return 0;
165
- }
166
- const exitCode = main((0, helpers_1.hideBin)(process.argv));
167
- if (typeof exitCode === 'number') {
168
- process.exit(exitCode);
169
- }
@@ -1,68 +0,0 @@
1
- msgid ""
2
- msgstr ""
3
- "Content-Type: text/plain; charset=utf-8\n"
4
- "Plural-Forms: nplurals = 2; plural = (n != 1);\n"
5
- "Language: en\n"
6
- "MIME-Version: 1.0\n"
7
- "Content-Transfer-Encoding: 8bit\n"
8
-
9
- #: src/templates/baseHTML.mjs:11
10
- msgid "Krejčovství Švadlenka – Oprava a úprava oděvů Praha 2"
11
- msgstr "Švadlenka Tailor Shop – Repair and Alteration of Clothing Prague 2"
12
-
13
- #: src/templates/baseHTML.mjs:12
14
- msgid ""
15
- "Švadlenka je krejčovství na Praze 2, které nabízí kvalitní opravy a úpravy "
16
- "oblečení – džíny, kabáty, podšívky, batohy i záclony. Najdete nás na "
17
- "Jaromírově 726/15."
18
- msgstr ""
19
- "Švadlenka is a tailor shop in Prague 2 offering quality repairs and "
20
- "alterations of clothing – jeans, coats, linings, backpacks, and curtains. "
21
- "You can find us at Jaromírova 726/15."
22
-
23
- #: src/templates/baseHTML.mjs:13
24
- msgid ""
25
- "krejčovství, oprava oblečení, úprava oděvů, výměna zipu, podšívka, záclony, "
26
- "Praha 2, Nusle"
27
- msgstr ""
28
- "tailor shop, clothes repair, clothing alteration, zipper replacement, "
29
- "lining, curtains, Prague 2, Nusle"
30
-
31
- #: src/templates/baseHTML.mjs:14
32
- msgid "Krejčovství Švadlenka – Praha 2"
33
- msgstr "Švadlenka Tailor Shop – Prague 2"
34
-
35
- #: src/templates/baseHTML.mjs:15
36
- msgid "Opravy a úpravy oblečení, záclon, batohů – najdete nás na Jaromírově 726/15."
37
- msgstr ""
38
- "Repairs and alterations of clothes, curtains, backpacks – you can find us "
39
- "at Jaromírova 726/15."
40
-
41
- #: src/templates/header.mjs:14
42
- #: src/templates/header.mjs:43
43
- msgid "Úvod"
44
- msgstr "Introduction"
45
-
46
- #: src/pages/sluzby.mjs:28
47
- #: src/templates/header.mjs:15
48
- #: src/templates/header.mjs:44
49
- msgid "Služby a ceník"
50
- msgstr "Services and Price List"
51
-
52
- #: src/templates/header.mjs:16
53
- #: src/templates/header.mjs:45
54
- #: src/templates/kontakty.mjs:5
55
- msgid "Kontakty"
56
- msgstr "Contacts"
57
-
58
- #: src/templates/kontakty.mjs:23
59
- msgid "Po – Čt: 10:00 – 18:00"
60
- msgstr "Mon – Thu: 10:00 AM – 6:00 PM"
61
-
62
- #: src/templates/kontakty.mjs:24
63
- msgid "Pá: 10:00 – 16:00"
64
- msgstr "Fri: 10:00 AM – 4:00 PM"
65
-
66
- #: src/templates/review.mjs:16
67
- msgid "Budeme vděční za vaši recenzi"
68
- msgstr "We would appreciate your review"
@@ -1,61 +0,0 @@
1
- msgid ""
2
- msgstr ""
3
- "Content-Type: text/plain; charset=utf-8\n"
4
- "Plural-Forms: nplurals = 3; plural = (n % 10 == 1 && n % 100 != 11 ? 0 : n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 10 || n % 100 >= 20) ? 1 : 2);\n"
5
- "Language: ru\n"
6
- "MIME-Version: 1.0\n"
7
- "Content-Transfer-Encoding: 8bit\n"
8
-
9
- #: src/templates/baseHTML.mjs:11
10
- msgid "Krejčovství Švadlenka – Oprava a úprava oděvů Praha 2"
11
- msgstr ""
12
-
13
- #: src/templates/baseHTML.mjs:12
14
- msgid ""
15
- "Švadlenka je krejčovství na Praze 2, které nabízí kvalitní opravy a úpravy "
16
- "oblečení – džíny, kabáty, podšívky, batohy i záclony. Najdete nás na "
17
- "Jaromírově 726/15."
18
- msgstr ""
19
-
20
- #: src/templates/baseHTML.mjs:13
21
- msgid ""
22
- "krejčovství, oprava oblečení, úprava oděvů, výměna zipu, podšívka, záclony, "
23
- "Praha 2, Nusle"
24
- msgstr ""
25
-
26
- #: src/templates/baseHTML.mjs:14
27
- msgid "Krejčovství Švadlenka – Praha 2"
28
- msgstr ""
29
-
30
- #: src/templates/baseHTML.mjs:15
31
- msgid "Opravy a úpravy oblečení, záclon, batohů – najdete nás na Jaromírově 726/15."
32
- msgstr ""
33
-
34
- #: src/templates/header.mjs:14
35
- #: src/templates/header.mjs:43
36
- msgid "Úvod"
37
- msgstr ""
38
-
39
- #: src/pages/sluzby.mjs:28
40
- #: src/templates/header.mjs:15
41
- #: src/templates/header.mjs:44
42
- msgid "Služby a ceník"
43
- msgstr ""
44
-
45
- #: src/templates/header.mjs:16
46
- #: src/templates/header.mjs:45
47
- #: src/templates/kontakty.mjs:5
48
- msgid "Kontakty"
49
- msgstr ""
50
-
51
- #: src/templates/kontakty.mjs:23
52
- msgid "Po – Čt: 10:00 – 18:00"
53
- msgstr ""
54
-
55
- #: src/templates/kontakty.mjs:24
56
- msgid "Pá: 10:00 – 16:00"
57
- msgstr ""
58
-
59
- #: src/templates/review.mjs:16
60
- msgid "Budeme vděční za vaši recenzi"
61
- msgstr ""
@@ -1,69 +0,0 @@
1
- msgid ""
2
- msgstr ""
3
- "Content-Type: text/plain; charset=utf-8\n"
4
- "Plural-Forms: nplurals = 3; plural = (n % 10 == 1 && n % 100 != 11 ? 0 : n "
5
- "% 10 >= 2 && n % 10 <= 4 && (n % 100 < 10 || n % 100 >= 20) ? 1 : 2);\n"
6
- "Language: uk\n"
7
- "MIME-Version: 1.0\n"
8
- "Content-Transfer-Encoding: 8bit\n"
9
-
10
- #: src/templates/baseHTML.mjs:11
11
- msgid "Krejčovství Švadlenka – Oprava a úprava oděvů Praha 2"
12
- msgstr "Ательє Швадленка – Ремонт та переробка одягу Прага 2"
13
-
14
- #: src/templates/baseHTML.mjs:12
15
- msgid ""
16
- "Švadlenka je krejčovství na Praze 2, které nabízí kvalitní opravy a úpravy "
17
- "oblečení – džíny, kabáty, podšívky, batohy i záclony. Najdete nás na "
18
- "Jaromírově 726/15."
19
- msgstr ""
20
- "Швадленка – це ательє в Празі 2, яке пропонує якісний ремонт та переробку "
21
- "одягу – джинси, пальта, підкладки, рюкзаки та штори. Знайдете нас на "
22
- "Яроміровій 726/15."
23
-
24
- #: src/templates/baseHTML.mjs:13
25
- msgid ""
26
- "krejčovství, oprava oblečení, úprava oděvů, výměna zipu, podšívka, záclony, "
27
- "Praha 2, Nusle"
28
- msgstr ""
29
- "ательє, ремонт одягу, переробка одягу, заміна блискавки, підкладка, штори, "
30
- "Прага 2, Нусле"
31
-
32
- #: src/templates/baseHTML.mjs:14
33
- msgid "Krejčovství Švadlenka – Praha 2"
34
- msgstr "Ательє Швадленка – Прага 2"
35
-
36
- #: src/templates/baseHTML.mjs:15
37
- msgid "Opravy a úpravy oblečení, záclon, batohů – najdete nás na Jaromírově 726/15."
38
- msgstr ""
39
- "Ремонт та переробка одягу, штор, рюкзаків – знайдете нас на Яроміровій "
40
- "726/15."
41
-
42
- #: src/templates/header.mjs:14
43
- #: src/templates/header.mjs:43
44
- msgid "Úvod"
45
- msgstr "Вступ"
46
-
47
- #: src/pages/sluzby.mjs:28
48
- #: src/templates/header.mjs:15
49
- #: src/templates/header.mjs:44
50
- msgid "Služby a ceník"
51
- msgstr "Послуги та прейскурант"
52
-
53
- #: src/templates/header.mjs:16
54
- #: src/templates/header.mjs:45
55
- #: src/templates/kontakty.mjs:5
56
- msgid "Kontakty"
57
- msgstr "Контакти"
58
-
59
- #: src/templates/kontakty.mjs:23
60
- msgid "Po – Čt: 10:00 – 18:00"
61
- msgstr "Пн – Чт: 10:00 – 18:00"
62
-
63
- #: src/templates/kontakty.mjs:24
64
- msgid "Pá: 10:00 – 16:00"
65
- msgstr "Пт: 10:00 – 16:00"
66
-
67
- #: src/templates/review.mjs:16
68
- msgid "Budeme vděční za vaši recenzi"
69
- msgstr "Будемо вдячні за ваш відгук"
@@ -1,49 +0,0 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.runTranslate = runTranslate;
7
- const node_fs_1 = __importDefault(require("node:fs"));
8
- const po_1 = require("./po");
9
- const translate_1 = require("./translate");
10
- const TRANSLATE_BATCH_SIZE = 15;
11
- async function runTranslate(poFilePath, apiKey, sourceLang) {
12
- try {
13
- const poContent = node_fs_1.default.readFileSync(poFilePath, 'utf8');
14
- const parsedPo = (0, po_1.parsePoContent)(poContent);
15
- const { entries, keys } = (0, po_1.getEntriesToTranslate)(parsedPo);
16
- if (entries.length === 0) {
17
- console.log(`Nothing to translate in ${poFilePath}.`);
18
- return 0;
19
- }
20
- const targetLanguage = (0, po_1.getLanguage)(parsedPo) ?? 'en';
21
- const formula = (0, po_1.getPluralForms)(parsedPo) ?? '';
22
- const options = { apiKey, sourceLanguage: sourceLang, formula };
23
- const allResults = [];
24
- for (let i = 0; i < entries.length; i += TRANSLATE_BATCH_SIZE) {
25
- const batch = entries.slice(i, i + TRANSLATE_BATCH_SIZE);
26
- const batchNum = Math.floor(i / TRANSLATE_BATCH_SIZE) + 1;
27
- const totalBatches = Math.ceil(entries.length / TRANSLATE_BATCH_SIZE);
28
- console.log(`Translating batch ${batchNum}/${totalBatches} (${batch.length} phrase${batch.length === 1 ? '' : 's'})...`);
29
- const batchResults = await (0, translate_1.translateStrings)(batch, targetLanguage, options);
30
- for (const r of batchResults) {
31
- if (typeof r.msgstr === 'string') {
32
- console.log(` ${r.msgid} => ${r.msgstr}`);
33
- }
34
- else {
35
- console.log(` ${r.msgid_plural} (plural) => ${r.msgstr.join(' | ')}`);
36
- }
37
- }
38
- allResults.push(...batchResults);
39
- }
40
- (0, po_1.applyTranslations)(parsedPo, keys, allResults);
41
- node_fs_1.default.writeFileSync(poFilePath, (0, po_1.compilePo)(parsedPo), undefined);
42
- return 0;
43
- }
44
- catch (error) {
45
- const message = error instanceof Error ? error.message : String(error);
46
- console.error(`Failed to process PO file: ${message}`);
47
- return 1;
48
- }
49
- }