msgai-cli 1.1.1 → 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.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,12 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file. See [commit-and-tag-version](https://github.com/absolute-version/commit-and-tag-version) for commit guidelines.
4
4
 
5
+ ## [1.2.0](https://github.com/AlexMost/msgai/compare/v1.1.1...v1.2.0) (2026-03-02)
6
+
7
+ ### Features
8
+
9
+ - add configurable po fold length ([343775c](https://github.com/AlexMost/msgai/commit/343775c8046abf6705ca02d687305d1db1e2c9c6))
10
+
5
11
  ## [1.1.1](https://github.com/AlexMost/msgai/compare/v1.1.0...v1.1.1) (2026-03-01)
6
12
 
7
13
  ### Bug Fixes
package/README.md CHANGED
@@ -79,7 +79,7 @@ msgai messages.po --api-key sk-...
79
79
  Usage:
80
80
 
81
81
  ```bash
82
- msgai <file.po> [--dry-run] [--api-key KEY] [--source-lang LANG] [--model MODEL] [--include-fuzzy] [--debug]
82
+ msgai <file.po> [--dry-run] [--api-key KEY] [--source-lang LANG] [--model MODEL] [--include-fuzzy] [--fold-length N] [--debug]
83
83
  ```
84
84
 
85
85
  Options:
@@ -89,6 +89,7 @@ Options:
89
89
  - `--source-lang LANG`: set the source language of `msgid` strings as an ISO 639-1 code such as `en` or `uk`
90
90
  - `--model MODEL`: set the OpenAI model used for translation; default is `gpt-4o`. Only models with `json_schema` structured outputs are supported.
91
91
  - `--api-key KEY`: pass the OpenAI API key directly instead of using `OPENAI_API_KEY`
92
+ - `--fold-length N`: set PO line fold length when writing files. Use `0` to disable folding and minimize formatting-only diffs. Default: `0`
92
93
  - `--debug`: print debug logs for batch preparation, OpenAI request retries, request payloads, and raw response validation
93
94
  - `--help`: print command usage
94
95
 
@@ -8,11 +8,23 @@ const yargs_1 = __importDefault(require("yargs/yargs"));
8
8
  const helpers_1 = require("yargs/helpers");
9
9
  const debug_1 = require("../debug");
10
10
  const runTranslate_1 = require("./runTranslate");
11
+ function normalizeFoldLength(value) {
12
+ if (value == null) {
13
+ return undefined;
14
+ }
15
+ if (typeof value !== 'number' || !Number.isFinite(value) || !Number.isInteger(value)) {
16
+ throw new Error('Invalid --fold-length. Expected a non-negative integer.');
17
+ }
18
+ if (value < 0) {
19
+ throw new Error('Invalid --fold-length. Expected a non-negative integer.');
20
+ }
21
+ return value;
22
+ }
11
23
  function parseArgs(argv) {
12
24
  try {
13
25
  const parsedArgs = (0, yargs_1.default)(argv)
14
26
  .scriptName('msgai')
15
- .usage('Usage: msgai <file.po> [--dry-run] [--api-key KEY] [--source-lang LANG] [--model MODEL] [--include-fuzzy] [--debug]')
27
+ .usage('Usage: msgai <file.po> [--dry-run] [--api-key KEY] [--source-lang LANG] [--model MODEL] [--include-fuzzy] [--fold-length N] [--debug]')
16
28
  .option('dry-run', {
17
29
  type: 'boolean',
18
30
  default: false,
@@ -33,6 +45,10 @@ function parseArgs(argv) {
33
45
  .option('model', {
34
46
  type: 'string',
35
47
  description: 'OpenAI model to use for translation. Default: gpt-4o',
48
+ })
49
+ .option('fold-length', {
50
+ type: 'number',
51
+ description: 'PO line fold length when writing files. Use 0 to disable folding. Default: 0',
36
52
  })
37
53
  .option('help', {
38
54
  alias: 'h',
@@ -61,6 +77,7 @@ function parseArgs(argv) {
61
77
  : undefined;
62
78
  const modelRaw = parsedArgs.model;
63
79
  const model = modelRaw != null && String(modelRaw).trim() !== '' ? String(modelRaw).trim() : undefined;
80
+ const foldLength = normalizeFoldLength(parsedArgs['fold-length']);
64
81
  if (positionalArgs.length > 1) {
65
82
  const result = {
66
83
  dryRun: Boolean(parsedArgs['dry-run']),
@@ -69,6 +86,7 @@ function parseArgs(argv) {
69
86
  sourceLang,
70
87
  model,
71
88
  includeFuzzy: Boolean(parsedArgs['include-fuzzy']),
89
+ foldLength,
72
90
  debug: Boolean(parsedArgs.debug),
73
91
  error: `Unexpected argument: ${positionalArgs[1]}`,
74
92
  };
@@ -82,6 +100,7 @@ function parseArgs(argv) {
82
100
  sourceLang,
83
101
  model,
84
102
  includeFuzzy: Boolean(parsedArgs['include-fuzzy']),
103
+ foldLength,
85
104
  debug: Boolean(parsedArgs.debug),
86
105
  };
87
106
  return result;
@@ -91,7 +110,7 @@ function parseArgs(argv) {
91
110
  return { dryRun: false, help: false, error: message };
92
111
  }
93
112
  }
94
- const USAGE = 'Usage: msgai <file.po> [--dry-run] [--api-key KEY] [--source-lang LANG] [--model MODEL] [--include-fuzzy] [--debug]';
113
+ const USAGE = 'Usage: msgai <file.po> [--dry-run] [--api-key KEY] [--source-lang LANG] [--model MODEL] [--include-fuzzy] [--fold-length N] [--debug]';
95
114
  function main(argv) {
96
115
  const args = parseArgs(argv);
97
116
  (0, debug_1.initDebugLogger)(args.debug);
@@ -116,6 +135,7 @@ function main(argv) {
116
135
  sourceLang: args.sourceLang,
117
136
  model: args.model,
118
137
  includeFuzzy: args.includeFuzzy,
138
+ foldLength: args.foldLength,
119
139
  debug: args.debug,
120
140
  });
121
141
  if (result instanceof Promise) {
@@ -48,7 +48,7 @@ function getInvalidModelMessage(model) {
48
48
  `Supported model families: ${translate_1.SUPPORTED_STRUCTURED_OUTPUT_MODELS.join(', ')}.`,
49
49
  ].join(' ');
50
50
  }
51
- async function runTranslate(poFilePath, apiKey, sourceLang, model, includeFuzzy, debug) {
51
+ async function runTranslate(poFilePath, apiKey, sourceLang, model, includeFuzzy, foldLength, debug) {
52
52
  (0, debug_1.initDebugLogger)(debug);
53
53
  const debugLogger = (0, debug_1.getDebugLogger)();
54
54
  try {
@@ -117,7 +117,7 @@ async function runTranslate(poFilePath, apiKey, sourceLang, model, includeFuzzy,
117
117
  if (includeFuzzy) {
118
118
  (0, po_1.clearFuzzyFromEntries)(parsedPo, batchResults);
119
119
  }
120
- node_fs_1.default.writeFileSync(poFilePath, (0, po_1.compilePo)(parsedPo));
120
+ node_fs_1.default.writeFileSync(poFilePath, (0, po_1.compilePo)(parsedPo, { foldLength }));
121
121
  debugLogger.log('cli.runTranslate', 'Wrote translated batch back to PO file', {
122
122
  batch: batchNum,
123
123
  poFilePath,
@@ -139,7 +139,7 @@ async function runTranslate(poFilePath, apiKey, sourceLang, model, includeFuzzy,
139
139
  return 1;
140
140
  }
141
141
  }
142
- const USAGE = 'Usage: msgai <file.po> [--dry-run] [--api-key KEY] [--source-lang LANG] [--model MODEL] [--include-fuzzy] [--debug]';
142
+ const USAGE = 'Usage: msgai <file.po> [--dry-run] [--api-key KEY] [--source-lang LANG] [--model MODEL] [--include-fuzzy] [--fold-length N] [--debug]';
143
143
  function runTranslateCommand(args) {
144
144
  (0, debug_1.initDebugLogger)(args.debug);
145
145
  const debugLogger = (0, debug_1.getDebugLogger)();
@@ -190,7 +190,7 @@ function runTranslateCommand(args) {
190
190
  console.warn(message.replace('pass apiKey in options', 'pass --api-key'));
191
191
  return 1;
192
192
  }
193
- return runTranslate(args.poFilePath, resultApiKey, args.sourceLang, args.model, args.includeFuzzy, args.debug);
193
+ return runTranslate(args.poFilePath, resultApiKey, args.sourceLang, args.model, args.includeFuzzy, args.foldLength, args.debug);
194
194
  }
195
195
  try {
196
196
  const poContent = node_fs_1.default.readFileSync(args.poFilePath, 'utf8');
package/dist/src/po.js CHANGED
@@ -10,6 +10,7 @@ exports.applyTranslations = applyTranslations;
10
10
  exports.clearFuzzyFromEntries = clearFuzzyFromEntries;
11
11
  exports.compilePo = compilePo;
12
12
  const gettext_parser_1 = require("gettext-parser");
13
+ const DEFAULT_FOLD_LENGTH = 0;
13
14
  function getUntranslatedMsgids(parsedPo) {
14
15
  const untranslatedMsgids = [];
15
16
  const translations = parsedPo.translations;
@@ -154,6 +155,9 @@ function clearFuzzyFromEntries(parsedPo, results) {
154
155
  /**
155
156
  * Compiles the parsed PO to a buffer (no file I/O).
156
157
  */
157
- function compilePo(parsedPo) {
158
- return gettext_parser_1.po.compile(parsedPo);
158
+ function compilePo(parsedPo, options) {
159
+ return gettext_parser_1.po.compile(parsedPo, {
160
+ foldLength: options?.foldLength ?? DEFAULT_FOLD_LENGTH,
161
+ sort: false,
162
+ });
159
163
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "msgai-cli",
3
- "version": "1.1.1",
3
+ "version": "1.2.0",
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": {