@i18nprune/core 0.1.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.
Files changed (71) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +165 -0
  3. package/dist/adapters-gp1lXp0T.d.ts +12 -0
  4. package/dist/capabilities-x74cD2Hu.d.ts +48 -0
  5. package/dist/cleanup.d.ts +64 -0
  6. package/dist/cleanup.js +3999 -0
  7. package/dist/config.d.ts +201 -0
  8. package/dist/config.js +2865 -0
  9. package/dist/coreContext-DMaWLvmB.d.ts +388 -0
  10. package/dist/fs-BUYD8ZhA.d.ts +20 -0
  11. package/dist/generate.d.ts +487 -0
  12. package/dist/generate.js +9389 -0
  13. package/dist/humanEmit-ygNlYX-S.d.ts +79 -0
  14. package/dist/index-BQuLEQ9b.d.ts +7 -0
  15. package/dist/index-B_ow_Xvr.d.ts +97 -0
  16. package/dist/index-BgG01AKL.d.ts +287 -0
  17. package/dist/index-CIzZl4W8.d.ts +124 -0
  18. package/dist/index-Csm1w7XD.d.ts +58 -0
  19. package/dist/index-DLwTogCo.d.ts +43 -0
  20. package/dist/index-DVT26v11.d.ts +61 -0
  21. package/dist/index-DdjljwMj.d.ts +39 -0
  22. package/dist/index-DeIw-cZd.d.ts +52 -0
  23. package/dist/index-X50E1FIX.d.ts +50 -0
  24. package/dist/index.d.ts +9180 -0
  25. package/dist/index.js +21888 -0
  26. package/dist/init.d.ts +86 -0
  27. package/dist/init.js +848 -0
  28. package/dist/listWindow-XEFxQZi1.d.ts +30 -0
  29. package/dist/localeTargetCodes-BBIQjauw.d.ts +11 -0
  30. package/dist/locales.d.ts +39 -0
  31. package/dist/locales.js +2288 -0
  32. package/dist/missing-BVCvgUC8.d.ts +10 -0
  33. package/dist/missing.d.ts +85 -0
  34. package/dist/missing.js +5892 -0
  35. package/dist/modeResolve-cGVaY5Hh.d.ts +25 -0
  36. package/dist/path-Bfn3SAts.d.ts +11 -0
  37. package/dist/profile-BwOP9WKh.d.ts +9 -0
  38. package/dist/providers-0uMEfT6q.d.ts +82 -0
  39. package/dist/prune-c6hKZCv_.d.ts +33 -0
  40. package/dist/quality.d.ts +36 -0
  41. package/dist/quality.js +3868 -0
  42. package/dist/report-D5-6bVFj.d.ts +8 -0
  43. package/dist/report-schema.d.ts +102 -0
  44. package/dist/report-schema.js +42 -0
  45. package/dist/resumeCandidates-xR13eEwt.d.ts +200 -0
  46. package/dist/root-2-kCaBvQ.d.ts +1110 -0
  47. package/dist/runtime/edge.d.ts +21 -0
  48. package/dist/runtime/edge.js +87 -0
  49. package/dist/runtime/helpers/sync.d.ts +16 -0
  50. package/dist/runtime/helpers/sync.js +117 -0
  51. package/dist/runtime/node.d.ts +24 -0
  52. package/dist/runtime/node.js +204 -0
  53. package/dist/runtime/web.d.ts +21 -0
  54. package/dist/runtime/web.js +84 -0
  55. package/dist/shared.d.ts +1177 -0
  56. package/dist/shared.js +4897 -0
  57. package/dist/sourceContext-1LQg3HiQ.d.ts +36 -0
  58. package/dist/sourceSurface-mDtwGo1E.d.ts +122 -0
  59. package/dist/sync.d.ts +86 -0
  60. package/dist/sync.js +4971 -0
  61. package/dist/syncSegment-Bx6He2Mu.d.ts +149 -0
  62. package/dist/targets-EmtKyr6F.d.ts +23 -0
  63. package/dist/template-CGM-_WLT.d.ts +139 -0
  64. package/dist/translate-CIHYp7wi.d.ts +77 -0
  65. package/dist/types/shared.d.ts +21 -0
  66. package/dist/types/shared.js +1 -0
  67. package/dist/types.d.ts +1345 -0
  68. package/dist/types.js +1 -0
  69. package/dist/validate.d.ts +126 -0
  70. package/dist/validate.js +3717 -0
  71. package/package.json +128 -0
package/dist/shared.js ADDED
@@ -0,0 +1,4897 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __export = (target, all) => {
3
+ for (var name in all)
4
+ __defProp(target, name, { get: all[name], enumerable: true });
5
+ };
6
+
7
+ // src/shared/json/index.ts
8
+ var json_exports = {};
9
+ __export(json_exports, {
10
+ I18nPruneJsonParseError: () => I18nPruneJsonParseError,
11
+ applyPreserveFromSource: () => applyPreserveFromSource,
12
+ deepClone: () => deepClone,
13
+ deleteAtPath: () => deleteAtPath,
14
+ getAtPath: () => getAtPath,
15
+ getJsonParseLocation: () => getJsonParseLocation,
16
+ mergeToTemplateShape: () => mergeToTemplateShape,
17
+ parseJsonText: () => parseJsonText,
18
+ pruneToTemplateShape: () => pruneToTemplateShape,
19
+ setAtPath: () => setAtPath,
20
+ splitPath: () => splitPath,
21
+ targetLocaleCoversAllSourcePaths: () => targetLocaleCoversAllSourcePaths,
22
+ tryParseJsonText: () => tryParseJsonText
23
+ });
24
+
25
+ // src/shared/json/clone.ts
26
+ function deepClone(x) {
27
+ if (x === null || typeof x !== "object") return x;
28
+ if (Array.isArray(x)) return x.map((e) => deepClone(e));
29
+ const o = {};
30
+ for (const k of Object.keys(x)) {
31
+ o[k] = deepClone(x[k]);
32
+ }
33
+ return o;
34
+ }
35
+
36
+ // src/shared/json/path.ts
37
+ function splitPath(pathStr) {
38
+ const parts = [];
39
+ const re = /[^.[\]]+|\[\d+\]/g;
40
+ let m;
41
+ const s = pathStr.trim();
42
+ while ((m = re.exec(s)) !== null) {
43
+ const tok = m[0];
44
+ if (tok.startsWith("[") && tok.endsWith("]")) {
45
+ parts.push(Number.parseInt(tok.slice(1, -1), 10));
46
+ } else {
47
+ parts.push(tok);
48
+ }
49
+ }
50
+ return parts;
51
+ }
52
+ function isPlainObject(x) {
53
+ return typeof x === "object" && x !== null && !Array.isArray(x);
54
+ }
55
+ function getAtPath(root, pathStr) {
56
+ let cur = root;
57
+ for (const seg of splitPath(pathStr)) {
58
+ if (cur === null || cur === void 0) return void 0;
59
+ if (typeof seg === "number") {
60
+ if (!Array.isArray(cur)) return void 0;
61
+ cur = cur[seg];
62
+ } else {
63
+ if (!isPlainObject(cur)) return void 0;
64
+ cur = cur[seg];
65
+ }
66
+ }
67
+ return cur;
68
+ }
69
+ function setAtPath(root, pathStr, value) {
70
+ const segs = splitPath(pathStr);
71
+ if (segs.length === 0) return root;
72
+ const clone = deepClone(root);
73
+ let cur = clone;
74
+ for (let i = 0; i < segs.length - 1; i += 1) {
75
+ const seg = segs[i];
76
+ const next = segs[i + 1];
77
+ if (typeof seg === "number") {
78
+ if (!Array.isArray(cur)) return clone;
79
+ ensureArraySlot(cur, seg, typeof next === "number" ? [] : {});
80
+ cur = cur[seg];
81
+ } else {
82
+ if (!isPlainObject(cur)) return clone;
83
+ if (!(seg in cur)) {
84
+ cur[seg] = typeof next === "number" ? [] : {};
85
+ }
86
+ cur = cur[seg];
87
+ }
88
+ }
89
+ const last = segs[segs.length - 1];
90
+ if (typeof last === "number") {
91
+ if (!Array.isArray(cur)) return clone;
92
+ ensureArraySlot(cur, last, null);
93
+ cur[last] = value;
94
+ } else {
95
+ if (!isPlainObject(cur)) return clone;
96
+ cur[last] = value;
97
+ }
98
+ return clone;
99
+ }
100
+ function ensureArraySlot(arr, index, fill) {
101
+ while (arr.length <= index) {
102
+ arr.push(fill);
103
+ }
104
+ }
105
+ function deleteAtPath(root, pathStr) {
106
+ const segs = splitPath(pathStr);
107
+ if (segs.length === 0) return root;
108
+ const clone = deepClone(root);
109
+ let cur = clone;
110
+ for (let i = 0; i < segs.length - 1; i += 1) {
111
+ const seg = segs[i];
112
+ if (typeof seg === "number") {
113
+ if (!Array.isArray(cur)) return clone;
114
+ cur = cur[seg];
115
+ } else {
116
+ if (!isPlainObject(cur)) return clone;
117
+ cur = cur[seg];
118
+ }
119
+ }
120
+ const last = segs[segs.length - 1];
121
+ if (typeof last === "number") {
122
+ if (Array.isArray(cur)) cur.splice(last, 1);
123
+ } else if (isPlainObject(cur)) {
124
+ delete cur[last];
125
+ }
126
+ return clone;
127
+ }
128
+
129
+ // src/shared/errors/index.ts
130
+ var errors_exports = {};
131
+ __export(errors_exports, {
132
+ I18nPruneError: () => I18nPruneError,
133
+ isErrnoCode: () => isErrnoCode,
134
+ issueFromI18nPruneError: () => issueFromI18nPruneError,
135
+ normalizeUnknownError: () => normalizeUnknownError,
136
+ rethrowAsI18n: () => rethrowAsI18n
137
+ });
138
+
139
+ // src/shared/errors/internal.ts
140
+ var I18nPruneError = class extends Error {
141
+ code;
142
+ issueCode;
143
+ constructor(message, code, options) {
144
+ super(message, options?.cause !== void 0 ? { cause: options.cause } : void 0);
145
+ this.name = "I18nPruneError";
146
+ this.code = code;
147
+ this.issueCode = options?.issueCode;
148
+ }
149
+ };
150
+
151
+ // src/shared/constants/links.ts
152
+ var GITHUB_OWNER = "zamdevio";
153
+ var GITHUB_REPO = "i18nprune";
154
+ var GITHUB_REPO_URL = `https://github.com/${GITHUB_OWNER}/${GITHUB_REPO}`;
155
+ var LICENSE_URL = `${GITHUB_REPO_URL}/blob/main/LICENSE`;
156
+ var DOCS_SITE_BASE = "https://docs.i18nprune.dev";
157
+ var META_WORKER_URL = "https://meta.i18nprune.dev";
158
+ var DEFAULT_WORKER_API_URL = "https://worker.i18nprune.dev";
159
+ var DEMO_REPORT_URL = "https://report.i18nprune.dev";
160
+ var DEMO_WEB_APP_BASE = "https://web.i18nprune.dev";
161
+ var NPM_PACKAGE_NAME = "i18nprune";
162
+ var NPM_PACKAGE_URL = `https://www.npmjs.com/package/${NPM_PACKAGE_NAME}`;
163
+
164
+ // src/shared/constants/docs.ts
165
+ var GITHUB_BASE = GITHUB_REPO_URL;
166
+ var GITHUB_DOCS_BASE = `${GITHUB_BASE}/blob/main/docs`;
167
+ var GITHUB_DOCS_TREE_BASE = `${GITHUB_BASE}/tree/main/docs`;
168
+ var DOCS_SITE_ORIGIN = DOCS_SITE_BASE;
169
+ var DOCS_ISSUES_PAGE_PATH = "/issues";
170
+
171
+ // src/shared/docs/issueAnchors.ts
172
+ var DOC_ISSUE_PARENT_SEGMENTS = /* @__PURE__ */ new Set([
173
+ "cli",
174
+ "cleanup",
175
+ "config",
176
+ "context",
177
+ "doctor",
178
+ "generate",
179
+ "io",
180
+ "languages",
181
+ "locale",
182
+ "locales",
183
+ "missing",
184
+ "patching",
185
+ "paths",
186
+ "project",
187
+ "quality",
188
+ "report",
189
+ "scan",
190
+ "share",
191
+ "sync",
192
+ "translate",
193
+ "validate"
194
+ ]);
195
+ function issueDocHeadingSlug(raw) {
196
+ return raw.toLowerCase().replace(/[.\s_]+/g, "-").replace(/[^a-z0-9-]/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "");
197
+ }
198
+ function splitIssueCode(code) {
199
+ return code.trim().split(".");
200
+ }
201
+ function buildIssueCodeDocLinkParts(code) {
202
+ const trimmed = code.trim();
203
+ const parts = splitIssueCode(trimmed);
204
+ let parent = null;
205
+ if (parts.length >= 3 && parts[0] === "i18nprune") {
206
+ const p = parts[1];
207
+ if (DOC_ISSUE_PARENT_SEGMENTS.has(p)) parent = p;
208
+ }
209
+ let anchor;
210
+ if (parent) {
211
+ anchor = issueDocHeadingSlug(parts.slice(2).join("."));
212
+ } else {
213
+ anchor = issueDocHeadingSlug(trimmed.includes(".") ? trimmed.replace(/\./g, "_") : trimmed);
214
+ }
215
+ const sitePagePath = parent ? `${DOCS_ISSUES_PAGE_PATH}/${parent}` : DOCS_ISSUES_PAGE_PATH;
216
+ const repoDocPath = parent ? `issues/${parent}` : "issues";
217
+ return { parent, anchor, sitePagePath, repoDocPath };
218
+ }
219
+ function resolveIssueCodeDocLink(code) {
220
+ return buildIssueCodeDocLinkParts(code);
221
+ }
222
+ function issueCodeRepoDocPathForIssueCode(code) {
223
+ return buildIssueCodeDocLinkParts(code).repoDocPath;
224
+ }
225
+ function issueCodeDocHref(code) {
226
+ const { sitePagePath, anchor } = buildIssueCodeDocLinkParts(code);
227
+ return `${DOCS_SITE_BASE}${sitePagePath}#${anchor}`;
228
+ }
229
+
230
+ // src/shared/errors/normalize.ts
231
+ function isErrnoCode(error, code) {
232
+ return typeof error === "object" && error !== null && "code" in error && error.code === code;
233
+ }
234
+ function normalizeUnknownError(error, input) {
235
+ if (error instanceof I18nPruneError) return error;
236
+ const extra = input.issueCode !== void 0 ? { issueCode: input.issueCode } : void 0;
237
+ if (error instanceof Error) {
238
+ return new I18nPruneError(`${input.when}: ${error.message}`, input.defaultCode, { cause: error, ...extra });
239
+ }
240
+ return new I18nPruneError(`${input.when}: ${String(error)}`, input.defaultCode, { cause: error, ...extra });
241
+ }
242
+ function issueFromI18nPruneError(error, input) {
243
+ const code = error.issueCode ?? input.codeByErrorCode?.[error.code] ?? input.fallbackCode;
244
+ const base = {
245
+ severity: "error",
246
+ code,
247
+ message: error.message
248
+ };
249
+ const withPath = input.path !== void 0 ? { ...base, path: input.path } : base;
250
+ if (!code.startsWith("i18nprune.")) return withPath;
251
+ return { ...withPath, docPath: issueCodeRepoDocPathForIssueCode(code) };
252
+ }
253
+
254
+ // src/shared/errors/wrap.ts
255
+ function rethrowAsI18n(err, message) {
256
+ if (err instanceof I18nPruneError) throw err;
257
+ throw normalizeUnknownError(err, { when: message, defaultCode: "INTERNAL" });
258
+ }
259
+
260
+ // src/shared/json/parse.ts
261
+ var I18nPruneJsonParseError = class extends I18nPruneError {
262
+ filePath;
263
+ line;
264
+ column;
265
+ offset;
266
+ constructor(input) {
267
+ const options = input.issueCode !== void 0 ? { cause: input.cause, issueCode: input.issueCode } : { cause: input.cause };
268
+ super(input.message, input.code, options);
269
+ this.name = "I18nPruneJsonParseError";
270
+ this.filePath = input.filePath;
271
+ this.line = input.location.line;
272
+ this.column = input.location.column;
273
+ this.offset = input.location.offset;
274
+ }
275
+ };
276
+ function locationFromOffset(text, offset) {
277
+ let line = 1;
278
+ let column = 1;
279
+ const capped = Math.max(0, Math.min(offset, text.length));
280
+ for (let i = 0; i < capped; i += 1) {
281
+ if (text.charCodeAt(i) === 10) {
282
+ line += 1;
283
+ column = 1;
284
+ } else {
285
+ column += 1;
286
+ }
287
+ }
288
+ return { line, column, offset };
289
+ }
290
+ function getJsonParseLocation(error, text) {
291
+ const message = error instanceof Error ? error.message : String(error);
292
+ const positionMatch = /\bposition\s+(\d+)\b/i.exec(message);
293
+ if (positionMatch?.[1]) {
294
+ return locationFromOffset(text, Number.parseInt(positionMatch[1], 10));
295
+ }
296
+ const lineColumnMatch = /\bline\s+(\d+)\s+column\s+(\d+)\b/i.exec(message);
297
+ if (lineColumnMatch?.[1] && lineColumnMatch[2]) {
298
+ return {
299
+ line: Number.parseInt(lineColumnMatch[1], 10),
300
+ column: Number.parseInt(lineColumnMatch[2], 10)
301
+ };
302
+ }
303
+ return {};
304
+ }
305
+ function formatJsonParseMessage(filePath, location, cause) {
306
+ const subject = filePath ? `Invalid JSON in ${filePath}` : "Invalid JSON";
307
+ const at = location.line !== void 0 && location.column !== void 0 ? ` at line ${String(location.line)}, column ${String(location.column)}` : location.offset !== void 0 ? ` at offset ${String(location.offset)}` : "";
308
+ const detail = cause instanceof Error ? cause.message : String(cause);
309
+ return `${subject}${at}: ${detail}`;
310
+ }
311
+ function parseJsonText(text, options = {}) {
312
+ try {
313
+ return JSON.parse(text);
314
+ } catch (cause) {
315
+ const location = getJsonParseLocation(cause, text);
316
+ throw new I18nPruneJsonParseError({
317
+ message: formatJsonParseMessage(options.filePath, location, cause),
318
+ code: options.code ?? "IO",
319
+ cause,
320
+ location,
321
+ ...options.issueCode !== void 0 ? { issueCode: options.issueCode } : {},
322
+ ...options.filePath !== void 0 ? { filePath: options.filePath } : {}
323
+ });
324
+ }
325
+ }
326
+ function tryParseJsonText(text, options = {}) {
327
+ try {
328
+ return { ok: true, data: parseJsonText(text, options) };
329
+ } catch (error) {
330
+ if (error instanceof I18nPruneJsonParseError) return { ok: false, error };
331
+ throw error;
332
+ }
333
+ }
334
+
335
+ // src/shared/locales/leaves/index.ts
336
+ var leaves_exports = {};
337
+ __export(leaves_exports, {
338
+ applyLocaleLeafMode: () => applyLocaleLeafMode,
339
+ applyLocaleLeafNormalization: () => applyLocaleLeafNormalization,
340
+ collectTranslationSurfaceLeaves: () => collectTranslationSurfaceLeaves,
341
+ isCompleteStructuredLocaleLeafMeta: () => isCompleteStructuredLocaleLeafMeta,
342
+ isStructuredLocaleLeafNode: () => isStructuredLocaleLeafNode,
343
+ localeSegmentSourceForFile: () => localeSegmentSourceForFile,
344
+ metadataModeEnabledFromConfig: () => metadataModeEnabledFromConfig,
345
+ resolveLocaleLeafMode: () => resolveLocaleLeafMode
346
+ });
347
+
348
+ // src/shared/json/localeLeafPath.ts
349
+ function isPlainObject2(x) {
350
+ return typeof x === "object" && x !== null && !Array.isArray(x);
351
+ }
352
+ function isLiteralDottedObjectKey(key) {
353
+ return key.includes(".");
354
+ }
355
+ function getLocaleLeafAtPath(root, pathStr) {
356
+ if (isPlainObject2(root) && Object.prototype.hasOwnProperty.call(root, pathStr)) {
357
+ return root[pathStr];
358
+ }
359
+ return getAtPath(root, pathStr);
360
+ }
361
+ function deleteLocaleLeafAtPath(root, pathStr) {
362
+ if (isPlainObject2(root) && Object.prototype.hasOwnProperty.call(root, pathStr)) {
363
+ const clone = deepClone(root);
364
+ delete clone[pathStr];
365
+ return clone;
366
+ }
367
+ return deleteAtPath(root, pathStr);
368
+ }
369
+ function stripLiteralDottedKeysAtLevel(root) {
370
+ if (!isPlainObject2(root)) {
371
+ if (Array.isArray(root)) return root.map((item) => stripLiteralDottedKeysAtLevel(item));
372
+ return root;
373
+ }
374
+ const out = {};
375
+ for (const [key, value] of Object.entries(root)) {
376
+ if (isLiteralDottedObjectKey(key)) continue;
377
+ out[key] = stripLiteralDottedKeysAtLevel(value);
378
+ }
379
+ return out;
380
+ }
381
+ function normalizeLocaleDocumentToNestedCanonical(root, knownLeafPaths) {
382
+ if (Array.isArray(root)) {
383
+ return root.map((item) => normalizeLocaleDocumentToNestedCanonical(item, knownLeafPaths));
384
+ }
385
+ if (!isPlainObject2(root)) return root;
386
+ const preservedNested = {};
387
+ const dottedAssignments = [];
388
+ for (const [key, value] of Object.entries(root)) {
389
+ if (isLiteralDottedObjectKey(key)) {
390
+ dottedAssignments.push({ path: key, value });
391
+ } else {
392
+ preservedNested[key] = normalizeLocaleDocumentToNestedCanonical(value, knownLeafPaths);
393
+ }
394
+ }
395
+ let result = preservedNested;
396
+ for (const { path, value } of dottedAssignments) {
397
+ result = setAtPath(result, path, deepClone(value));
398
+ }
399
+ if (knownLeafPaths) {
400
+ for (const leafPath of knownLeafPaths) {
401
+ if (isLiteralDottedObjectKey(leafPath) && isPlainObject2(result) && Object.prototype.hasOwnProperty.call(result, leafPath)) {
402
+ result = deleteLocaleLeafAtPath(result, leafPath);
403
+ }
404
+ }
405
+ }
406
+ return stripLiteralDottedKeysAtLevel(result);
407
+ }
408
+
409
+ // src/shared/locales/leaves/mode/applyModeHelpers.ts
410
+ function isPlainObjectForLocaleLeaves(x) {
411
+ return typeof x === "object" && x !== null && !Array.isArray(x);
412
+ }
413
+ function bump(m, key) {
414
+ m[key] = (m[key] ?? 0) + 1;
415
+ }
416
+ function initReasonMap() {
417
+ return {
418
+ legacy_string_promoted: 0,
419
+ non_object_replaced: 0,
420
+ missing_value: 0,
421
+ invalid_status: 0,
422
+ invalid_confidence: 0,
423
+ invalid_needs_review: 0,
424
+ invalid_needs_translation_again: 0,
425
+ invalid_source: 0,
426
+ canonical_metadata_materialized: 0
427
+ };
428
+ }
429
+ var MATERIALIZED_STRUCTURED_KEYS = [
430
+ "value",
431
+ "status",
432
+ "confidence",
433
+ "needsReview",
434
+ "source",
435
+ "needsTranslationAgain"
436
+ ];
437
+ function shouldMaterializeCanonicalStructuredFields(cur) {
438
+ for (const k of MATERIALIZED_STRUCTURED_KEYS) {
439
+ if (!(k in cur)) return true;
440
+ }
441
+ return false;
442
+ }
443
+ function classifyLeafRuntimeKind(cur) {
444
+ if (typeof cur === "undefined") return "missing";
445
+ if (typeof cur === "string") return "legacy_string";
446
+ if (!isPlainObjectForLocaleLeaves(cur)) return "other";
447
+ if (typeof cur.value === "string") {
448
+ const validStatus = cur.status === void 0 || typeof cur.status === "string" && cur.status.trim().length > 0;
449
+ const validConfidence = cur.confidence === void 0 || cur.confidence === null || typeof cur.confidence === "number" && Number.isFinite(cur.confidence);
450
+ const validNeedsReview = cur.needsReview === void 0 || typeof cur.needsReview === "boolean";
451
+ const validNeedsTranslationAgain = cur.needsTranslationAgain === void 0 || typeof cur.needsTranslationAgain === "boolean";
452
+ const validSource = cur.source === void 0 || typeof cur.source === "string" && cur.source.trim().length > 0;
453
+ return validStatus && validConfidence && validNeedsReview && validNeedsTranslationAgain && validSource ? "structured_valid" : "structured_corrupt";
454
+ }
455
+ return "structured_corrupt";
456
+ }
457
+ function normalizeStructuredLeaf(cur, sourceValue) {
458
+ const roundConfidence = (v) => Math.round(Math.max(0, Math.min(1, v)) * 100) / 100;
459
+ const reasons = [];
460
+ if (typeof cur === "string") {
461
+ reasons.push("legacy_string_promoted");
462
+ return {
463
+ leaf: {
464
+ value: cur,
465
+ status: "translated",
466
+ confidence: null,
467
+ needsReview: true,
468
+ needsTranslationAgain: false,
469
+ source: "manual"
470
+ },
471
+ changed: true,
472
+ reasons
473
+ };
474
+ }
475
+ if (!isPlainObjectForLocaleLeaves(cur)) {
476
+ reasons.push("non_object_replaced");
477
+ return {
478
+ leaf: {
479
+ value: sourceValue,
480
+ status: "pending",
481
+ confidence: null,
482
+ needsReview: true,
483
+ needsTranslationAgain: true,
484
+ source: "sync"
485
+ },
486
+ changed: true,
487
+ reasons
488
+ };
489
+ }
490
+ let changed = false;
491
+ const out = { value: sourceValue };
492
+ if (typeof cur.value === "string") out.value = cur.value;
493
+ else {
494
+ changed = true;
495
+ reasons.push("missing_value");
496
+ }
497
+ if (typeof cur.status === "string" && cur.status.trim().length > 0) {
498
+ out.status = cur.status;
499
+ } else if (cur.status === void 0) {
500
+ out.status = "translated";
501
+ } else {
502
+ out.status = "translated";
503
+ changed = true;
504
+ reasons.push("invalid_status");
505
+ }
506
+ if (typeof cur.confidence === "number" && Number.isFinite(cur.confidence)) out.confidence = roundConfidence(cur.confidence);
507
+ else if (cur.confidence === null || cur.confidence === void 0) out.confidence = null;
508
+ else {
509
+ out.confidence = null;
510
+ changed = true;
511
+ reasons.push("invalid_confidence");
512
+ }
513
+ if (typeof cur.needsReview === "boolean") {
514
+ out.needsReview = cur.needsReview;
515
+ } else if (cur.needsReview === void 0) {
516
+ out.needsReview = false;
517
+ } else {
518
+ out.needsReview = false;
519
+ changed = true;
520
+ reasons.push("invalid_needs_review");
521
+ }
522
+ if (typeof cur.source === "string" && cur.source.trim().length > 0) {
523
+ out.source = cur.source;
524
+ } else if (cur.source === void 0) {
525
+ out.source = "manual";
526
+ } else {
527
+ out.source = "manual";
528
+ changed = true;
529
+ reasons.push("invalid_source");
530
+ }
531
+ if (typeof cur.needsTranslationAgain === "boolean") out.needsTranslationAgain = cur.needsTranslationAgain;
532
+ else if ("needsTranslationAgain" in cur) {
533
+ out.needsTranslationAgain = false;
534
+ changed = true;
535
+ reasons.push("invalid_needs_translation_again");
536
+ } else {
537
+ out.needsTranslationAgain = false;
538
+ }
539
+ const materialized = isPlainObjectForLocaleLeaves(cur) && typeof cur.value === "string" && shouldMaterializeCanonicalStructuredFields(cur);
540
+ if (materialized && !changed) reasons.push("canonical_metadata_materialized");
541
+ const effectiveChanged = changed || materialized;
542
+ if (changed) {
543
+ out.needsReview = true;
544
+ }
545
+ return { leaf: out, changed: effectiveChanged, reasons };
546
+ }
547
+
548
+ // src/shared/locales/leaves/mode/applyLocaleLeafMode.ts
549
+ function applyLocaleLeafMode(input) {
550
+ const changes = [];
551
+ const leafDecisions = [];
552
+ let next = input.localeJson;
553
+ let unchangedLeaves = 0;
554
+ let structuredLeavesWritten = 0;
555
+ let promotedLegacyLeaves = 0;
556
+ let repairedCorruptLeaves = 0;
557
+ let strippedStructuredLeaves = 0;
558
+ let missingPathsHydratedFromSource = 0;
559
+ const byReason = initReasonMap();
560
+ const sampleLimit = input.sampleLimit ?? 40;
561
+ for (const [leafPath, sourceValue] of input.sourceMap.entries()) {
562
+ const cur = getLocaleLeafAtPath(next, leafPath);
563
+ const beforeKind = classifyLeafRuntimeKind(cur);
564
+ const beforeValue = cur;
565
+ if (input.mode === "legacy_string") {
566
+ const nextValue = typeof cur === "string" ? cur : isPlainObjectForLocaleLeaves(cur) && typeof cur.value === "string" ? cur.value : sourceValue;
567
+ let action2 = "unchanged";
568
+ const reasons = [];
569
+ if (typeof cur === "undefined") {
570
+ missingPathsHydratedFromSource += 1;
571
+ action2 = "hydrated_missing";
572
+ }
573
+ if (isPlainObjectForLocaleLeaves(cur) && typeof cur.value === "string") {
574
+ strippedStructuredLeaves += 1;
575
+ action2 = "stripped_structured";
576
+ }
577
+ if (cur === nextValue) unchangedLeaves += 1;
578
+ else next = setAtPath(next, leafPath, nextValue);
579
+ const afterValue2 = getLocaleLeafAtPath(next, leafPath);
580
+ const afterKind2 = classifyLeafRuntimeKind(afterValue2);
581
+ leafDecisions.push({
582
+ path: leafPath,
583
+ sourceValue,
584
+ beforeKind,
585
+ afterKind: afterKind2,
586
+ action: action2,
587
+ reasons,
588
+ beforeValue,
589
+ afterValue: afterValue2
590
+ });
591
+ continue;
592
+ }
593
+ const normalized = normalizeStructuredLeaf(cur, sourceValue);
594
+ let action = "unchanged";
595
+ if (normalized.changed) {
596
+ next = setAtPath(next, leafPath, normalized.leaf);
597
+ structuredLeavesWritten += 1;
598
+ for (const reason of normalized.reasons) {
599
+ bump(byReason, reason);
600
+ if (changes.length < sampleLimit) changes.push({ path: leafPath, reason });
601
+ }
602
+ const hasLegacy = normalized.reasons.includes("legacy_string_promoted");
603
+ const hasCorruptRepair = normalized.reasons.some(
604
+ (r) => r !== "legacy_string_promoted" && r !== "canonical_metadata_materialized"
605
+ );
606
+ if (hasLegacy) {
607
+ promotedLegacyLeaves += 1;
608
+ action = "promoted_legacy";
609
+ }
610
+ if (hasCorruptRepair) {
611
+ repairedCorruptLeaves += 1;
612
+ if (!hasLegacy) action = "repaired_corrupt";
613
+ }
614
+ } else {
615
+ unchangedLeaves += 1;
616
+ }
617
+ if (typeof cur === "undefined") missingPathsHydratedFromSource += 1;
618
+ const afterValue = getLocaleLeafAtPath(next, leafPath);
619
+ const afterKind = classifyLeafRuntimeKind(afterValue);
620
+ leafDecisions.push({
621
+ path: leafPath,
622
+ sourceValue,
623
+ beforeKind,
624
+ afterKind,
625
+ action,
626
+ reasons: normalized.reasons,
627
+ beforeValue,
628
+ afterValue
629
+ });
630
+ }
631
+ const leafPaths = [...input.sourceMap.keys()];
632
+ next = normalizeLocaleDocumentToNestedCanonical(next, leafPaths);
633
+ return {
634
+ next,
635
+ report: {
636
+ mode: input.mode,
637
+ totalSourceLeafPaths: input.sourceMap.size,
638
+ unchangedLeaves,
639
+ structuredLeavesWritten,
640
+ promotedLegacyLeaves,
641
+ repairedCorruptLeaves,
642
+ strippedStructuredLeaves,
643
+ missingPathsHydratedFromSource,
644
+ byReason,
645
+ changedPathsSample: changes,
646
+ leafDecisions
647
+ }
648
+ };
649
+ }
650
+
651
+ // src/shared/locales/leaves/mode/modeResolve.ts
652
+ function metadataModeEnabledFromConfig(mode) {
653
+ return mode === "structured";
654
+ }
655
+ function resolveLocaleLeafMode(input) {
656
+ if (input.stripMetadataFlag === true) {
657
+ return {
658
+ mode: "legacy_string",
659
+ conflict: input.metadataFlag === true,
660
+ reason: "strip_precedence"
661
+ };
662
+ }
663
+ if (input.metadataFlag === true) return { mode: "structured", conflict: false, reason: "explicit_metadata" };
664
+ if (metadataModeEnabledFromConfig(input.configMode)) {
665
+ return { mode: "structured", conflict: false, reason: "config_structured" };
666
+ }
667
+ return { mode: "legacy_string", conflict: false, reason: "default_legacy" };
668
+ }
669
+ function applyLocaleLeafNormalization(input) {
670
+ const modeDecision = resolveLocaleLeafMode(input.resolveInput);
671
+ const normalized = applyLocaleLeafMode({
672
+ localeJson: input.localeJson,
673
+ sourceMap: input.sourceMap,
674
+ mode: modeDecision.mode
675
+ });
676
+ return {
677
+ next: normalized.next,
678
+ report: normalized.report,
679
+ modeDecision
680
+ };
681
+ }
682
+
683
+ // src/shared/locales/enumerate/parseSegmentLocale.ts
684
+ function localeCodeForSegment(structure, path, segment) {
685
+ if (structure === "locale_file") {
686
+ if (segment.relativePath.includes("/")) return null;
687
+ return path.basename(segment.absolutePath, ".json");
688
+ }
689
+ if (structure === "locale_per_dir") {
690
+ const slash = segment.relativePath.indexOf("/");
691
+ if (slash < 0) return null;
692
+ const locale = segment.relativePath.slice(0, slash);
693
+ return locale.length > 0 ? locale : null;
694
+ }
695
+ if (structure === "feature_bundle") {
696
+ return path.basename(segment.absolutePath, ".json");
697
+ }
698
+ return null;
699
+ }
700
+
701
+ // src/shared/locales/leaves/segmentSource/localeSegmentSourceForFile.ts
702
+ function localeSegmentSourceForFile(input) {
703
+ const { path, absoluteFile, localesDir, structure } = input;
704
+ let relativePath = path.relative(localesDir, absoluteFile);
705
+ if (relativePath.startsWith("..") || path.isAbsolute(relativePath)) {
706
+ relativePath = path.basename(absoluteFile);
707
+ }
708
+ relativePath = relativePath.replace(/\\/g, "/");
709
+ const locale = localeCodeForSegment(structure, path, { absolutePath: absoluteFile, relativePath });
710
+ if (locale === null) return null;
711
+ return { file: absoluteFile, locale, relativePath };
712
+ }
713
+
714
+ // src/shared/locales/leaves/walk/translationSurfaceWalk.ts
715
+ function isPlainObject3(x) {
716
+ return typeof x === "object" && x !== null && !Array.isArray(x);
717
+ }
718
+ function isStructuredLocaleLeafNode(x) {
719
+ return isPlainObject3(x) && typeof x.value === "string";
720
+ }
721
+ function readOptionalStatus(o) {
722
+ const s = o.status;
723
+ if (typeof s !== "string" || !s.trim()) return void 0;
724
+ return s;
725
+ }
726
+ function readOptionalLeafSource(o) {
727
+ const s = o.source;
728
+ if (typeof s !== "string" || !s.trim()) return void 0;
729
+ return s;
730
+ }
731
+ function readConfidence(o) {
732
+ const c = o.confidence;
733
+ if (c === null || c === void 0) return null;
734
+ if (typeof c !== "number" || !Number.isFinite(c)) return null;
735
+ const clamped = Math.max(0, Math.min(1, c));
736
+ return Math.round(clamped * 100) / 100;
737
+ }
738
+ function readNeedsReview(o) {
739
+ if (!("needsReview" in o)) return null;
740
+ return typeof o.needsReview === "boolean" ? o.needsReview : null;
741
+ }
742
+ function readNeedsTranslationAgain(o) {
743
+ if (!("needsTranslationAgain" in o)) return null;
744
+ return typeof o.needsTranslationAgain === "boolean" ? o.needsTranslationAgain : null;
745
+ }
746
+ function isCompleteStructuredLocaleLeafMeta(node) {
747
+ if (!isStructuredLocaleLeafNode(node)) return false;
748
+ const o = node;
749
+ if (typeof o.status !== "string" || !o.status.trim()) return false;
750
+ if (!(o.confidence === null || typeof o.confidence === "number" && Number.isFinite(o.confidence))) return false;
751
+ if (typeof o.needsReview !== "boolean") return false;
752
+ if (typeof o.needsTranslationAgain !== "boolean") return false;
753
+ if (typeof o.source !== "string" || !o.source.trim()) return false;
754
+ return true;
755
+ }
756
+ function pushStructuredRow(out, prefix, root, fileOrigin) {
757
+ out.push({
758
+ path: prefix,
759
+ value: root.value,
760
+ shape: "structured",
761
+ status: readOptionalStatus(root),
762
+ confidence: readConfidence(root),
763
+ needsReview: readNeedsReview(root),
764
+ needsTranslationAgain: readNeedsTranslationAgain(root),
765
+ source: readOptionalLeafSource(root),
766
+ structuredMetaComplete: isCompleteStructuredLocaleLeafMeta(root),
767
+ ...fileOrigin ? { fileOrigin } : {}
768
+ });
769
+ }
770
+ function collectTranslationSurfaceLeaves(root, prefix = "", out = [], fileOrigin) {
771
+ if (typeof root === "string") {
772
+ if (prefix) {
773
+ out.push({
774
+ path: prefix,
775
+ value: root,
776
+ shape: "legacy_string",
777
+ confidence: null,
778
+ needsReview: null,
779
+ ...fileOrigin ? { fileOrigin } : {}
780
+ });
781
+ }
782
+ return out;
783
+ }
784
+ if (isStructuredLocaleLeafNode(root)) {
785
+ if (prefix) pushStructuredRow(out, prefix, root, fileOrigin);
786
+ return out;
787
+ }
788
+ if (Array.isArray(root)) {
789
+ root.forEach((item, i) => {
790
+ const p = prefix ? `${prefix}[${i}]` : `[${i}]`;
791
+ collectTranslationSurfaceLeaves(item, p, out, fileOrigin);
792
+ });
793
+ return out;
794
+ }
795
+ if (isPlainObject3(root)) {
796
+ for (const k of Object.keys(root)) {
797
+ const p = prefix ? `${prefix}.${k}` : k;
798
+ collectTranslationSurfaceLeaves(root[k], p, out, fileOrigin);
799
+ }
800
+ }
801
+ return out;
802
+ }
803
+
804
+ // src/shared/json/targetCoverage.ts
805
+ function targetLocaleCoversAllSourcePaths(sourceRaw, targetRaw) {
806
+ const sLeaves = collectTranslationSurfaceLeaves(sourceRaw);
807
+ return targetLocaleCoversAllSourceLeaves(sLeaves, targetRaw);
808
+ }
809
+ function targetLocaleCoversAllSourceLeaves(sourceLeaves, targetRaw) {
810
+ const tLeaves = collectTranslationSurfaceLeaves(targetRaw);
811
+ const targetSet = new Set(tLeaves.map((l) => l.path));
812
+ return sourceLeaves.every((l) => targetSet.has(l.path));
813
+ }
814
+
815
+ // src/shared/reference/paths.ts
816
+ var paths_exports = {};
817
+ __export(paths_exports, {
818
+ pathUnderAnyUncertainPrefix: () => pathUnderAnyUncertainPrefix,
819
+ pathUnderUncertainPrefix: () => pathUnderUncertainPrefix
820
+ });
821
+ function pathUnderUncertainPrefix(keyPath, prefix) {
822
+ if (keyPath === prefix) return true;
823
+ if (keyPath.startsWith(`${prefix}.`)) return true;
824
+ if (keyPath.startsWith(`${prefix}[`)) return true;
825
+ return false;
826
+ }
827
+ function pathUnderAnyUncertainPrefix(keyPath, prefixes) {
828
+ for (const p of prefixes) {
829
+ if (pathUnderUncertainPrefix(keyPath, p)) return true;
830
+ }
831
+ return false;
832
+ }
833
+
834
+ // src/shared/json/merge.ts
835
+ function isPlainObject4(x) {
836
+ return typeof x === "object" && x !== null && !Array.isArray(x);
837
+ }
838
+ var OMIT = /* @__PURE__ */ Symbol("i18nprune.merge.omit");
839
+ function mergeToTemplateShape(template, target, preserve, options) {
840
+ return mergeWalk(
841
+ template,
842
+ target,
843
+ preserve,
844
+ "",
845
+ options?.uncertainKeepPrefixes,
846
+ options?.skipFillPaths === void 0 ? void 0 : new Set(options.skipFillPaths),
847
+ options?.forceFillPaths === void 0 ? void 0 : new Set(options.forceFillPaths)
848
+ );
849
+ }
850
+ function mergeWalk(template, target, preserve, path, uncertainKeepPrefixes, skipFillPaths, forceFillPaths) {
851
+ if (typeof template === "string") {
852
+ if (skipFillPaths?.has(path)) return OMIT;
853
+ if (forceFillPaths?.has(path)) return template;
854
+ if (typeof target === "string") return target;
855
+ if (isPlainObject4(target) && typeof target.value === "string") {
856
+ return deepClone(target);
857
+ }
858
+ return template;
859
+ }
860
+ if (Array.isArray(template)) {
861
+ if (!Array.isArray(target)) target = [];
862
+ const out = [];
863
+ const tArr = target;
864
+ for (let i = 0; i < template.length; i += 1) {
865
+ const seg = path ? `${path}[${String(i)}]` : `[${String(i)}]`;
866
+ const next = mergeWalk(template[i], tArr[i], preserve, seg, uncertainKeepPrefixes, skipFillPaths, forceFillPaths);
867
+ if (next !== OMIT) out.push(next);
868
+ }
869
+ return out;
870
+ }
871
+ if (isPlainObject4(template)) {
872
+ const tObj = isPlainObject4(target) ? target : {};
873
+ const out = {};
874
+ for (const k of Object.keys(template)) {
875
+ const p = path ? `${path}.${k}` : k;
876
+ const next = mergeWalk(template[k], tObj[k], preserve, p, uncertainKeepPrefixes, skipFillPaths, forceFillPaths);
877
+ if (next !== OMIT) out[k] = next;
878
+ }
879
+ if (uncertainKeepPrefixes?.length) {
880
+ for (const k of Object.keys(tObj)) {
881
+ if (k in template) continue;
882
+ const p = path ? `${path}.${k}` : k;
883
+ if (pathUnderAnyUncertainPrefix(p, uncertainKeepPrefixes)) {
884
+ out[k] = deepClone(tObj[k]);
885
+ }
886
+ }
887
+ }
888
+ return out;
889
+ }
890
+ return deepClone(template);
891
+ }
892
+ function applyPreserveFromSource(target, source, paths) {
893
+ let out = deepClone(target);
894
+ for (const p of paths) {
895
+ const v = getAtPath(source, p);
896
+ if (v !== void 0) {
897
+ out = setAtPath(out, p, deepClone(v));
898
+ }
899
+ }
900
+ return out;
901
+ }
902
+
903
+ // src/shared/json/prune.ts
904
+ function isPlainObject5(x) {
905
+ return typeof x === "object" && x !== null && !Array.isArray(x);
906
+ }
907
+ function pruneToTemplateShape(template, target, options) {
908
+ return pruneWalk(template, target, "", options?.uncertainKeepPrefixes);
909
+ }
910
+ function pruneWalk(template, target, path, uncertainKeepPrefixes) {
911
+ if (template === null || typeof template !== "object") {
912
+ return target;
913
+ }
914
+ if (Array.isArray(template)) {
915
+ if (!Array.isArray(target)) return [];
916
+ const len = Math.min(template.length, target.length);
917
+ const out2 = [];
918
+ for (let i = 0; i < len; i += 1) {
919
+ const seg = path ? `${path}[${String(i)}]` : `[${String(i)}]`;
920
+ out2.push(pruneWalk(template[i], target[i], seg, uncertainKeepPrefixes));
921
+ }
922
+ return out2;
923
+ }
924
+ if (!isPlainObject5(template)) return target;
925
+ if (!isPlainObject5(target)) return {};
926
+ const out = {};
927
+ for (const k of Object.keys(template)) {
928
+ if (k in target) {
929
+ const p = path ? `${path}.${k}` : k;
930
+ out[k] = pruneWalk(template[k], target[k], p, uncertainKeepPrefixes);
931
+ }
932
+ }
933
+ if (uncertainKeepPrefixes?.length) {
934
+ for (const k of Object.keys(target)) {
935
+ if (k in template) continue;
936
+ const p = path ? `${path}.${k}` : k;
937
+ if (pathUnderAnyUncertainPrefix(p, uncertainKeepPrefixes)) {
938
+ out[k] = deepClone(target[k]);
939
+ }
940
+ }
941
+ }
942
+ return out;
943
+ }
944
+
945
+ // src/shared/scanner/index.ts
946
+ var scanner_exports = {};
947
+ __export(scanner_exports, {
948
+ scanSources: () => scanSources
949
+ });
950
+
951
+ // src/runtime/helpers/sync/assert.ts
952
+ function isThenable(value) {
953
+ return typeof value === "object" && value !== null && "then" in value && typeof value.then === "function";
954
+ }
955
+ function assertSyncPortResult(value, label, at) {
956
+ if (isThenable(value)) {
957
+ throw new I18nPruneError(
958
+ `Synchronous ${label} requires a plain value (got a Promise at ${at})`,
959
+ "USAGE"
960
+ );
961
+ }
962
+ return value;
963
+ }
964
+
965
+ // src/runtime/helpers/sync/fs.ts
966
+ function readRuntimeFsTextSync(filePath, fs) {
967
+ return assertSyncPortResult(fs.readText(filePath), "fs.readText", filePath);
968
+ }
969
+ function existsRuntimeFsSync(filePath, fs) {
970
+ return assertSyncPortResult(fs.exists(filePath), "fs.exists", filePath);
971
+ }
972
+ function listRuntimeFsDirSync(dirPath, fs) {
973
+ return assertSyncPortResult(fs.listDir(dirPath), "fs.listDir", dirPath);
974
+ }
975
+
976
+ // src/shared/constants/issueCodes.ts
977
+ var ISSUE_CONTEXT_DISCOVERY_WARNING = "i18nprune.context.discovery_warning";
978
+ var ISSUE_CONTEXT_RESOLUTION_FAILED = "i18nprune.context.resolution_failed";
979
+ var ISSUE_VALIDATE_MISSING_LITERAL_KEYS = "i18nprune.validate.missing_literal_keys";
980
+ var ISSUE_VALIDATE_DYNAMIC_KEY_SITES = "i18nprune.validate.dynamic_key_sites";
981
+ var ISSUE_VALIDATE_SOURCE_LOCALE_READ_FAILED = "i18nprune.validate.source_locale_unreadable";
982
+ var ISSUE_PROJECT_CONFIG_FILE_MISSING = "i18nprune.project.config_file_missing";
983
+ var ISSUE_PROJECT_SOURCE_LOCALE_UNAVAILABLE = "i18nprune.project.source_locale_unavailable";
984
+ var ISSUE_PROJECT_LOCALES_DIR_UNAVAILABLE = "i18nprune.project.locales_dir_unavailable";
985
+ var ISSUE_PROJECT_SRC_ROOT_UNAVAILABLE = "i18nprune.project.src_root_unavailable";
986
+ var ISSUE_PROJECT_LOCALES_STRUCTURE_REQUIRED = "i18nprune.project.locales_structure_required";
987
+ var ISSUE_PROJECT_LOCALES_SOURCE_NOT_LANGUAGE_CODE = "i18nprune.project.locales_source_not_language_code";
988
+ var ISSUE_PROJECT_LOCALES_SOURCE_NOT_IN_BUNDLE = "i18nprune.project.locales_source_not_in_bundle";
989
+ var ISSUE_PROJECT_SOURCE_LOCALE_MISSING_SEGMENTS = "i18nprune.project.source_locale_missing_segments";
990
+ var ISSUE_SCAN_DYNAMIC_KEY_SITES = "i18nprune.scan.dynamic_key_sites";
991
+ var ISSUE_MISSING_PATHS_NOT_IN_SCAN = "i18nprune.missing.paths_not_in_current_scan";
992
+ var ISSUE_SYNC_LOCALE_FILE_NOT_FOUND = "i18nprune.sync.locale_file_not_found";
993
+ var ISSUE_SYNC_METADATA_FLAG_CONFLICT = "i18nprune.sync.metadata_flag_conflict";
994
+ var ISSUE_LOCALE_SOURCE_PLACEHOLDER_LEAVES = "i18nprune.locale.source_placeholder_leaves";
995
+ var ISSUE_LOCALE_TARGET_PLACEHOLDER_LEAVES = "i18nprune.locale.target_placeholder_leaves";
996
+ var ISSUE_CLEANUP_UNCERTAIN_PATHS_EXCLUDED = "i18nprune.cleanup.uncertain_paths_excluded";
997
+ var ISSUE_CLEANUP_RIPGREP_UNAVAILABLE = "i18nprune.cleanup.ripgrep_unavailable";
998
+ var ISSUE_QUALITY_ENGLISH_IDENTICAL_LEAVES = "i18nprune.quality.english_identical_leaves";
999
+ var ISSUE_LANGUAGES_EMPTY_FILTER = "i18nprune.languages.empty_filter";
1000
+ var ISSUE_LANGUAGES_UNSUPPORTED_LANGUAGE_CODE = "i18nprune.languages.unsupported_language_code";
1001
+ var ISSUE_CONFIG_MISSING = "i18nprune.config.missing";
1002
+ var ISSUE_CONFIG_INVALID = "i18nprune.config.invalid";
1003
+ var ISSUE_CONFIG_LOAD_FAILED = "i18nprune.config.load_failed";
1004
+ var ISSUE_LOCALES_USAGE = "i18nprune.locales.usage";
1005
+ var ISSUE_LOCALE_TARGET_NOT_FOUND = "i18nprune.locale.target_not_found";
1006
+ var ISSUE_IO_READ_FAILED = "i18nprune.io.read_failed";
1007
+ var ISSUE_TRANSLATE_IDENTITY_STREAK_WARNING = "i18nprune.translate.identity_streak_warning";
1008
+ var ISSUE_TRANSLATE_IDENTITY_STREAK_ABORT = "i18nprune.translate.identity_streak_abort";
1009
+ var ISSUE_TRANSLATE_UNKNOWN_TRANSLATION_PROVIDER = "i18nprune.translate.unknown_translation_provider";
1010
+ var ISSUE_TRANSLATE_PROVIDER_NOT_IMPLEMENTED_YET = "i18nprune.translate.provider_not_implemented_yet";
1011
+ var ISSUE_TRANSLATE_MISSING_CREDENTIALS = "i18nprune.translate.missing_credentials";
1012
+ var ISSUE_TRANSLATE_CONFIG_DEFAULT_APPLIED = "i18nprune.translate.config_default_applied";
1013
+ var ISSUE_TRANSLATE_HANDOFF_NO_ELIGIBLE_PROVIDER = "i18nprune.translate.handoff_no_eligible_provider";
1014
+ var ISSUE_GENERATE_USAGE = "i18nprune.generate.usage";
1015
+ var ISSUE_GENERATE_SOURCE_EMPTY_STRING_LEAVES = "i18nprune.generate.source_empty_string_leaves";
1016
+ var ISSUE_GENERATE_TRANSLATE_RATE_LIMITED = "i18nprune.generate.translate_rate_limited";
1017
+ var ISSUE_GENERATE_TRANSLATE_NETWORK_ERROR = "i18nprune.generate.translate_network_error";
1018
+ var ISSUE_REPORT_INVALID_FORMAT = "i18nprune.report.invalid_format";
1019
+ var ISSUE_CLI_INVALID_JSON_PRETTY = "i18nprune.cli.invalid_json_pretty";
1020
+ var ISSUE_SHARE_JSON_REPAIRED = "i18nprune.share.json_repaired";
1021
+ var ISSUE_SHARE_CACHE_ENTRY_NOT_FOUND = "i18nprune.share.cache_entry_not_found";
1022
+ var ISSUE_SHARE_STALE_CACHE_ROW_REMOVED = "i18nprune.share.stale_cache_row_removed";
1023
+ var ISSUE_SHARE_CACHE_EMPTY = "i18nprune.share.cache_empty";
1024
+ var ISSUE_SHARE_JSON_WRITE_FAILED = "i18nprune.share.json_write_failed";
1025
+ var ISSUE_SHARE_REMOTE_PROJECT_NOT_FOUND = "i18nprune.share.remote_project_not_found";
1026
+ var ISSUE_SHARE_REMOTE_REPORT_NOT_FOUND = "i18nprune.share.remote_report_not_found";
1027
+ var ISSUE_SHARE_REMOTE_PAYLOAD_TOO_LARGE = "i18nprune.share.remote_payload_too_large";
1028
+ var ISSUE_SHARE_REMOTE_REPORT_REJECTED = "i18nprune.share.remote_report_rejected";
1029
+ var ISSUE_SHARE_REMOTE_UPLOAD_REJECTED = "i18nprune.share.remote_upload_rejected";
1030
+ var ISSUE_SHARE_REMOTE_UNAVAILABLE = "i18nprune.share.remote_unavailable";
1031
+ var ISSUE_SHARE_REMOTE_ERROR = "i18nprune.share.remote_error";
1032
+ var ISSUE_SHARE_SNAPSHOT_EMPTY = "i18nprune.share.snapshot_empty";
1033
+ var ISSUE_SHARE_ZIP_FAILED = "i18nprune.share.zip_failed";
1034
+ var ISSUE_PATCHING_CONFIG_SIZE_ANOMALY = "i18nprune.patching.config_size_anomaly";
1035
+ var ISSUE_PATCHING_CONFIG_TOO_LARGE = "i18nprune.patching.config_too_large";
1036
+ var ISSUE_PATCHING_CONFIG_INVALID_SCHEMA = "i18nprune.patching.config_invalid_schema";
1037
+ var ISSUE_PATCHING_CONFIG_PARSE_FAILED = "i18nprune.patching.config_parse_failed";
1038
+ var ISSUE_PATCHING_CONFIG_LOCALE_MISSING_FILE = "i18nprune.patching.config_locale_missing_file";
1039
+ var ISSUE_PATCHING_FILE_LOCALE_MISSING_CONFIG = "i18nprune.patching.file_locale_missing_config";
1040
+ var ISSUE_PATCHING_CATALOG_MISMATCH_ENGLISH = "i18nprune.patching.catalog_mismatch_english_name";
1041
+ var ISSUE_PATCHING_CATALOG_MISMATCH_NATIVE = "i18nprune.patching.catalog_mismatch_native_name";
1042
+ var ISSUE_PATCHING_CATALOG_MISMATCH_DIRECTION = "i18nprune.patching.catalog_mismatch_direction";
1043
+ var ISSUE_PATCHING_CONFIG_SECTION_INCOMPLETE = "i18nprune.patching.config_section_incomplete";
1044
+ var ISSUE_DOCTOR_RUNTIME_UNSUPPORTED_NODE = "i18nprune.doctor.runtime_unsupported_node";
1045
+ var ISSUE_DOCTOR_TOOLS_RG_NOT_ON_PATH = "i18nprune.doctor.tools_rg_not_on_path";
1046
+ var ISSUE_DOCTOR_CONFIG_MISSING_FILE = "i18nprune.doctor.config_missing_file";
1047
+ var ISSUE_DOCTOR_PATHS_SOURCE_LOCALE_MISSING = "i18nprune.doctor.paths_source_locale_missing";
1048
+ var ISSUE_DOCTOR_PATHS_DIRECTORIES_MISSING = "i18nprune.doctor.paths_directories_missing";
1049
+ var ISSUE_PATHS_WINDOWS_RESERVED_NAME = "i18nprune.paths.windows_reserved_name";
1050
+ var ISSUE_PATHS_WINDOWS_LONG_PATH = "i18nprune.paths.windows_long_path";
1051
+ var ISSUE_PATHS_NETWORK_DRIVE = "i18nprune.paths.network_drive";
1052
+ var ISSUE_PROJECT_HOSTED_SNAPSHOT_INVALID = "i18nprune.project.hosted_snapshot_invalid";
1053
+ var ISSUE_PROJECT_HOSTED_SNAPSHOT_SCHEMA_VERSION = "i18nprune.project.hosted_snapshot_schema_version";
1054
+ var ISSUE_PROJECT_UPLOAD_CONFIG_JSON_INVALID = "i18nprune.project.upload_config_json_invalid";
1055
+ var ISSUE_PROJECT_UPLOAD_CONFIG_REQUIRED = "i18nprune.project.upload_config_required";
1056
+ var ISSUE_PROJECT_SOURCE_LOCALE_NOT_FOUND = "i18nprune.project.source_locale_not_found";
1057
+ var ISSUE_PROJECT_SOURCE_LOCALE_INVALID_JSON = "i18nprune.project.source_locale_invalid_json";
1058
+ var ISSUE_PROJECT_SOURCE_LOCALE_INVALID_SHAPE = "i18nprune.project.source_locale_invalid_shape";
1059
+ var ISSUE_REPORT_HOSTED_REPORT_INVALID = "i18nprune.report.hosted_report_invalid";
1060
+ var ISSUE_SHARE_PREPARE_NOTHING_REQUESTED = "i18nprune.share.prepare_nothing_requested";
1061
+ var ISSUE_SHARE_PREPARE_REPORT_HOST_REQUIRED = "i18nprune.share.prepare_report_host_required";
1062
+ var ISSUE_SHARE_PREPARE_ANALYSIS_FAILED = "i18nprune.share.prepare_analysis_failed";
1063
+ var ISSUE_SHARE_PREPARE_REPORT_FROM_ARCHIVE_FAILED = "i18nprune.share.prepare_report_from_archive_failed";
1064
+
1065
+ // src/shared/options/runOptions.ts
1066
+ var run = {
1067
+ json: false,
1068
+ jsonPretty: true,
1069
+ quiet: false,
1070
+ silent: false,
1071
+ debugScan: false,
1072
+ debugCache: false,
1073
+ onScanDebug: void 0
1074
+ };
1075
+ function resetRunOptions() {
1076
+ run = {
1077
+ json: false,
1078
+ jsonPretty: true,
1079
+ quiet: false,
1080
+ silent: false,
1081
+ debugScan: false,
1082
+ debugCache: false,
1083
+ onScanDebug: void 0
1084
+ };
1085
+ }
1086
+ function setRunOptions(partial) {
1087
+ run = { ...run, ...partial };
1088
+ }
1089
+ function getRunOptions() {
1090
+ return run;
1091
+ }
1092
+
1093
+ // src/shared/scanner/presets.ts
1094
+ var SCAN_EXCLUDE_PRESETS = {
1095
+ production: {
1096
+ dirs: ["node_modules", "dist", "build", "compiled", "tests", "bench"],
1097
+ files: ["pnpm-lock.yaml", "package-lock.json", "yarn.lock"],
1098
+ extensions: ["test.ts", "test.tsx", "spec.ts", "spec.tsx", "test.js", "test.jsx", "spec.js", "spec.jsx"]
1099
+ }
1100
+ };
1101
+ function mergeExcludeRules(base, extra) {
1102
+ if (!base && !extra) return void 0;
1103
+ return {
1104
+ useDefaultSkip: base?.useDefaultSkip ?? extra?.useDefaultSkip,
1105
+ dirs: [...extra?.dirs ?? [], ...base?.dirs ?? []],
1106
+ files: [...extra?.files ?? [], ...base?.files ?? []],
1107
+ extensions: [...extra?.extensions ?? [], ...base?.extensions ?? []],
1108
+ patterns: [...extra?.patterns ?? [], ...base?.patterns ?? []]
1109
+ };
1110
+ }
1111
+ function resolveScanExcludeConfig(exclude) {
1112
+ if (!exclude) return void 0;
1113
+ const fromPreset = exclude.preset ? SCAN_EXCLUDE_PRESETS[exclude.preset] : void 0;
1114
+ return mergeExcludeRules(exclude, fromPreset);
1115
+ }
1116
+
1117
+ // src/shared/scanner/files.ts
1118
+ function resolveScanDebugSink(listOpts) {
1119
+ const g = getRunOptions();
1120
+ if (g.silent) return void 0;
1121
+ return listOpts?.onScanDebug ?? g.onScanDebug;
1122
+ }
1123
+ function emitScanDebug(sink, event) {
1124
+ if (sink) sink(event);
1125
+ }
1126
+ var DEFAULT_SCAN_SKIP_DIR_NAMES = [
1127
+ "node_modules",
1128
+ "dist",
1129
+ "build",
1130
+ ".git",
1131
+ "coverage",
1132
+ ".next",
1133
+ "out"
1134
+ ];
1135
+ var DEFAULT_SCAN_SKIP_DIR_SET = new Set(DEFAULT_SCAN_SKIP_DIR_NAMES);
1136
+ var SOURCE_FILE_NAME = /\.(tsx?|jsx?|mjs|cjs|vue|svelte)$/i;
1137
+ var MAX_SOURCE_TREE_WALK_DEPTH = 48;
1138
+ function walkDirectoryKey(dir, pathPort, fs) {
1139
+ if (fs.realpath) {
1140
+ try {
1141
+ return fs.realpath(dir);
1142
+ } catch {
1143
+ return pathPort.resolve(dir);
1144
+ }
1145
+ }
1146
+ return pathPort.resolve(dir);
1147
+ }
1148
+ function normExtToken(s) {
1149
+ const t = s.trim().toLowerCase();
1150
+ return t.startsWith(".") ? t.slice(1) : t;
1151
+ }
1152
+ function basenameExtensionSuffixes(fileBase) {
1153
+ const parts = fileBase.split(".");
1154
+ if (parts.length < 2) return [];
1155
+ const out = [];
1156
+ for (let i = 1; i < parts.length; i++) {
1157
+ out.push(parts.slice(i).join(".").toLowerCase());
1158
+ }
1159
+ out.sort((a, b) => b.length - a.length);
1160
+ return out;
1161
+ }
1162
+ function relPosix(pathPort, rootDir, absPath) {
1163
+ return pathPort.relative(rootDir, absPath).replace(/\\/g, "/");
1164
+ }
1165
+ function partitionRules(rules) {
1166
+ const strings = /* @__PURE__ */ new Set();
1167
+ const regexes = [];
1168
+ if (!rules) return { strings, regexes };
1169
+ for (const r of rules) {
1170
+ if (typeof r === "string") {
1171
+ const t = r.trim();
1172
+ if (t) strings.add(t);
1173
+ } else {
1174
+ regexes.push(r);
1175
+ }
1176
+ }
1177
+ return { strings, regexes };
1178
+ }
1179
+ function partitionExtRules(rules) {
1180
+ const strings = /* @__PURE__ */ new Set();
1181
+ const regexes = [];
1182
+ if (!rules) return { strings, regexes };
1183
+ for (const r of rules) {
1184
+ if (typeof r === "string") {
1185
+ const n = normExtToken(r);
1186
+ if (n) strings.add(n);
1187
+ } else {
1188
+ regexes.push(r);
1189
+ }
1190
+ }
1191
+ return { strings, regexes };
1192
+ }
1193
+ function compileScanExclude(exclude) {
1194
+ const resolved = resolveScanExcludeConfig(exclude);
1195
+ const useDefault = resolved?.useDefaultSkip !== false;
1196
+ const defaultDirs = useDefault ? DEFAULT_SCAN_SKIP_DIR_SET : null;
1197
+ const dirs = partitionRules(resolved?.dirs);
1198
+ const files = partitionRules(resolved?.files);
1199
+ const exts = partitionExtRules(resolved?.extensions);
1200
+ const pathPatterns = resolved?.patterns ?? [];
1201
+ const userRulesEmpty = dirs.strings.size === 0 && dirs.regexes.length === 0 && files.strings.size === 0 && files.regexes.length === 0 && exts.strings.size === 0 && exts.regexes.length === 0 && pathPatterns.length === 0;
1202
+ return {
1203
+ defaultDirs,
1204
+ dirStrings: dirs.strings,
1205
+ dirRegexes: dirs.regexes,
1206
+ fileStrings: files.strings,
1207
+ fileRegexes: files.regexes,
1208
+ extStrings: exts.strings,
1209
+ extRegexes: exts.regexes,
1210
+ pathPatterns,
1211
+ userRulesEmpty
1212
+ };
1213
+ }
1214
+ function explainDirSkip(name, c) {
1215
+ if (c.defaultDirs?.has(name)) return `built-in directory skip (${name})`;
1216
+ if (c.userRulesEmpty) return null;
1217
+ if (c.dirStrings.has(name)) return `exclude.dirs (${name})`;
1218
+ for (const re of c.dirRegexes) {
1219
+ if (re.test(name)) return `exclude.dirs regex /${re.source}/`;
1220
+ }
1221
+ return null;
1222
+ }
1223
+ function explainFileSkip(relPosix2, baseName, c) {
1224
+ if (c.userRulesEmpty) return null;
1225
+ if (c.fileStrings.has(baseName)) return `exclude.files (${baseName})`;
1226
+ for (const re of c.fileRegexes) {
1227
+ if (re.test(baseName)) return `exclude.files regex /${re.source}/`;
1228
+ }
1229
+ if (c.extStrings.size > 0 || c.extRegexes.length > 0) {
1230
+ for (const suf of basenameExtensionSuffixes(baseName)) {
1231
+ if (c.extStrings.has(suf)) return `exclude.extensions (${suf})`;
1232
+ for (const re of c.extRegexes) {
1233
+ if (re.test(suf)) return `exclude.extensions regex /${re.source}/`;
1234
+ }
1235
+ }
1236
+ }
1237
+ for (const re of c.pathPatterns) {
1238
+ if (re.test(relPosix2)) return `exclude.patterns /${re.source}/ \u2190 ${relPosix2}`;
1239
+ }
1240
+ return null;
1241
+ }
1242
+ function listSourceFiles(runtime, rootDir, exclude, listOpts) {
1243
+ const { fs, path } = runtime;
1244
+ const compiled = compileScanExclude(exclude);
1245
+ const out = [];
1246
+ const debugSink = resolveScanDebugSink(listOpts);
1247
+ const visitedDirs = /* @__PURE__ */ new Set();
1248
+ function walk(dir, depth) {
1249
+ if (!existsRuntimeFsSync(dir, fs)) return;
1250
+ const dirKey = walkDirectoryKey(dir, path, fs);
1251
+ if (visitedDirs.has(dirKey)) {
1252
+ emitScanDebug(debugSink, {
1253
+ kind: "skip_directory",
1254
+ relativePath: relPosix(path, rootDir, dir),
1255
+ basename: path.basename(dir),
1256
+ reason: "directory already visited (symlink cycle or duplicate path)"
1257
+ });
1258
+ return;
1259
+ }
1260
+ visitedDirs.add(dirKey);
1261
+ if (depth > MAX_SOURCE_TREE_WALK_DEPTH) {
1262
+ emitScanDebug(debugSink, {
1263
+ kind: "skip_directory",
1264
+ relativePath: relPosix(path, rootDir, dir),
1265
+ basename: path.basename(dir),
1266
+ reason: `scan depth limit (${String(MAX_SOURCE_TREE_WALK_DEPTH)})`
1267
+ });
1268
+ return;
1269
+ }
1270
+ const entries = listRuntimeFsDirSync(dir, fs);
1271
+ for (const e of entries) {
1272
+ const p = path.join(dir, e.name);
1273
+ if (e.kind === "directory") {
1274
+ const why = explainDirSkip(e.name, compiled);
1275
+ if (why) {
1276
+ emitScanDebug(debugSink, {
1277
+ kind: "skip_directory",
1278
+ relativePath: relPosix(path, rootDir, p),
1279
+ basename: e.name,
1280
+ reason: why
1281
+ });
1282
+ continue;
1283
+ }
1284
+ walk(p, depth + 1);
1285
+ } else if (e.kind === "file") {
1286
+ const rel = relPosix(path, rootDir, p);
1287
+ if (!SOURCE_FILE_NAME.test(e.name)) {
1288
+ emitScanDebug(debugSink, {
1289
+ kind: "skip_file",
1290
+ relativePath: rel,
1291
+ basename: e.name,
1292
+ reason: `not a scanned source extension (${e.name})`
1293
+ });
1294
+ continue;
1295
+ }
1296
+ const whyF = explainFileSkip(rel, e.name, compiled);
1297
+ if (whyF) {
1298
+ emitScanDebug(debugSink, {
1299
+ kind: "skip_file",
1300
+ relativePath: rel,
1301
+ basename: e.name,
1302
+ reason: whyF
1303
+ });
1304
+ continue;
1305
+ }
1306
+ out.push(p);
1307
+ } else if (e.kind === "other") {
1308
+ emitScanDebug(debugSink, {
1309
+ kind: "skip_file",
1310
+ relativePath: relPosix(path, rootDir, p),
1311
+ basename: e.name,
1312
+ reason: "not a regular file or directory (symlink or special entry)"
1313
+ });
1314
+ }
1315
+ }
1316
+ }
1317
+ walk(rootDir, 0);
1318
+ return out;
1319
+ }
1320
+
1321
+ // src/shared/scanner/index.ts
1322
+ function scanSources(runtime, srcRoot, exclude, scanOpts) {
1323
+ const files = listSourceFiles(runtime, srcRoot, exclude, scanOpts);
1324
+ const parts = [];
1325
+ for (const f of files) {
1326
+ try {
1327
+ parts.push(readRuntimeFsTextSync(f, runtime.fs));
1328
+ } catch {
1329
+ }
1330
+ }
1331
+ return { files, text: parts.join("\n") };
1332
+ }
1333
+
1334
+ // src/shared/placeholders/index.ts
1335
+ var placeholders_exports = {};
1336
+ __export(placeholders_exports, {
1337
+ mask: () => mask,
1338
+ restore: () => restore,
1339
+ validateRestored: () => validateRestored
1340
+ });
1341
+ var SENTINEL_RE = /__I18NPRUNE_(\d+)__/g;
1342
+ function mask(input) {
1343
+ const originals = [];
1344
+ const text = input.replace(/\{\{([^}]+)\}\}/g, (_, inner) => {
1345
+ const i = originals.length;
1346
+ originals.push(inner.trim());
1347
+ return `__I18NPRUNE_${i}__`;
1348
+ });
1349
+ return { text, originals };
1350
+ }
1351
+ function restore(masked, originals) {
1352
+ return masked.replace(SENTINEL_RE, (_, idx) => {
1353
+ const i = Number.parseInt(idx, 10);
1354
+ const o = originals[i];
1355
+ return o !== void 0 ? `{{${o}}}` : _;
1356
+ });
1357
+ }
1358
+ function validateRestored(source, restored, originals) {
1359
+ if (/__I18NPRUNE_\d+__/.test(restored)) {
1360
+ throw new Error("Translation output still contains placeholder sentinels");
1361
+ }
1362
+ const srcMatches = [...source.matchAll(/\{\{([^}]+)\}\}/g)].map((m) => m[1].trim());
1363
+ if (srcMatches.length !== originals.length) {
1364
+ throw new Error("Placeholder count mismatch after translation");
1365
+ }
1366
+ }
1367
+
1368
+ // src/shared/translator/index.ts
1369
+ var translator_exports = {};
1370
+ __export(translator_exports, {
1371
+ localeJsonValueFromTranslation: () => localeJsonValueFromTranslation,
1372
+ translateLeaf: () => translateLeaf,
1373
+ validateLeafTranslationString: () => validateLeafTranslationString
1374
+ });
1375
+
1376
+ // src/shared/translator/utils/metadata.ts
1377
+ function buildHeuristicLeafMeta(input) {
1378
+ const src = input.sourceText.trim();
1379
+ const tgt = input.translatedText.trim();
1380
+ const tag = `${input.providerId}-heuristic`;
1381
+ if (src.length === 0) {
1382
+ return {
1383
+ status: "translated",
1384
+ confidence: null,
1385
+ needsReview: true,
1386
+ source: tag,
1387
+ needsTranslationAgain: true
1388
+ };
1389
+ }
1390
+ if (src === tgt) {
1391
+ return {
1392
+ status: "translated",
1393
+ confidence: null,
1394
+ needsReview: true,
1395
+ source: tag,
1396
+ needsTranslationAgain: true
1397
+ };
1398
+ }
1399
+ const ratio = tgt.length / src.length;
1400
+ const drift = Math.abs(1 - Math.min(ratio, 2));
1401
+ const confidence = Math.max(0.35, Math.min(0.88, 0.62 + (1 - drift) * 0.25));
1402
+ return {
1403
+ status: "translated",
1404
+ confidence,
1405
+ needsReview: confidence < 0.52,
1406
+ source: tag,
1407
+ needsTranslationAgain: false
1408
+ };
1409
+ }
1410
+
1411
+ // src/shared/translator/utils/pipeline.ts
1412
+ function unpackProviderTranslation(raw) {
1413
+ if (typeof raw === "string") return { text: raw, patch: {} };
1414
+ return { text: raw.text, patch: raw.leafMeta ?? {} };
1415
+ }
1416
+ function mergeTranslationLeafMeta(heuristic, provider) {
1417
+ return {
1418
+ status: provider.status ?? heuristic.status,
1419
+ confidence: "confidence" in provider ? provider.confidence ?? null : heuristic.confidence,
1420
+ needsReview: "needsReview" in provider ? provider.needsReview : heuristic.needsReview,
1421
+ needsTranslationAgain: "needsTranslationAgain" in provider ? provider.needsTranslationAgain : heuristic.needsTranslationAgain,
1422
+ source: provider.source ?? heuristic.source
1423
+ };
1424
+ }
1425
+ function finalizeTranslationLeafMeta(patch, decision) {
1426
+ const roundConfidence = (v) => {
1427
+ if (v === null || v === void 0) return null;
1428
+ if (!Number.isFinite(v)) return null;
1429
+ const clamped = Math.max(0, Math.min(1, v));
1430
+ return Math.round(clamped * 100) / 100;
1431
+ };
1432
+ return {
1433
+ status: patch.status ?? "translated",
1434
+ confidence: roundConfidence(patch.confidence),
1435
+ needsReview: decision === "review" ? true : patch.needsReview ?? false,
1436
+ needsTranslationAgain: patch.needsTranslationAgain ?? false,
1437
+ source: patch.source ?? "manual"
1438
+ };
1439
+ }
1440
+ function localeJsonValueFromTranslation(persistStructuredMetadata, tr) {
1441
+ if (!persistStructuredMetadata) return tr.text;
1442
+ return {
1443
+ value: tr.text,
1444
+ status: tr.leafMeta.status,
1445
+ confidence: tr.leafMeta.confidence,
1446
+ needsReview: tr.leafMeta.needsReview,
1447
+ needsTranslationAgain: tr.leafMeta.needsTranslationAgain,
1448
+ source: tr.leafMeta.source
1449
+ };
1450
+ }
1451
+ function validateLeafTranslationString(value, context) {
1452
+ if (typeof value !== "string") {
1453
+ throw new I18nPruneError(
1454
+ `Translator returned non-string${context ? ` (${context})` : ""}`,
1455
+ "INTERNAL"
1456
+ );
1457
+ }
1458
+ return value;
1459
+ }
1460
+
1461
+ // src/translator/policy/classify.ts
1462
+ function classifyTranslateFailure(err) {
1463
+ const msg = err instanceof Error ? err.message : String(err);
1464
+ if (/\b429\b/.test(msg) || /\btoo many requests\b/i.test(msg)) {
1465
+ if (/MYMEMORY WARNING:\s*YOU USED ALL AVAILABLE FREE TRANSLATIONS FOR TODAY/i.test(msg)) {
1466
+ return "quota_exceeded";
1467
+ }
1468
+ return "rate_limited";
1469
+ }
1470
+ if (/\b401\b/.test(msg) || /\b403\b/.test(msg) || /\bunauthorized\b/i.test(msg) || /\bforbidden\b/i.test(msg)) {
1471
+ return "auth_failure";
1472
+ }
1473
+ if (isErrnoCode(err, "ECONNRESET") || isErrnoCode(err, "ETIMEDOUT") || isErrnoCode(err, "ENOTFOUND") || isErrnoCode(err, "EAI_AGAIN") || isErrnoCode(err, "ECONNREFUSED") || /fetch failed/i.test(msg) || /network/i.test(msg)) {
1474
+ return "transient_network";
1475
+ }
1476
+ if (/\b5\d{2}\b/.test(msg) || /\bservice unavailable\b/i.test(msg)) {
1477
+ return "provider_unavailable";
1478
+ }
1479
+ if (/invalid json/i.test(msg) || /malformed/i.test(msg) || /unexpected token/i.test(msg)) {
1480
+ return "malformed_response";
1481
+ }
1482
+ return "unknown_hard_stop";
1483
+ }
1484
+
1485
+ // src/shared/constants/translate.ts
1486
+ var TRANSLATE_WORKERS_CAP = 64;
1487
+ var ENV_TRANSLATE_MAX_WORKERS = "I18NPRUNE_TRANSLATE_MAX_WORKERS";
1488
+ var ENV_TRANSLATE_PROVIDER = "I18NPRUNE_TRANSLATE_PROVIDER";
1489
+ var ENV_TRANSLATE_DEEPL_API_KEY = "I18NPRUNE_TRANSLATE_DEEPL_API_KEY";
1490
+ var ENV_TRANSLATE_LIBRE_URL = "I18NPRUNE_TRANSLATE_LIBRE_URL";
1491
+ var ENV_TRANSLATE_LLM_API_KEY = "I18NPRUNE_TRANSLATE_LLM_API_KEY";
1492
+ var ENV_TRANSLATE_LLM_BASE_URL = "I18NPRUNE_TRANSLATE_LLM_BASE_URL";
1493
+ var ENV_TRANSLATE_LLM_MODEL = "I18NPRUNE_TRANSLATE_LLM_MODEL";
1494
+
1495
+ // src/shared/translator/index.ts
1496
+ var DEFAULT_DELAYS = [400, 900];
1497
+ async function sleep(ms) {
1498
+ await new Promise((r) => setTimeout(r, ms));
1499
+ }
1500
+ async function translateLeaf(provider, sourceText, sourceLang, targetLang, options) {
1501
+ const { text, originals } = mask(sourceText);
1502
+ const providerId = options?.providerId ?? "google";
1503
+ let lastErr;
1504
+ for (let attempt = 0; attempt < 3; attempt += 1) {
1505
+ try {
1506
+ const raw = await provider.translate(text, sourceLang, targetLang);
1507
+ const unpacked = unpackProviderTranslation(raw);
1508
+ const normalized = validateLeafTranslationString(unpacked.text, "translate");
1509
+ const restored = restore(normalized, originals);
1510
+ validateRestored(sourceText, restored, originals);
1511
+ const heuristic = buildHeuristicLeafMeta({
1512
+ sourceText,
1513
+ translatedText: restored,
1514
+ providerId
1515
+ });
1516
+ const merged = mergeTranslationLeafMeta(heuristic, unpacked.patch);
1517
+ const decision = merged.needsReview === true ? "review" : "translated";
1518
+ const leafMeta = finalizeTranslationLeafMeta(merged, decision);
1519
+ await options?.onTranslated?.(sourceText, restored);
1520
+ const attempts = attempt + 1;
1521
+ return {
1522
+ text: restored,
1523
+ leafMeta,
1524
+ decision,
1525
+ runtime: { attempts, retries: Math.max(0, attempts - 1) }
1526
+ };
1527
+ } catch (e) {
1528
+ lastErr = e;
1529
+ if (attempt < 2) await sleep(DEFAULT_DELAYS[attempt] ?? 500);
1530
+ }
1531
+ }
1532
+ const parseMyMemoryQuotaWait = (msg) => {
1533
+ const m = msg.match(/NEXT AVAILABLE IN\s+(\d+)\s+HOURS\s+(\d+)\s+MINUTES\s+(\d+)\s+SECONDS/i);
1534
+ if (!m) return null;
1535
+ const h = Number.parseInt(m[1] ?? "", 10);
1536
+ const min = Number.parseInt(m[2] ?? "", 10);
1537
+ const s = Number.parseInt(m[3] ?? "", 10);
1538
+ if (![h, min, s].every((n) => Number.isFinite(n) && n >= 0)) return null;
1539
+ const parts = [h ? `${String(h)}h` : "", min ? `${String(min)}m` : "", `${String(s)}s`].filter(Boolean);
1540
+ return parts.join(" ");
1541
+ };
1542
+ const outcome = classifyTranslateFailure(lastErr);
1543
+ const issueCode = outcome === "rate_limited" || outcome === "quota_exceeded" ? ISSUE_GENERATE_TRANSLATE_RATE_LIMITED : outcome === "transient_network" || outcome === "provider_unavailable" ? ISSUE_GENERATE_TRANSLATE_NETWORK_ERROR : void 0;
1544
+ const issues = issueCode !== void 0 ? [
1545
+ {
1546
+ severity: "error",
1547
+ code: issueCode,
1548
+ message: issueCode === ISSUE_GENERATE_TRANSLATE_RATE_LIMITED ? (() => {
1549
+ const msg = lastErr instanceof Error ? lastErr.message : String(lastErr);
1550
+ const wait = /MYMEMORY WARNING/i.test(msg) ? parseMyMemoryQuotaWait(msg) : null;
1551
+ const waitHint = wait ? ` Wait time reported by MyMemory: ${wait}.` : "";
1552
+ const limitsHint = /MYMEMORY WARNING/i.test(msg) ? " See MyMemory usage limits: https://mymemory.translated.net/doc/usagelimits.php." : "";
1553
+ return `Translation failed: backend rate limited the request(s) (HTTP 429). Reduce --workers, wait, or switch provider.${waitHint}${limitsHint}`;
1554
+ })() : "Translation failed: network error talking to the translation backend. Check connectivity/DNS/proxy and retry.",
1555
+ docPath: issueCodeRepoDocPathForIssueCode(issueCode)
1556
+ }
1557
+ ] : [];
1558
+ const norm = normalizeUnknownError(lastErr, {
1559
+ when: "Translation failed after retries",
1560
+ defaultCode: "INTERNAL",
1561
+ ...issueCode !== void 0 ? { issueCode } : {}
1562
+ });
1563
+ norm.issues = issues;
1564
+ throw norm;
1565
+ }
1566
+
1567
+ // src/shared/locales/layout/index.ts
1568
+ var layout_exports = {};
1569
+ __export(layout_exports, {
1570
+ isLocalesLayoutReadSupported: () => isLocalesLayoutReadSupported,
1571
+ isLocalesLayoutWriteSupported: () => isLocalesLayoutWriteSupported,
1572
+ resolveLocalesLayout: () => resolveLocalesLayout,
1573
+ resolveLocalesLayoutFromContext: () => resolveLocalesLayoutFromContext,
1574
+ sourceLocaleCodeForLayout: () => sourceLocaleCodeForLayout
1575
+ });
1576
+
1577
+ // src/shared/locales/layout/requireStructure.ts
1578
+ function localesMode(config) {
1579
+ return config.mode ?? "flat_file";
1580
+ }
1581
+ function resolveLocalesStructure(config) {
1582
+ if (config.structure !== void 0) {
1583
+ return config.structure;
1584
+ }
1585
+ if (localesMode(config) === "flat_file") {
1586
+ return "locale_file";
1587
+ }
1588
+ throw new Error("locales.structure is required when locales.mode is locale_directory");
1589
+ }
1590
+
1591
+ // src/shared/locales/layout/resolveLayout.ts
1592
+ function resolveLocalesLayout(config, directoryAbsolute) {
1593
+ const mode = localesMode(config);
1594
+ const structure = resolveLocalesStructure(config);
1595
+ return { mode, structure, directoryAbsolute, config };
1596
+ }
1597
+ function resolveLocalesLayoutFromContext(ctx) {
1598
+ return resolveLocalesLayout(ctx.config.locales, ctx.paths.localesDir);
1599
+ }
1600
+ function isLocalesLayoutReadSupported(layout) {
1601
+ return layout.mode === "flat_file" && layout.structure === "locale_file" || layout.mode === "locale_directory" && (layout.structure === "locale_per_dir" || layout.structure === "feature_bundle");
1602
+ }
1603
+ function isLocalesLayoutWriteSupported(layout) {
1604
+ return layout.mode === "flat_file" && layout.structure === "locale_file" || layout.mode === "locale_directory" && (layout.structure === "locale_per_dir" || layout.structure === "feature_bundle");
1605
+ }
1606
+
1607
+ // src/shared/languages/normalize.ts
1608
+ function normalizeLanguageCode(code) {
1609
+ return code.trim().toLowerCase().replace(/_/g, "-");
1610
+ }
1611
+
1612
+ // src/shared/path/posix.ts
1613
+ function toPosixPath(value) {
1614
+ return value.replace(/\\/g, "/");
1615
+ }
1616
+
1617
+ // src/shared/locales/enumerate/resolveSegmentPath.ts
1618
+ function resolveLocaleSegmentAbsolutePath(input) {
1619
+ const { layout, path, locale } = input;
1620
+ const rel = input.segmentRelativePath ?? `${locale}.json`;
1621
+ return toPosixPath(path.join(layout.directoryAbsolute, rel));
1622
+ }
1623
+ function localeSegmentRefFromAbsolute(input) {
1624
+ const { layout, path, absolutePath } = input;
1625
+ let relativePath = path.relative(layout.directoryAbsolute, absolutePath);
1626
+ if (relativePath.startsWith("..") || path.isAbsolute(relativePath)) {
1627
+ return null;
1628
+ }
1629
+ relativePath = relativePath.replace(/\\/g, "/");
1630
+ if (!relativePath.endsWith(".json")) {
1631
+ return null;
1632
+ }
1633
+ const locale = localeCodeForSegment(layout.structure, path, { absolutePath, relativePath });
1634
+ if (locale === null) return null;
1635
+ return { locale, relativePath, absolutePath: toPosixPath(absolutePath) };
1636
+ }
1637
+
1638
+ // src/shared/locales/layout/sourceLocaleCode.ts
1639
+ function sourceLocaleCodeForLayout(input) {
1640
+ const ref = localeSegmentRefFromAbsolute({
1641
+ layout: input.layout,
1642
+ path: input.path,
1643
+ absolutePath: input.sourceLocaleAbsolute
1644
+ });
1645
+ if (ref !== null) {
1646
+ return normalizeLanguageCode(ref.locale);
1647
+ }
1648
+ return normalizeLanguageCode(input.path.basename(input.sourceLocaleAbsolute, ".json"));
1649
+ }
1650
+
1651
+ // src/shared/locales/read/index.ts
1652
+ var read_exports = {};
1653
+ __export(read_exports, {
1654
+ createLocaleReadCache: () => createLocaleReadCache,
1655
+ invalidateLocaleReadCacheForAbsolutePath: () => invalidateLocaleReadCacheForAbsolutePath,
1656
+ invalidateLocaleReadCacheForLocaleCode: () => invalidateLocaleReadCacheForLocaleCode,
1657
+ readFlatLocaleJsonSurface: () => readFlatLocaleJsonSurface,
1658
+ readLocaleBundle: () => readLocaleBundle,
1659
+ readLocaleCodeSurfaceFromContext: () => readLocaleCodeSurfaceFromContext,
1660
+ readLocaleJsonFromContextSync: () => readLocaleJsonFromContextSync,
1661
+ readLocalePerDirLocaleSurface: () => readLocalePerDirLocaleSurface,
1662
+ readLocaleSegmentFromContext: () => readLocaleSegmentFromContext
1663
+ });
1664
+
1665
+ // src/shared/locales/read/flatFileSurface.ts
1666
+ function readFlatLocaleJsonSurface(input) {
1667
+ const diagnostics = [];
1668
+ const emit = (d) => {
1669
+ diagnostics.push(d);
1670
+ input.onDiagnostic?.(d);
1671
+ };
1672
+ try {
1673
+ const text = readRuntimeFsTextSync(input.absoluteFile, input.fs);
1674
+ let json;
1675
+ try {
1676
+ json = parseJsonText(text, {
1677
+ filePath: input.absoluteFile,
1678
+ code: "IO",
1679
+ issueCode: ISSUE_IO_READ_FAILED
1680
+ });
1681
+ } catch (e) {
1682
+ const message = e instanceof Error ? e.message : String(e);
1683
+ emit({ level: "error", code: "locale_json_parse_failed", message, path: input.absoluteFile });
1684
+ return { ok: false, leaves: [], diagnostics };
1685
+ }
1686
+ const fileOrigin = localeSegmentSourceForFile({
1687
+ path: input.path,
1688
+ absoluteFile: input.absoluteFile,
1689
+ localesDir: input.localesDir,
1690
+ structure: input.structure
1691
+ });
1692
+ const leaves = collectTranslationSurfaceLeaves(json, "", [], fileOrigin ?? void 0);
1693
+ return { ok: true, document: json, leaves, text, diagnostics };
1694
+ } catch (e) {
1695
+ const message = e instanceof Error ? e.message : String(e);
1696
+ emit({ level: "error", code: "locale_fs_read_failed", message, path: input.absoluteFile });
1697
+ return { ok: false, leaves: [], diagnostics };
1698
+ }
1699
+ }
1700
+
1701
+ // src/shared/locales/read/bundle.ts
1702
+ function readLocaleBundle(input) {
1703
+ const diagnostics = [];
1704
+ const emit = (d) => {
1705
+ diagnostics.push(d);
1706
+ input.onDiagnostic?.(d);
1707
+ };
1708
+ if (!isLocalesLayoutReadSupported(input.layout)) {
1709
+ emit({
1710
+ level: "error",
1711
+ code: "locale_layout_unsupported",
1712
+ message: `locale read is not implemented for mode=${input.layout.mode} structure=${input.layout.structure}`,
1713
+ path: input.absoluteFile
1714
+ });
1715
+ return { ok: false, leaves: [], diagnostics };
1716
+ }
1717
+ const segmentRef = localeSegmentRefFromAbsolute({
1718
+ layout: input.layout,
1719
+ path: input.path,
1720
+ absolutePath: input.absoluteFile
1721
+ });
1722
+ if (segmentRef === null) {
1723
+ emit({
1724
+ level: "warn",
1725
+ code: "locale_read_path_layout_mismatch",
1726
+ message: `path does not match configured layout mode=${input.layout.mode} structure=${input.layout.structure}`,
1727
+ path: input.absoluteFile
1728
+ });
1729
+ return { ok: false, leaves: [], diagnostics };
1730
+ }
1731
+ return readFlatLocaleJsonSurface({
1732
+ fs: input.fs,
1733
+ path: input.path,
1734
+ absoluteFile: input.absoluteFile,
1735
+ localesDir: input.layout.directoryAbsolute,
1736
+ structure: input.layout.structure,
1737
+ onDiagnostic: input.onDiagnostic
1738
+ });
1739
+ }
1740
+
1741
+ // src/shared/locales/diagnostics/structuralParity.ts
1742
+ function localeStructuralSlot(structure, relativePath) {
1743
+ if (structure === "locale_per_dir") {
1744
+ const slash = relativePath.indexOf("/");
1745
+ if (slash < 0) return null;
1746
+ const slot = relativePath.slice(slash + 1);
1747
+ return slot.length > 0 ? slot : null;
1748
+ }
1749
+ if (structure === "feature_bundle") {
1750
+ const slash = relativePath.lastIndexOf("/");
1751
+ if (slash < 0) return null;
1752
+ const slot = relativePath.slice(0, slash);
1753
+ return slot.length > 0 ? slot : null;
1754
+ }
1755
+ return null;
1756
+ }
1757
+ function slotsByLocale(structure, segments) {
1758
+ const byLocale = /* @__PURE__ */ new Map();
1759
+ for (const segment of segments) {
1760
+ const slot = localeStructuralSlot(structure, segment.relativePath);
1761
+ if (slot === null) continue;
1762
+ let set = byLocale.get(segment.locale);
1763
+ if (!set) {
1764
+ set = /* @__PURE__ */ new Set();
1765
+ byLocale.set(segment.locale, set);
1766
+ }
1767
+ set.add(slot);
1768
+ }
1769
+ return byLocale;
1770
+ }
1771
+ function pickReferenceLocale(byLocale, preferred) {
1772
+ if (preferred !== void 0 && byLocale.has(preferred)) return preferred;
1773
+ let best = null;
1774
+ let bestSize = -1;
1775
+ for (const [locale, slots] of byLocale) {
1776
+ if (slots.size > bestSize) {
1777
+ best = locale;
1778
+ bestSize = slots.size;
1779
+ }
1780
+ }
1781
+ return best;
1782
+ }
1783
+ function collectLocaleStructuralParityDiagnostics(input) {
1784
+ const { structure, segments } = input;
1785
+ if (structure !== "locale_per_dir" && structure !== "feature_bundle") {
1786
+ return [];
1787
+ }
1788
+ const byLocale = slotsByLocale(structure, segments);
1789
+ if (byLocale.size < 2) return [];
1790
+ const reference = pickReferenceLocale(byLocale, input.referenceLocale);
1791
+ if (reference === null) return [];
1792
+ const referenceSlots = byLocale.get(reference);
1793
+ if (!referenceSlots || referenceSlots.size === 0) return [];
1794
+ const diagnostics = [];
1795
+ for (const [locale, slots] of byLocale) {
1796
+ if (locale === reference) continue;
1797
+ for (const slot of referenceSlots) {
1798
+ if (!slots.has(slot)) {
1799
+ diagnostics.push({
1800
+ level: "warn",
1801
+ code: "locale_structure_slot_missing",
1802
+ message: `locale ${locale} is missing segment slot ${slot} (present for reference locale ${reference})`
1803
+ });
1804
+ }
1805
+ }
1806
+ for (const slot of slots) {
1807
+ if (!referenceSlots.has(slot)) {
1808
+ diagnostics.push({
1809
+ level: "warn",
1810
+ code: "locale_structure_slot_extra",
1811
+ message: `locale ${locale} has extra segment slot ${slot} (not present for reference locale ${reference})`
1812
+ });
1813
+ }
1814
+ }
1815
+ }
1816
+ diagnostics.sort((a, b) => a.message.localeCompare(b.message));
1817
+ return diagnostics;
1818
+ }
1819
+ function collectSourceLocaleMissingSegmentDiagnostics(input) {
1820
+ const { structure, segments, sourceLocale } = input;
1821
+ if (structure !== "locale_per_dir" && structure !== "feature_bundle") {
1822
+ return [];
1823
+ }
1824
+ const byLocale = slotsByLocale(structure, segments);
1825
+ const sourceSlots = byLocale.get(sourceLocale);
1826
+ if (!sourceSlots) return [];
1827
+ const peerSlots = /* @__PURE__ */ new Set();
1828
+ for (const [locale, slots] of byLocale) {
1829
+ if (locale === sourceLocale) continue;
1830
+ for (const slot of slots) {
1831
+ peerSlots.add(slot);
1832
+ }
1833
+ }
1834
+ if (peerSlots.size === 0) return [];
1835
+ const diagnostics = [];
1836
+ for (const slot of peerSlots) {
1837
+ if (!sourceSlots.has(slot)) {
1838
+ diagnostics.push({
1839
+ level: "warn",
1840
+ code: "source_locale_segment_slot_missing",
1841
+ message: `source locale ${sourceLocale} is missing segment ${slot} (present for other locale(s) under locales.directory)`
1842
+ });
1843
+ }
1844
+ }
1845
+ diagnostics.sort((a, b) => a.message.localeCompare(b.message));
1846
+ return diagnostics;
1847
+ }
1848
+
1849
+ // src/shared/constants/locales.ts
1850
+ var MAX_LOCALE_SEGMENT_TREE_DEPTH = 16;
1851
+
1852
+ // src/shared/locales/enumerate/walkJsonTree.ts
1853
+ function posixRelative(pathApi, root, absolute) {
1854
+ let rel = pathApi.relative(root, absolute);
1855
+ if (rel.startsWith("..") || pathApi.isAbsolute(rel)) {
1856
+ rel = pathApi.basename(absolute);
1857
+ }
1858
+ return rel.replace(/\\/g, "/");
1859
+ }
1860
+ function walkLocaleJsonSegments(input) {
1861
+ const { fs, path, rootAbsolute, recursive } = input;
1862
+ const maxDepth = input.maxDepth ?? MAX_LOCALE_SEGMENT_TREE_DEPTH;
1863
+ const out = [];
1864
+ function visit(dirAbsolute, depth) {
1865
+ if (!existsRuntimeFsSync(dirAbsolute, fs)) return;
1866
+ const entries = listRuntimeFsDirSync(dirAbsolute, fs);
1867
+ for (const entry of entries) {
1868
+ const childAbsolute = path.join(dirAbsolute, entry.name);
1869
+ if (entry.kind === "file" && entry.name.endsWith(".json")) {
1870
+ out.push({
1871
+ absolutePath: childAbsolute,
1872
+ relativePath: posixRelative(path, rootAbsolute, childAbsolute)
1873
+ });
1874
+ } else if (recursive && entry.kind === "directory" && depth < maxDepth) {
1875
+ visit(childAbsolute, depth + 1);
1876
+ }
1877
+ }
1878
+ }
1879
+ visit(rootAbsolute, 0);
1880
+ return out;
1881
+ }
1882
+
1883
+ // src/shared/locales/enumerate/listLocaleSegments.ts
1884
+ function listLocaleSegments(input) {
1885
+ const diagnostics = [];
1886
+ const { layout, fs, path } = input;
1887
+ const recursive = layout.structure !== "locale_file";
1888
+ const walked = walkLocaleJsonSegments({
1889
+ fs,
1890
+ path,
1891
+ rootAbsolute: layout.directoryAbsolute,
1892
+ recursive
1893
+ });
1894
+ const segments = [];
1895
+ for (const segment of walked) {
1896
+ const locale = localeCodeForSegment(layout.structure, path, segment);
1897
+ if (locale === null) continue;
1898
+ segments.push({
1899
+ locale,
1900
+ relativePath: segment.relativePath,
1901
+ absolutePath: segment.absolutePath
1902
+ });
1903
+ }
1904
+ segments.sort((a, b) => {
1905
+ const byLocale = a.locale.localeCompare(b.locale);
1906
+ if (byLocale !== 0) return byLocale;
1907
+ return a.relativePath.localeCompare(b.relativePath);
1908
+ });
1909
+ diagnostics.push(
1910
+ ...collectLocaleStructuralParityDiagnostics({
1911
+ structure: layout.structure,
1912
+ segments
1913
+ })
1914
+ );
1915
+ return { segments, diagnostics };
1916
+ }
1917
+
1918
+ // src/shared/locales/enumerate/listLocaleCodes.ts
1919
+ function listLocaleCodes(input) {
1920
+ const { segments, diagnostics } = listLocaleSegments(input);
1921
+ const codes = [...new Set(segments.map((s) => s.locale))].sort((a, b) => a.localeCompare(b));
1922
+ return { codes, diagnostics };
1923
+ }
1924
+
1925
+ // src/shared/locales/enumerate/fromContext.ts
1926
+ function listLocaleSegmentsFromContext(ctx) {
1927
+ return listLocaleSegments({
1928
+ layout: resolveLocalesLayoutFromContext(ctx),
1929
+ fs: ctx.adapters.fs,
1930
+ path: ctx.adapters.path
1931
+ });
1932
+ }
1933
+ function listLocaleCodesFromContext(ctx) {
1934
+ return listLocaleCodes({
1935
+ layout: resolveLocalesLayoutFromContext(ctx),
1936
+ fs: ctx.adapters.fs,
1937
+ path: ctx.adapters.path
1938
+ });
1939
+ }
1940
+
1941
+ // src/shared/locales/targets/context.ts
1942
+ function normalizeCode(code) {
1943
+ return normalizeLanguageCode(code);
1944
+ }
1945
+ function listLocaleSegmentTargets(ctx) {
1946
+ const { segments } = listLocaleSegmentsFromContext(ctx);
1947
+ return segments.map((segment) => ({
1948
+ ...segment,
1949
+ reportKey: segment.relativePath
1950
+ }));
1951
+ }
1952
+ function sourceLocaleCodeFromContext(ctx) {
1953
+ const layout = resolveLocalesLayoutFromContext(ctx);
1954
+ const ref = localeSegmentRefFromAbsolute({
1955
+ layout,
1956
+ path: ctx.adapters.path,
1957
+ absolutePath: ctx.paths.sourceLocale
1958
+ });
1959
+ if (ref !== null) {
1960
+ return normalizeCode(ref.locale);
1961
+ }
1962
+ return normalizeCode(ctx.adapters.path.basename(ctx.paths.sourceLocale, ".json"));
1963
+ }
1964
+ function localeCodesFromContext(ctx) {
1965
+ return listLocaleCodesFromContext(ctx).codes.map((c) => normalizeCode(c));
1966
+ }
1967
+ function targetLocaleCodesFromContext(ctx) {
1968
+ const source = sourceLocaleCodeFromContext(ctx);
1969
+ return localeCodesFromContext(ctx).filter((c) => c !== source);
1970
+ }
1971
+ function segmentsForLocaleCode(ctx, localeCode) {
1972
+ const want = normalizeCode(localeCode);
1973
+ return listLocaleSegmentTargets(ctx).filter((s) => normalizeCode(s.locale) === want);
1974
+ }
1975
+ function primarySegmentForLocale(ctx, localeCode) {
1976
+ const segments = segmentsForLocaleCode(ctx, localeCode);
1977
+ if (segments.length === 0) return void 0;
1978
+ const sourceResolved = ctx.adapters.path.resolve(ctx.paths.sourceLocale);
1979
+ const sourceMatch = segments.find((s) => ctx.adapters.path.resolve(s.absolutePath) === sourceResolved);
1980
+ if (sourceMatch) return sourceMatch;
1981
+ return segments.slice().sort((a, b) => a.relativePath.localeCompare(b.relativePath))[0];
1982
+ }
1983
+ function resolveLocaleSegmentTargets(ctx, input) {
1984
+ const source = sourceLocaleCodeFromContext(ctx);
1985
+ const all = listLocaleSegmentTargets(ctx).filter((s) => normalizeCode(s.locale) !== source);
1986
+ if (input.selection.mode === "all") {
1987
+ return { segments: all, missingLocaleCodes: [] };
1988
+ }
1989
+ const missingLocaleCodes = [];
1990
+ const segments = [];
1991
+ for (const code of input.selection.codes) {
1992
+ const norm = normalizeCode(code);
1993
+ const forCode = all.filter((s) => normalizeCode(s.locale) === norm);
1994
+ if (forCode.length === 0) {
1995
+ missingLocaleCodes.push(norm);
1996
+ continue;
1997
+ }
1998
+ segments.push(...forCode);
1999
+ }
2000
+ segments.sort((a, b) => {
2001
+ const byLocale = a.locale.localeCompare(b.locale);
2002
+ if (byLocale !== 0) return byLocale;
2003
+ return a.relativePath.localeCompare(b.relativePath);
2004
+ });
2005
+ return { segments, missingLocaleCodes };
2006
+ }
2007
+
2008
+ // src/shared/locales/read/cache.ts
2009
+ function createLocaleReadCache() {
2010
+ return {
2011
+ segments: /* @__PURE__ */ new Map(),
2012
+ localeCodes: /* @__PURE__ */ new Map()
2013
+ };
2014
+ }
2015
+ function invalidateLocaleReadCacheForAbsolutePath(ctx, absolutePath) {
2016
+ ctx.localeRead.segments.delete(absolutePath);
2017
+ const layout = resolveLocalesLayoutFromContext(ctx);
2018
+ const ref = localeSegmentRefFromAbsolute({
2019
+ layout,
2020
+ path: ctx.adapters.path,
2021
+ absolutePath
2022
+ });
2023
+ if (ref !== null) {
2024
+ ctx.localeRead.localeCodes.delete(normalizeLanguageCode(ref.locale));
2025
+ }
2026
+ }
2027
+ function dropLocaleCodeReadCache(ctx, localeCode) {
2028
+ ctx.localeRead.localeCodes.delete(normalizeLanguageCode(localeCode));
2029
+ }
2030
+ function invalidateLocaleReadCacheForLocaleCode(ctx, localeCode) {
2031
+ const normalized = normalizeLanguageCode(localeCode);
2032
+ dropLocaleCodeReadCache(ctx, normalized);
2033
+ for (const segment of segmentsForLocaleCode(ctx, normalized)) {
2034
+ ctx.localeRead.segments.delete(segment.absolutePath);
2035
+ }
2036
+ }
2037
+
2038
+ // src/shared/locales/read/fromContext.ts
2039
+ function storeSegmentSnapshot(ctx, absoluteFile, snapshot) {
2040
+ ctx.localeRead.segments.set(absoluteFile, snapshot);
2041
+ if (snapshot.ok) {
2042
+ const layout = resolveLocalesLayoutFromContext(ctx);
2043
+ const ref = localeSegmentRefFromAbsolute({
2044
+ layout,
2045
+ path: ctx.adapters.path,
2046
+ absolutePath: absoluteFile
2047
+ });
2048
+ if (ref !== null) {
2049
+ dropLocaleCodeReadCache(ctx, ref.locale);
2050
+ }
2051
+ }
2052
+ }
2053
+ function segmentSnapshotToResult(snapshot) {
2054
+ if (snapshot.ok) {
2055
+ return {
2056
+ ok: true,
2057
+ document: snapshot.document,
2058
+ leaves: snapshot.leaves,
2059
+ text: snapshot.text,
2060
+ diagnostics: []
2061
+ };
2062
+ }
2063
+ return { ok: false, leaves: [], diagnostics: snapshot.diagnostics };
2064
+ }
2065
+ function readLocaleSegmentFromContext(ctx, absoluteFile, onDiagnostic) {
2066
+ const cached = ctx.localeRead.segments.get(absoluteFile);
2067
+ if (cached !== void 0) {
2068
+ return segmentSnapshotToResult(cached);
2069
+ }
2070
+ const result = readLocaleBundle({
2071
+ layout: resolveLocalesLayoutFromContext(ctx),
2072
+ fs: ctx.adapters.fs,
2073
+ path: ctx.adapters.path,
2074
+ absoluteFile,
2075
+ onDiagnostic
2076
+ });
2077
+ if (result.ok) {
2078
+ storeSegmentSnapshot(ctx, absoluteFile, {
2079
+ ok: true,
2080
+ absolutePath: absoluteFile,
2081
+ document: result.document,
2082
+ leaves: result.leaves,
2083
+ text: result.text
2084
+ });
2085
+ } else {
2086
+ storeSegmentSnapshot(ctx, absoluteFile, {
2087
+ ok: false,
2088
+ absolutePath: absoluteFile,
2089
+ diagnostics: result.diagnostics
2090
+ });
2091
+ }
2092
+ return result;
2093
+ }
2094
+ function storeLocaleCodeSnapshot(ctx, snapshot) {
2095
+ ctx.localeRead.localeCodes.set(normalizeLanguageCode(snapshot.localeCode), snapshot);
2096
+ }
2097
+ function readLocaleCodeSurfaceFromContext(ctx, localeCode, onDiagnostic) {
2098
+ const normalized = normalizeLanguageCode(localeCode);
2099
+ const cached = ctx.localeRead.localeCodes.get(normalized);
2100
+ if (cached !== void 0) {
2101
+ return {
2102
+ ok: true,
2103
+ document: cached.document,
2104
+ leaves: cached.leaves,
2105
+ text: "",
2106
+ diagnostics: []
2107
+ };
2108
+ }
2109
+ const layout = resolveLocalesLayoutFromContext(ctx);
2110
+ if (layout.mode === "flat_file") {
2111
+ const segment = primarySegmentForLocale(ctx, normalized);
2112
+ const absoluteFile = segment?.absolutePath ?? ctx.paths.sourceLocale;
2113
+ const read = readLocaleSegmentFromContext(ctx, absoluteFile, onDiagnostic);
2114
+ if (!read.ok) return read;
2115
+ storeLocaleCodeSnapshot(ctx, {
2116
+ localeCode: normalized,
2117
+ document: read.document,
2118
+ leaves: read.leaves
2119
+ });
2120
+ return read;
2121
+ }
2122
+ const diagnostics = [];
2123
+ const { segments, diagnostics: listDiagnostics } = listLocaleSegments({
2124
+ layout,
2125
+ fs: ctx.adapters.fs,
2126
+ path: ctx.adapters.path
2127
+ });
2128
+ diagnostics.push(...listDiagnostics);
2129
+ const forLocale = segments.filter((s) => normalizeLanguageCode(s.locale) === normalized);
2130
+ if (forLocale.length === 0) {
2131
+ const empty = { localeCode: normalized, document: {}, leaves: [] };
2132
+ storeLocaleCodeSnapshot(ctx, empty);
2133
+ return { ok: true, document: {}, leaves: [], text: "{}", diagnostics };
2134
+ }
2135
+ const allLeaves = [];
2136
+ const documents = [];
2137
+ let combinedText = "";
2138
+ for (const segment of forLocale) {
2139
+ const read = readLocaleSegmentFromContext(ctx, segment.absolutePath, onDiagnostic);
2140
+ diagnostics.push(...read.diagnostics);
2141
+ if (!read.ok) return { ok: false, leaves: [], diagnostics };
2142
+ allLeaves.push(...read.leaves);
2143
+ documents.push(read.document);
2144
+ combinedText = read.text;
2145
+ }
2146
+ const document = documents.length === 1 ? documents[0] : documents;
2147
+ storeLocaleCodeSnapshot(ctx, {
2148
+ localeCode: normalized,
2149
+ document,
2150
+ leaves: allLeaves
2151
+ });
2152
+ return {
2153
+ ok: true,
2154
+ document,
2155
+ leaves: allLeaves,
2156
+ text: combinedText,
2157
+ diagnostics
2158
+ };
2159
+ }
2160
+ function readLocaleJsonFromContextSync(ctx, absoluteFile) {
2161
+ const read = readLocaleSegmentFromContext(ctx, absoluteFile);
2162
+ if (!read.ok) {
2163
+ const message = read.diagnostics.map((d) => d.message).join(" \xB7 ") || "failed to read locale JSON";
2164
+ throw new I18nPruneError(message, "IO", { issueCode: ISSUE_IO_READ_FAILED });
2165
+ }
2166
+ return read.document;
2167
+ }
2168
+
2169
+ // src/shared/locales/read/perDirLocaleSurface.ts
2170
+ function readLocalePerDirLocaleSurface(input) {
2171
+ const diagnostics = [];
2172
+ const emit = (d) => {
2173
+ diagnostics.push(d);
2174
+ input.onDiagnostic?.(d);
2175
+ };
2176
+ const { segments, diagnostics: listDiagnostics } = listLocaleSegments({
2177
+ layout: input.layout,
2178
+ fs: input.fs,
2179
+ path: input.path
2180
+ });
2181
+ diagnostics.push(...listDiagnostics);
2182
+ const forLocale = segments.filter((s) => s.locale === input.localeCode);
2183
+ if (forLocale.length === 0) {
2184
+ emit({
2185
+ level: "warn",
2186
+ code: "locale_segment_not_found",
2187
+ message: `no locale segments found for code ${input.localeCode}`
2188
+ });
2189
+ return { ok: true, document: {}, leaves: [], text: "{}", diagnostics };
2190
+ }
2191
+ const allLeaves = [];
2192
+ const documents = [];
2193
+ let combinedText = "";
2194
+ for (const segment of forLocale) {
2195
+ const read = readFlatLocaleJsonSurface({
2196
+ fs: input.fs,
2197
+ path: input.path,
2198
+ absoluteFile: segment.absolutePath,
2199
+ localesDir: input.layout.directoryAbsolute,
2200
+ structure: input.layout.structure,
2201
+ onDiagnostic: input.onDiagnostic
2202
+ });
2203
+ diagnostics.push(...read.diagnostics);
2204
+ if (!read.ok) return { ok: false, leaves: [], diagnostics };
2205
+ allLeaves.push(...read.leaves);
2206
+ documents.push(read.document);
2207
+ combinedText = read.text;
2208
+ }
2209
+ return {
2210
+ ok: true,
2211
+ document: documents.length === 1 ? documents[0] : documents,
2212
+ leaves: allLeaves,
2213
+ text: combinedText,
2214
+ diagnostics
2215
+ };
2216
+ }
2217
+
2218
+ // src/shared/locales/write/index.ts
2219
+ var write_exports = {};
2220
+ __export(write_exports, {
2221
+ writeFlatLocaleJsonDocument: () => writeFlatLocaleJsonDocument,
2222
+ writeLocaleBundle: () => writeLocaleBundle,
2223
+ writeLocaleJsonFromContextSync: () => writeLocaleJsonFromContextSync
2224
+ });
2225
+
2226
+ // src/shared/json/sortKeys.ts
2227
+ function isPlainObject6(x) {
2228
+ return typeof x === "object" && x !== null && !Array.isArray(x);
2229
+ }
2230
+ function sortJsonObjectKeysAsc(value) {
2231
+ if (Array.isArray(value)) {
2232
+ return value.map((item) => sortJsonObjectKeysAsc(item));
2233
+ }
2234
+ if (!isPlainObject6(value)) return value;
2235
+ const sorted = {};
2236
+ for (const key of Object.keys(value).sort()) {
2237
+ sorted[key] = sortJsonObjectKeysAsc(value[key]);
2238
+ }
2239
+ return sorted;
2240
+ }
2241
+
2242
+ // src/shared/locales/write/flatFileLocaleJson.ts
2243
+ function writeFlatLocaleJsonDocument(input) {
2244
+ const diagnostics = [];
2245
+ const emit = (d) => {
2246
+ diagnostics.push(d);
2247
+ input.onDiagnostic?.(d);
2248
+ };
2249
+ const indent = input.indent ?? 2;
2250
+ let body;
2251
+ try {
2252
+ body = `${JSON.stringify(sortJsonObjectKeysAsc(input.data), null, indent)}
2253
+ `;
2254
+ } catch (e) {
2255
+ const message = e instanceof Error ? e.message : String(e);
2256
+ emit({ level: "error", code: "locale_json_serialize_failed", message, path: input.absoluteFile });
2257
+ return { ok: false, diagnostics };
2258
+ }
2259
+ try {
2260
+ input.fs.mkdirp(input.path.dirname(input.absoluteFile));
2261
+ input.fs.writeText(input.absoluteFile, body);
2262
+ return { ok: true, diagnostics };
2263
+ } catch (e) {
2264
+ const message = e instanceof Error ? e.message : String(e);
2265
+ emit({ level: "error", code: "locale_fs_write_failed", message, path: input.absoluteFile });
2266
+ return { ok: false, diagnostics };
2267
+ }
2268
+ }
2269
+
2270
+ // src/shared/locales/write/bundle.ts
2271
+ function writeLocaleBundle(input) {
2272
+ const diagnostics = [];
2273
+ const emit = (d) => {
2274
+ diagnostics.push(d);
2275
+ input.onDiagnostic?.(d);
2276
+ };
2277
+ if (!isLocalesLayoutWriteSupported(input.layout)) {
2278
+ emit({
2279
+ level: "error",
2280
+ code: "locale_layout_unsupported",
2281
+ message: `locale write is not implemented for mode=${input.layout.mode} structure=${input.layout.structure}`,
2282
+ path: input.absoluteFile
2283
+ });
2284
+ return { ok: false, diagnostics };
2285
+ }
2286
+ const segmentRef = localeSegmentRefFromAbsolute({
2287
+ layout: input.layout,
2288
+ path: input.path,
2289
+ absolutePath: input.absoluteFile
2290
+ });
2291
+ if (segmentRef === null) {
2292
+ emit({
2293
+ level: "warn",
2294
+ code: "locale_write_path_layout_mismatch",
2295
+ message: `path does not match configured layout mode=${input.layout.mode} structure=${input.layout.structure}`,
2296
+ path: input.absoluteFile
2297
+ });
2298
+ return { ok: false, diagnostics };
2299
+ }
2300
+ return writeFlatLocaleJsonDocument({
2301
+ fs: input.fs,
2302
+ path: input.path,
2303
+ absoluteFile: input.absoluteFile,
2304
+ data: input.data,
2305
+ indent: input.indent,
2306
+ onDiagnostic: input.onDiagnostic
2307
+ });
2308
+ }
2309
+ function writeLocaleJsonFromContextSync(ctx, absoluteFile, data) {
2310
+ const result = writeLocaleBundle({
2311
+ layout: resolveLocalesLayoutFromContext(ctx),
2312
+ fs: ctx.adapters.fs,
2313
+ path: ctx.adapters.path,
2314
+ absoluteFile,
2315
+ data
2316
+ });
2317
+ if (!result.ok) {
2318
+ const message = result.diagnostics.map((d) => d.message).join(" \xB7 ") || "failed to write locale JSON";
2319
+ throw new I18nPruneError(message, "IO", { issueCode: ISSUE_IO_READ_FAILED });
2320
+ }
2321
+ invalidateLocaleReadCacheForAbsolutePath(ctx, absoluteFile);
2322
+ }
2323
+
2324
+ // src/shared/projects/index.ts
2325
+ var projects_exports = {};
2326
+ __export(projects_exports, {
2327
+ translationSurfacePathValueMap: () => translationSurfacePathValueMap
2328
+ });
2329
+
2330
+ // src/shared/projects/localeSurfaceMap.ts
2331
+ function translationSurfacePathValueMap(localeJson) {
2332
+ const m = /* @__PURE__ */ new Map();
2333
+ for (const row of collectTranslationSurfaceLeaves(localeJson)) {
2334
+ m.set(row.path, row.value);
2335
+ }
2336
+ return m;
2337
+ }
2338
+
2339
+ // src/shared/sourcePlaceholders/index.ts
2340
+ var sourcePlaceholders_exports = {};
2341
+ __export(sourcePlaceholders_exports, {
2342
+ detectLocalePlaceholderLeaves: () => detectLocalePlaceholderLeaves,
2343
+ detectSourcePlaceholderLeaves: () => detectSourcePlaceholderLeaves,
2344
+ formatSourcePlaceholderMessage: () => formatSourcePlaceholderMessage,
2345
+ formatSyncSourcePlaceholderMessage: () => formatSyncSourcePlaceholderMessage,
2346
+ formatTargetPlaceholderMessage: () => formatTargetPlaceholderMessage,
2347
+ issuesFromSourcePlaceholderLeaves: () => issuesFromSourcePlaceholderLeaves,
2348
+ issuesFromTargetPlaceholderLeaves: () => issuesFromTargetPlaceholderLeaves,
2349
+ sourcePlaceholderValues: () => sourcePlaceholderValues
2350
+ });
2351
+
2352
+ // src/shared/constants/missing.ts
2353
+ var DEFAULT_MISSING_LEAF_PLACEHOLDER = "__I18NPRUNE_MISSING__";
2354
+ var MAX_MISSING_TARGET_SUGGESTIONS = 3;
2355
+
2356
+ // src/missing/placeholder.ts
2357
+ var MISSING_LEAF_PLACEHOLDER_MAX_LEN = 256;
2358
+ function resolveMissingLeafPlaceholder(raw) {
2359
+ const warnings = [];
2360
+ const def = DEFAULT_MISSING_LEAF_PLACEHOLDER;
2361
+ if (raw === void 0) return { placeholder: def, warnings };
2362
+ if (typeof raw !== "string") {
2363
+ warnings.push(
2364
+ `missing.placeholder must be a string; got ${typeof raw}. Using default ${JSON.stringify(def)} for reliable detection.`
2365
+ );
2366
+ return { placeholder: def, warnings };
2367
+ }
2368
+ const t = raw.trim();
2369
+ if (t.length === 0) {
2370
+ warnings.push(
2371
+ `missing.placeholder is empty or whitespace-only; using default ${JSON.stringify(def)} so missing tooling can detect scaffolded paths.`
2372
+ );
2373
+ return { placeholder: def, warnings };
2374
+ }
2375
+ if (t.length > MISSING_LEAF_PLACEHOLDER_MAX_LEN) {
2376
+ warnings.push(
2377
+ `missing.placeholder exceeds ${String(MISSING_LEAF_PLACEHOLDER_MAX_LEN)} characters; using default ${JSON.stringify(def)}.`
2378
+ );
2379
+ return { placeholder: def, warnings };
2380
+ }
2381
+ return { placeholder: t, warnings };
2382
+ }
2383
+
2384
+ // src/shared/sourcePlaceholders/index.ts
2385
+ function sourcePlaceholderValues(configuredPlaceholder) {
2386
+ const resolved = resolveMissingLeafPlaceholder(configuredPlaceholder).placeholder;
2387
+ return [...new Set([DEFAULT_MISSING_LEAF_PLACEHOLDER, resolved].filter((value) => value.trim().length > 0))];
2388
+ }
2389
+ function detectSourcePlaceholderLeaves(leaves, placeholderValues) {
2390
+ const sentinels = new Set(placeholderValues);
2391
+ if (sentinels.size === 0) return [];
2392
+ return leaves.filter((leaf) => sentinels.has(leaf.value)).map((leaf) => ({ path: leaf.path, value: leaf.value }));
2393
+ }
2394
+ function detectLocalePlaceholderLeaves(input) {
2395
+ return detectSourcePlaceholderLeaves(input.leaves, input.placeholderValues).map((leaf) => ({
2396
+ ...leaf,
2397
+ localeRole: input.localeRole,
2398
+ localeCode: input.localeCode,
2399
+ ...input.localePath !== void 0 ? { localePath: input.localePath } : {}
2400
+ }));
2401
+ }
2402
+ function formatSourcePlaceholderMessage(input) {
2403
+ const sample = input.samplePaths.join(", ");
2404
+ return `Source locale has ${String(input.count)} missing placeholder value(s). Run \`i18nprune missing --full\` to list placeholder paths. Replace them with real source copy, then run \`i18nprune sync\` and \`i18nprune generate --resume\` for target locales. Sample paths: ${sample}`;
2405
+ }
2406
+ function formatSyncSourcePlaceholderMessage(input) {
2407
+ const sample = input.samplePaths.join(", ");
2408
+ return `Source locale has ${String(input.count)} missing placeholder value(s); sync skipped those path(s) so placeholders are not copied to target locales. Run \`i18nprune missing --full\` to list placeholder paths. Replace them with real source copy, then run \`i18nprune sync\` and \`i18nprune generate --resume\`. Sample paths: ${sample}`;
2409
+ }
2410
+ function formatTargetPlaceholderMessage(input) {
2411
+ const sample = input.samplePaths.join(", ");
2412
+ const target = input.targetLabel === void 0 ? "Target locale" : `Target locale ${input.targetLabel}`;
2413
+ const listCommand = input.targetLabel === void 0 ? "i18nprune missing --target all --full" : `i18nprune missing --target ${input.targetLabel} --full`;
2414
+ return `${target} has ${String(input.count)} missing placeholder value(s). Run \`${listCommand}\` to list placeholder paths, then \`i18nprune sync\` and \`i18nprune generate --resume\` to refill translations. Sample paths: ${sample}`;
2415
+ }
2416
+ function issuesFromSourcePlaceholderLeaves(leaves) {
2417
+ if (leaves.length === 0) return [];
2418
+ return [
2419
+ {
2420
+ severity: "warning",
2421
+ code: ISSUE_LOCALE_SOURCE_PLACEHOLDER_LEAVES,
2422
+ message: formatSourcePlaceholderMessage({
2423
+ count: leaves.length,
2424
+ samplePaths: leaves.slice(0, 5).map((leaf) => leaf.path)
2425
+ }),
2426
+ docPath: issueCodeRepoDocPathForIssueCode(ISSUE_LOCALE_SOURCE_PLACEHOLDER_LEAVES)
2427
+ }
2428
+ ];
2429
+ }
2430
+ function issuesFromTargetPlaceholderLeaves(leaves) {
2431
+ const targetLeaves = leaves.filter((leaf) => leaf.localeRole === "target");
2432
+ if (targetLeaves.length === 0) return [];
2433
+ return [
2434
+ {
2435
+ severity: "warning",
2436
+ code: ISSUE_LOCALE_TARGET_PLACEHOLDER_LEAVES,
2437
+ message: formatTargetPlaceholderMessage({
2438
+ count: targetLeaves.length,
2439
+ samplePaths: targetLeaves.slice(0, 5).map((leaf) => `${leaf.localeCode}:${leaf.path}`),
2440
+ ...new Set(targetLeaves.map((leaf) => leaf.localeCode)).size === 1 ? { targetLabel: targetLeaves[0].localeCode } : {}
2441
+ }),
2442
+ docPath: issueCodeRepoDocPathForIssueCode(ISSUE_LOCALE_TARGET_PLACEHOLDER_LEAVES)
2443
+ }
2444
+ ];
2445
+ }
2446
+
2447
+ // src/shared/options/index.ts
2448
+ var options_exports = {};
2449
+ __export(options_exports, {
2450
+ LIST_WINDOW_DEFAULT_TOP: () => LIST_WINDOW_DEFAULT_TOP,
2451
+ LIST_WINDOW_HARD_CAP: () => LIST_WINDOW_HARD_CAP,
2452
+ applyListWindow: () => applyListWindow,
2453
+ getRunOptions: () => getRunOptions,
2454
+ resetRunOptions: () => resetRunOptions,
2455
+ resolveListWindow: () => resolveListWindow,
2456
+ setRunOptions: () => setRunOptions
2457
+ });
2458
+
2459
+ // src/shared/options/listWindow.ts
2460
+ var LIST_WINDOW_DEFAULT_TOP = 200;
2461
+ var LIST_WINDOW_HARD_CAP = 1e4;
2462
+ function clampPositiveInt(raw, fallback) {
2463
+ if (typeof raw !== "number" || !Number.isFinite(raw) || !Number.isInteger(raw) || raw < 1) {
2464
+ return fallback;
2465
+ }
2466
+ return raw;
2467
+ }
2468
+ function resolveListWindow(input, options) {
2469
+ const hardCap = clampPositiveInt(options?.hardCap, LIST_WINDOW_HARD_CAP);
2470
+ const defaultTopRaw = clampPositiveInt(options?.defaultTop, LIST_WINDOW_DEFAULT_TOP);
2471
+ const defaultTop = Math.min(defaultTopRaw, hardCap);
2472
+ if (input?.full === true) {
2473
+ return {
2474
+ top: hardCap,
2475
+ full: true,
2476
+ limit: hardCap,
2477
+ hardCap,
2478
+ clamped: false
2479
+ };
2480
+ }
2481
+ const requestedTop = input?.top;
2482
+ const top = clampPositiveInt(requestedTop, defaultTop);
2483
+ const limit = Math.min(top, hardCap);
2484
+ const isRequestedValidNumber = typeof requestedTop === "number" && Number.isFinite(requestedTop) && Number.isInteger(requestedTop);
2485
+ return {
2486
+ top,
2487
+ full: false,
2488
+ limit,
2489
+ hardCap,
2490
+ clamped: isRequestedValidNumber && requestedTop > hardCap
2491
+ };
2492
+ }
2493
+ function applyListWindow(items, window) {
2494
+ return items.slice(0, window.limit);
2495
+ }
2496
+
2497
+ // src/shared/run/index.ts
2498
+ var run_exports = {};
2499
+ __export(run_exports, {
2500
+ emitIssuesAsRunErrors: () => emitIssuesAsRunErrors,
2501
+ emitRunErrorFromUnknown: () => emitRunErrorFromUnknown,
2502
+ emitRunEvent: () => emitRunEvent,
2503
+ emitRunMessage: () => emitRunMessage,
2504
+ isProgressEvent: () => isProgressEvent,
2505
+ noopRunEmitter: () => noopRunEmitter,
2506
+ nowMs: () => nowMs
2507
+ });
2508
+ var noopRunEmitter = () => {
2509
+ };
2510
+ function emitRunEvent(emit, event) {
2511
+ if (!emit) return;
2512
+ try {
2513
+ emit(event);
2514
+ } catch {
2515
+ }
2516
+ }
2517
+ function emitRunMessage(emit, input) {
2518
+ emitRunEvent(emit, {
2519
+ type: "run.message",
2520
+ op: input.op,
2521
+ runId: input.runId,
2522
+ at: input.at ?? nowMs(),
2523
+ level: input.level,
2524
+ ...input.channel !== void 0 ? { channel: input.channel } : {},
2525
+ message: input.message,
2526
+ ...input.target !== void 0 ? { target: input.target } : {},
2527
+ ...input.path !== void 0 ? { path: input.path } : {},
2528
+ ...input.data !== void 0 ? { data: input.data } : {}
2529
+ });
2530
+ }
2531
+ function nowMs() {
2532
+ return Date.now();
2533
+ }
2534
+ function isProgressEvent(event) {
2535
+ return event.type.startsWith("run.progress.");
2536
+ }
2537
+ function emitIssuesAsRunErrors(emit, input) {
2538
+ const at = input.at ?? nowMs();
2539
+ for (const issue of input.issues) {
2540
+ emitRunEvent(emit, {
2541
+ type: "run.error",
2542
+ op: input.op,
2543
+ runId: input.runId,
2544
+ at,
2545
+ issue,
2546
+ recoverable: input.recoverable
2547
+ });
2548
+ }
2549
+ }
2550
+ function emitRunErrorFromUnknown(emit, input) {
2551
+ const normalized = normalizeUnknownError(input.err, {
2552
+ when: "Run error",
2553
+ defaultCode: "INTERNAL"
2554
+ });
2555
+ emitRunEvent(emit, {
2556
+ type: "run.error",
2557
+ op: input.op,
2558
+ runId: input.runId,
2559
+ at: input.at ?? nowMs(),
2560
+ issue: {
2561
+ severity: "error",
2562
+ code: input.code,
2563
+ message: normalized.message
2564
+ },
2565
+ recoverable: input.recoverable
2566
+ });
2567
+ }
2568
+
2569
+ // src/shared/result/index.ts
2570
+ var result_exports = {};
2571
+ __export(result_exports, {
2572
+ DOCS_SITE_ORIGIN: () => DOCS_SITE_ORIGIN,
2573
+ buildCliJsonEnvelope: () => buildCliJsonEnvelope,
2574
+ enrichIssuesWithDocHrefs: () => enrichIssuesWithDocHrefs,
2575
+ issueCodeDocHref: () => issueCodeDocHref,
2576
+ normalizeRepoDocPath: () => normalizeRepoDocPath,
2577
+ resolveIssueCodeDocLink: () => resolveIssueCodeDocLink,
2578
+ stringifyCliCommandJson: () => stringifyCliCommandJson,
2579
+ stringifyEnvelope: () => stringifyEnvelope
2580
+ });
2581
+
2582
+ // src/shared/constants/result.ts
2583
+ var RESULT_API_VERSION = "1";
2584
+
2585
+ // src/shared/docs/urls.ts
2586
+ function parseDocsLinkInput(input) {
2587
+ const hashIdx = input.indexOf("#");
2588
+ const hash = hashIdx >= 0 ? input.slice(hashIdx) : "";
2589
+ let p = (hashIdx >= 0 ? input.slice(0, hashIdx) : input).trim().replace(/^\/+/, "");
2590
+ p = p.replace(/\/+$/g, "");
2591
+ if (p.endsWith(".md")) p = p.slice(0, -3);
2592
+ if (p.endsWith(".mdx")) p = p.slice(0, -4);
2593
+ if (p === "README" || p.endsWith("/README")) {
2594
+ p = p === "README" ? "" : p.slice(0, -"/README".length);
2595
+ }
2596
+ p = p.replace(/\/+$/g, "");
2597
+ p = p.replace(/\/+/g, "/");
2598
+ return { core: p, hash };
2599
+ }
2600
+ function docsCommandUrl(command) {
2601
+ const slug = command.trim().toLowerCase();
2602
+ return `${DOCS_SITE_BASE}/commands/${slug}`;
2603
+ }
2604
+ function getDocsUrl(path = "") {
2605
+ const { core, hash } = parseDocsLinkInput(path);
2606
+ if (!core) {
2607
+ return `${DOCS_SITE_BASE}${hash}`;
2608
+ }
2609
+ return `${DOCS_SITE_BASE}/${core}${hash}`;
2610
+ }
2611
+
2612
+ // src/shared/docs/repoPaths.ts
2613
+ function normalizeRepoDocPath(docPath) {
2614
+ const t = docPath.trim();
2615
+ if (t === "") return t;
2616
+ if (t.startsWith("docs/")) return t;
2617
+ if (/^https?:\/\//i.test(t)) return t;
2618
+ return `docs/${t}`;
2619
+ }
2620
+
2621
+ // src/shared/result/issueDocLinks.ts
2622
+ function enrichIssuesWithDocHrefs(issues) {
2623
+ return issues.map((issue) => {
2624
+ const withPath = issue.docPath !== void 0 ? { ...issue, docPath: normalizeRepoDocPath(issue.docPath) } : issue;
2625
+ if (!withPath.code.startsWith("i18nprune.")) return withPath;
2626
+ if (withPath.docHref !== void 0) return withPath;
2627
+ return { ...withPath, docHref: issueCodeDocHref(withPath.code) };
2628
+ });
2629
+ }
2630
+
2631
+ // src/shared/result/cliJson.ts
2632
+ function dataWithoutRedundantKind(envelopeKind, data) {
2633
+ if (data === null || typeof data !== "object" || Array.isArray(data)) return data;
2634
+ if (!("kind" in data)) return data;
2635
+ const k = data.kind;
2636
+ if (k !== envelopeKind) return data;
2637
+ const { kind: _omit, ...rest } = data;
2638
+ return rest;
2639
+ }
2640
+ function buildCliJsonEnvelope(kind, data, options) {
2641
+ return {
2642
+ ok: options.ok,
2643
+ kind,
2644
+ data: dataWithoutRedundantKind(kind, data),
2645
+ issues: enrichIssuesWithDocHrefs(options.issues ?? []),
2646
+ meta: {
2647
+ apiVersion: RESULT_API_VERSION,
2648
+ ...options.schemaVersion !== void 0 ? { schemaVersion: options.schemaVersion } : {},
2649
+ ...options.cwd !== void 0 ? { cwd: options.cwd } : {}
2650
+ }
2651
+ };
2652
+ }
2653
+ function stringifyCliCommandJson(input) {
2654
+ const { kind, data, ok, issues, cwd, pretty } = input;
2655
+ const resolvedPretty = pretty ?? getRunOptions().jsonPretty;
2656
+ const envelope = buildCliJsonEnvelope(kind, data, {
2657
+ ok,
2658
+ issues,
2659
+ ...cwd !== void 0 ? { cwd } : {}
2660
+ });
2661
+ return resolvedPretty ? JSON.stringify(envelope, null, 2) : JSON.stringify(envelope);
2662
+ }
2663
+ function stringifyEnvelope(envelope, pretty) {
2664
+ const resolvedPretty = pretty ?? getRunOptions().jsonPretty;
2665
+ return resolvedPretty ? JSON.stringify(envelope, null, 2) : JSON.stringify(envelope);
2666
+ }
2667
+
2668
+ // src/shared/languages/catalog/index.ts
2669
+ var catalog_exports = {};
2670
+ __export(catalog_exports, {
2671
+ buildLanguageCatalog: () => buildLanguageCatalog,
2672
+ filterLanguageCatalog: () => filterLanguageCatalog,
2673
+ generatedLanguageCatalog: () => generatedLanguageCatalog,
2674
+ getLanguageByCodeFromCatalog: () => getLanguageByCodeFromCatalog,
2675
+ suggestCatalogCodesForInvalidInputFromCatalog: () => suggestCatalogCodesForInvalidInputFromCatalog
2676
+ });
2677
+
2678
+ // src/shared/languages/catalog/languages.json
2679
+ var languages_default = [
2680
+ {
2681
+ code: "ab",
2682
+ english: "Abkhazian",
2683
+ native: "Abkhazian",
2684
+ direction: "ltr"
2685
+ },
2686
+ {
2687
+ code: "ace",
2688
+ english: "Acehnese",
2689
+ native: "Acehnese",
2690
+ direction: "ltr"
2691
+ },
2692
+ {
2693
+ code: "ach",
2694
+ english: "Acoli",
2695
+ native: "Acoli",
2696
+ direction: "ltr"
2697
+ },
2698
+ {
2699
+ code: "af",
2700
+ english: "Afrikaans",
2701
+ native: "Afrikaans",
2702
+ direction: "ltr"
2703
+ },
2704
+ {
2705
+ code: "ak",
2706
+ english: "Akan",
2707
+ native: "Akan",
2708
+ direction: "ltr"
2709
+ },
2710
+ {
2711
+ code: "alz",
2712
+ english: "alz",
2713
+ native: "alz",
2714
+ direction: "ltr"
2715
+ },
2716
+ {
2717
+ code: "am",
2718
+ english: "Amharic",
2719
+ native: "\u12A0\u121B\u122D\u129B",
2720
+ direction: "ltr"
2721
+ },
2722
+ {
2723
+ code: "ar",
2724
+ english: "Arabic",
2725
+ native: "\u0627\u0644\u0639\u0631\u0628\u064A\u0629",
2726
+ direction: "rtl"
2727
+ },
2728
+ {
2729
+ code: "ar-sa",
2730
+ english: "Arabic (Saudi Arabia)",
2731
+ native: "\u0627\u0644\u0639\u0631\u0628\u064A\u0629 (\u0627\u0644\u0645\u0645\u0644\u0643\u0629 \u0627\u0644\u0639\u0631\u0628\u064A\u0629 \u0627\u0644\u0633\u0639\u0648\u062F\u064A\u0629)",
2732
+ direction: "rtl"
2733
+ },
2734
+ {
2735
+ code: "as",
2736
+ english: "Assamese",
2737
+ native: "\u0985\u09B8\u09AE\u09C0\u09AF\u09BC\u09BE",
2738
+ direction: "ltr"
2739
+ },
2740
+ {
2741
+ code: "awa",
2742
+ english: "Awadhi",
2743
+ native: "Awadhi",
2744
+ direction: "ltr"
2745
+ },
2746
+ {
2747
+ code: "ay",
2748
+ english: "Aymara",
2749
+ native: "Aymara",
2750
+ direction: "ltr"
2751
+ },
2752
+ {
2753
+ code: "az",
2754
+ english: "Azerbaijani",
2755
+ native: "az\u0259rbaycan",
2756
+ direction: "ltr"
2757
+ },
2758
+ {
2759
+ code: "ba",
2760
+ english: "Bashkir",
2761
+ native: "Bashkir",
2762
+ direction: "ltr"
2763
+ },
2764
+ {
2765
+ code: "ban",
2766
+ english: "Balinese",
2767
+ native: "Balinese",
2768
+ direction: "ltr"
2769
+ },
2770
+ {
2771
+ code: "bbc",
2772
+ english: "Batak Toba",
2773
+ native: "Batak Toba",
2774
+ direction: "ltr"
2775
+ },
2776
+ {
2777
+ code: "be",
2778
+ english: "Belarusian",
2779
+ native: "\u0431\u0435\u043B\u0430\u0440\u0443\u0441\u043A\u0430\u044F",
2780
+ direction: "ltr"
2781
+ },
2782
+ {
2783
+ code: "bem",
2784
+ english: "Bemba",
2785
+ native: "Ichibemba",
2786
+ direction: "ltr"
2787
+ },
2788
+ {
2789
+ code: "bew",
2790
+ english: "Betawi",
2791
+ native: "Betawi",
2792
+ direction: "ltr"
2793
+ },
2794
+ {
2795
+ code: "bg",
2796
+ english: "Bulgarian",
2797
+ native: "\u0431\u044A\u043B\u0433\u0430\u0440\u0441\u043A\u0438",
2798
+ direction: "ltr"
2799
+ },
2800
+ {
2801
+ code: "bho",
2802
+ english: "Bhojpuri",
2803
+ native: "\u092D\u094B\u091C\u092A\u0941\u0930\u0940",
2804
+ direction: "ltr"
2805
+ },
2806
+ {
2807
+ code: "bik",
2808
+ english: "Bikol",
2809
+ native: "Bikol",
2810
+ direction: "ltr"
2811
+ },
2812
+ {
2813
+ code: "bm",
2814
+ english: "Bambara",
2815
+ native: "bamanakan",
2816
+ direction: "ltr"
2817
+ },
2818
+ {
2819
+ code: "bn",
2820
+ english: "Bangla",
2821
+ native: "\u09AC\u09BE\u0982\u09B2\u09BE",
2822
+ direction: "ltr"
2823
+ },
2824
+ {
2825
+ code: "bn-in",
2826
+ english: "Bangla (India)",
2827
+ native: "\u09AC\u09BE\u0982\u09B2\u09BE (\u09AD\u09BE\u09B0\u09A4)",
2828
+ direction: "ltr"
2829
+ },
2830
+ {
2831
+ code: "br",
2832
+ english: "Breton",
2833
+ native: "brezhoneg",
2834
+ direction: "ltr"
2835
+ },
2836
+ {
2837
+ code: "bs",
2838
+ english: "Bosnian",
2839
+ native: "bosanski",
2840
+ direction: "ltr"
2841
+ },
2842
+ {
2843
+ code: "bs-cyrl",
2844
+ english: "Bosnian (Cyrillic)",
2845
+ native: "\u0431\u043E\u0441\u0430\u043D\u0441\u043A\u0438 (\u045B\u0438\u0440\u0438\u043B\u0438\u0446\u0430)",
2846
+ direction: "ltr"
2847
+ },
2848
+ {
2849
+ code: "bts",
2850
+ english: "bts",
2851
+ native: "bts",
2852
+ direction: "ltr"
2853
+ },
2854
+ {
2855
+ code: "btx",
2856
+ english: "btx",
2857
+ native: "btx",
2858
+ direction: "ltr"
2859
+ },
2860
+ {
2861
+ code: "bua",
2862
+ english: "Buriat",
2863
+ native: "Buriat",
2864
+ direction: "ltr"
2865
+ },
2866
+ {
2867
+ code: "ca",
2868
+ english: "Catalan",
2869
+ native: "catal\xE0",
2870
+ direction: "ltr"
2871
+ },
2872
+ {
2873
+ code: "ceb",
2874
+ english: "Cebuano",
2875
+ native: "Cebuano",
2876
+ direction: "ltr"
2877
+ },
2878
+ {
2879
+ code: "cgg",
2880
+ english: "Chiga",
2881
+ native: "Rukiga",
2882
+ direction: "ltr"
2883
+ },
2884
+ {
2885
+ code: "chm",
2886
+ english: "Mari",
2887
+ native: "Mari",
2888
+ direction: "ltr"
2889
+ },
2890
+ {
2891
+ code: "ckb",
2892
+ english: "Central Kurdish",
2893
+ native: "\u06A9\u0648\u0631\u062F\u06CC\u06CC \u0646\u0627\u0648\u06D5\u0646\u062F\u06CC",
2894
+ direction: "rtl"
2895
+ },
2896
+ {
2897
+ code: "cnh",
2898
+ english: "cnh",
2899
+ native: "cnh",
2900
+ direction: "ltr"
2901
+ },
2902
+ {
2903
+ code: "co",
2904
+ english: "Corsican",
2905
+ native: "Corsican",
2906
+ direction: "ltr"
2907
+ },
2908
+ {
2909
+ code: "crh",
2910
+ english: "Crimean Tatar",
2911
+ native: "Crimean Tatar",
2912
+ direction: "ltr"
2913
+ },
2914
+ {
2915
+ code: "crs",
2916
+ english: "Seselwa Creole French",
2917
+ native: "Seselwa Creole French",
2918
+ direction: "ltr"
2919
+ },
2920
+ {
2921
+ code: "cs",
2922
+ english: "Czech",
2923
+ native: "\u010De\u0161tina",
2924
+ direction: "ltr"
2925
+ },
2926
+ {
2927
+ code: "cv",
2928
+ english: "Chuvash",
2929
+ native: "\u0447\u04D1\u0432\u0430\u0448",
2930
+ direction: "ltr"
2931
+ },
2932
+ {
2933
+ code: "cy",
2934
+ english: "Welsh",
2935
+ native: "Cymraeg",
2936
+ direction: "ltr"
2937
+ },
2938
+ {
2939
+ code: "da",
2940
+ english: "Danish",
2941
+ native: "dansk",
2942
+ direction: "ltr"
2943
+ },
2944
+ {
2945
+ code: "de",
2946
+ english: "German",
2947
+ native: "Deutsch",
2948
+ direction: "ltr"
2949
+ },
2950
+ {
2951
+ code: "din",
2952
+ english: "Dinka",
2953
+ native: "Dinka",
2954
+ direction: "ltr"
2955
+ },
2956
+ {
2957
+ code: "doi",
2958
+ english: "Dogri",
2959
+ native: "\u0921\u094B\u0917\u0930\u0940",
2960
+ direction: "ltr"
2961
+ },
2962
+ {
2963
+ code: "dov",
2964
+ english: "dov",
2965
+ native: "dov",
2966
+ direction: "ltr"
2967
+ },
2968
+ {
2969
+ code: "dv",
2970
+ english: "Divehi",
2971
+ native: "Divehi",
2972
+ direction: "rtl"
2973
+ },
2974
+ {
2975
+ code: "dz",
2976
+ english: "Dzongkha",
2977
+ native: "\u0F62\u0FAB\u0F7C\u0F44\u0F0B\u0F41",
2978
+ direction: "ltr"
2979
+ },
2980
+ {
2981
+ code: "ee",
2982
+ english: "Ewe",
2983
+ native: "E\u028Begbe",
2984
+ direction: "ltr"
2985
+ },
2986
+ {
2987
+ code: "el",
2988
+ english: "Greek",
2989
+ native: "\u0395\u03BB\u03BB\u03B7\u03BD\u03B9\u03BA\u03AC",
2990
+ direction: "ltr"
2991
+ },
2992
+ {
2993
+ code: "en",
2994
+ english: "English",
2995
+ native: "English",
2996
+ direction: "ltr"
2997
+ },
2998
+ {
2999
+ code: "en-au",
3000
+ english: "Australian English",
3001
+ native: "Australian English",
3002
+ direction: "ltr"
3003
+ },
3004
+ {
3005
+ code: "en-ca",
3006
+ english: "Canadian English",
3007
+ native: "Canadian English",
3008
+ direction: "ltr"
3009
+ },
3010
+ {
3011
+ code: "en-gb",
3012
+ english: "British English",
3013
+ native: "British English",
3014
+ direction: "ltr"
3015
+ },
3016
+ {
3017
+ code: "en-nz",
3018
+ english: "English (New Zealand)",
3019
+ native: "English (New Zealand)",
3020
+ direction: "ltr"
3021
+ },
3022
+ {
3023
+ code: "en-ph",
3024
+ english: "English (Philippines)",
3025
+ native: "English (Philippines)",
3026
+ direction: "ltr"
3027
+ },
3028
+ {
3029
+ code: "en-us",
3030
+ english: "American English",
3031
+ native: "American English",
3032
+ direction: "ltr"
3033
+ },
3034
+ {
3035
+ code: "en-za",
3036
+ english: "English (South Africa)",
3037
+ native: "English (South Africa)",
3038
+ direction: "ltr"
3039
+ },
3040
+ {
3041
+ code: "eo",
3042
+ english: "Esperanto",
3043
+ native: "Esperanto",
3044
+ direction: "ltr"
3045
+ },
3046
+ {
3047
+ code: "es",
3048
+ english: "Spanish",
3049
+ native: "espa\xF1ol",
3050
+ direction: "ltr"
3051
+ },
3052
+ {
3053
+ code: "es-419",
3054
+ english: "Latin American Spanish",
3055
+ native: "espa\xF1ol latinoamericano",
3056
+ direction: "ltr"
3057
+ },
3058
+ {
3059
+ code: "es-ar",
3060
+ english: "Spanish (Argentina)",
3061
+ native: "espa\xF1ol (Argentina)",
3062
+ direction: "ltr"
3063
+ },
3064
+ {
3065
+ code: "es-cl",
3066
+ english: "Spanish (Chile)",
3067
+ native: "espa\xF1ol (Chile)",
3068
+ direction: "ltr"
3069
+ },
3070
+ {
3071
+ code: "es-co",
3072
+ english: "Spanish (Colombia)",
3073
+ native: "espa\xF1ol (Colombia)",
3074
+ direction: "ltr"
3075
+ },
3076
+ {
3077
+ code: "es-cr",
3078
+ english: "Spanish (Costa Rica)",
3079
+ native: "espa\xF1ol (Costa Rica)",
3080
+ direction: "ltr"
3081
+ },
3082
+ {
3083
+ code: "es-ec",
3084
+ english: "Spanish (Ecuador)",
3085
+ native: "espa\xF1ol (Ecuador)",
3086
+ direction: "ltr"
3087
+ },
3088
+ {
3089
+ code: "es-es",
3090
+ english: "European Spanish",
3091
+ native: "espa\xF1ol de Espa\xF1a",
3092
+ direction: "ltr"
3093
+ },
3094
+ {
3095
+ code: "es-gt",
3096
+ english: "Spanish (Guatemala)",
3097
+ native: "espa\xF1ol (Guatemala)",
3098
+ direction: "ltr"
3099
+ },
3100
+ {
3101
+ code: "es-hn",
3102
+ english: "Spanish (Honduras)",
3103
+ native: "espa\xF1ol (Honduras)",
3104
+ direction: "ltr"
3105
+ },
3106
+ {
3107
+ code: "es-ht",
3108
+ english: "Spanish (Haiti)",
3109
+ native: "espa\xF1ol (Hait\xED)",
3110
+ direction: "ltr"
3111
+ },
3112
+ {
3113
+ code: "es-mx",
3114
+ english: "Mexican Spanish",
3115
+ native: "espa\xF1ol de M\xE9xico",
3116
+ direction: "ltr"
3117
+ },
3118
+ {
3119
+ code: "es-ni",
3120
+ english: "Spanish (Nicaragua)",
3121
+ native: "espa\xF1ol (Nicaragua)",
3122
+ direction: "ltr"
3123
+ },
3124
+ {
3125
+ code: "es-pa",
3126
+ english: "Spanish (Panama)",
3127
+ native: "espa\xF1ol (Panam\xE1)",
3128
+ direction: "ltr"
3129
+ },
3130
+ {
3131
+ code: "es-pe",
3132
+ english: "Spanish (Peru)",
3133
+ native: "espa\xF1ol (Per\xFA)",
3134
+ direction: "ltr"
3135
+ },
3136
+ {
3137
+ code: "es-pr",
3138
+ english: "Spanish (Puerto Rico)",
3139
+ native: "espa\xF1ol (Puerto Rico)",
3140
+ direction: "ltr"
3141
+ },
3142
+ {
3143
+ code: "es-py",
3144
+ english: "Spanish (Paraguay)",
3145
+ native: "espa\xF1ol (Paraguay)",
3146
+ direction: "ltr"
3147
+ },
3148
+ {
3149
+ code: "es-sv",
3150
+ english: "Spanish (El Salvador)",
3151
+ native: "espa\xF1ol (El Salvador)",
3152
+ direction: "ltr"
3153
+ },
3154
+ {
3155
+ code: "es-us",
3156
+ english: "Spanish (United States)",
3157
+ native: "espa\xF1ol (Estados Unidos)",
3158
+ direction: "ltr"
3159
+ },
3160
+ {
3161
+ code: "es-uy",
3162
+ english: "Spanish (Uruguay)",
3163
+ native: "espa\xF1ol (Uruguay)",
3164
+ direction: "ltr"
3165
+ },
3166
+ {
3167
+ code: "es-ve",
3168
+ english: "Spanish (Venezuela)",
3169
+ native: "espa\xF1ol (Venezuela)",
3170
+ direction: "ltr"
3171
+ },
3172
+ {
3173
+ code: "et",
3174
+ english: "Estonian",
3175
+ native: "eesti",
3176
+ direction: "ltr"
3177
+ },
3178
+ {
3179
+ code: "eu",
3180
+ english: "Basque",
3181
+ native: "euskara",
3182
+ direction: "ltr"
3183
+ },
3184
+ {
3185
+ code: "fa",
3186
+ english: "Persian",
3187
+ native: "\u0641\u0627\u0631\u0633\u06CC",
3188
+ direction: "rtl"
3189
+ },
3190
+ {
3191
+ code: "ff",
3192
+ english: "Fula",
3193
+ native: "Pulaar",
3194
+ direction: "rtl"
3195
+ },
3196
+ {
3197
+ code: "fi",
3198
+ english: "Finnish",
3199
+ native: "suomi",
3200
+ direction: "ltr"
3201
+ },
3202
+ {
3203
+ code: "fil",
3204
+ english: "Filipino",
3205
+ native: "Filipino",
3206
+ direction: "ltr"
3207
+ },
3208
+ {
3209
+ code: "fj",
3210
+ english: "Fijian",
3211
+ native: "Fijian",
3212
+ direction: "ltr"
3213
+ },
3214
+ {
3215
+ code: "fr",
3216
+ english: "French",
3217
+ native: "fran\xE7ais",
3218
+ direction: "ltr"
3219
+ },
3220
+ {
3221
+ code: "fr-ca",
3222
+ english: "Canadian French",
3223
+ native: "fran\xE7ais canadien",
3224
+ direction: "ltr"
3225
+ },
3226
+ {
3227
+ code: "fr-ch",
3228
+ english: "Swiss French",
3229
+ native: "fran\xE7ais suisse",
3230
+ direction: "ltr"
3231
+ },
3232
+ {
3233
+ code: "fr-fr",
3234
+ english: "French (France)",
3235
+ native: "fran\xE7ais (France)",
3236
+ direction: "ltr"
3237
+ },
3238
+ {
3239
+ code: "fy",
3240
+ english: "Western Frisian",
3241
+ native: "Frysk",
3242
+ direction: "ltr"
3243
+ },
3244
+ {
3245
+ code: "ga",
3246
+ english: "Irish",
3247
+ native: "Gaeilge",
3248
+ direction: "ltr"
3249
+ },
3250
+ {
3251
+ code: "gaa",
3252
+ english: "Ga",
3253
+ native: "Ga",
3254
+ direction: "ltr"
3255
+ },
3256
+ {
3257
+ code: "gd",
3258
+ english: "Scottish Gaelic",
3259
+ native: "G\xE0idhlig",
3260
+ direction: "ltr"
3261
+ },
3262
+ {
3263
+ code: "gl",
3264
+ english: "Galician",
3265
+ native: "galego",
3266
+ direction: "ltr"
3267
+ },
3268
+ {
3269
+ code: "gn",
3270
+ english: "Guarani",
3271
+ native: "Guarani",
3272
+ direction: "ltr"
3273
+ },
3274
+ {
3275
+ code: "gom",
3276
+ english: "Goan Konkani",
3277
+ native: "Goan Konkani",
3278
+ direction: "ltr"
3279
+ },
3280
+ {
3281
+ code: "gu",
3282
+ english: "Gujarati",
3283
+ native: "\u0A97\u0AC1\u0A9C\u0AB0\u0ABE\u0AA4\u0AC0",
3284
+ direction: "ltr"
3285
+ },
3286
+ {
3287
+ code: "ha",
3288
+ english: "Hausa",
3289
+ native: "Hausa",
3290
+ direction: "rtl"
3291
+ },
3292
+ {
3293
+ code: "haw",
3294
+ english: "Hawaiian",
3295
+ native: "\u02BB\u014Clelo Hawai\u02BBi",
3296
+ direction: "ltr"
3297
+ },
3298
+ {
3299
+ code: "he",
3300
+ english: "Hebrew",
3301
+ native: "\u05E2\u05D1\u05E8\u05D9\u05EA",
3302
+ direction: "rtl"
3303
+ },
3304
+ {
3305
+ code: "hi",
3306
+ english: "Hindi",
3307
+ native: "\u0939\u093F\u0928\u094D\u0926\u0940",
3308
+ direction: "ltr"
3309
+ },
3310
+ {
3311
+ code: "hil",
3312
+ english: "Hiligaynon",
3313
+ native: "Hiligaynon",
3314
+ direction: "ltr"
3315
+ },
3316
+ {
3317
+ code: "hmn",
3318
+ english: "Hmong",
3319
+ native: "Hmong",
3320
+ direction: "ltr"
3321
+ },
3322
+ {
3323
+ code: "hr",
3324
+ english: "Croatian",
3325
+ native: "hrvatski",
3326
+ direction: "ltr"
3327
+ },
3328
+ {
3329
+ code: "hrx",
3330
+ english: "hrx",
3331
+ native: "hrx",
3332
+ direction: "ltr"
3333
+ },
3334
+ {
3335
+ code: "ht",
3336
+ english: "Haitian Creole",
3337
+ native: "Haitian Creole",
3338
+ direction: "ltr"
3339
+ },
3340
+ {
3341
+ code: "hu",
3342
+ english: "Hungarian",
3343
+ native: "magyar",
3344
+ direction: "ltr"
3345
+ },
3346
+ {
3347
+ code: "hy",
3348
+ english: "Armenian",
3349
+ native: "\u0570\u0561\u0575\u0565\u0580\u0565\u0576",
3350
+ direction: "ltr"
3351
+ },
3352
+ {
3353
+ code: "id",
3354
+ english: "Indonesian",
3355
+ native: "Indonesia",
3356
+ direction: "ltr"
3357
+ },
3358
+ {
3359
+ code: "ig",
3360
+ english: "Igbo",
3361
+ native: "Igbo",
3362
+ direction: "ltr"
3363
+ },
3364
+ {
3365
+ code: "ilo",
3366
+ english: "Iloko",
3367
+ native: "Iloko",
3368
+ direction: "ltr"
3369
+ },
3370
+ {
3371
+ code: "is",
3372
+ english: "Icelandic",
3373
+ native: "\xEDslenska",
3374
+ direction: "ltr"
3375
+ },
3376
+ {
3377
+ code: "it",
3378
+ english: "Italian",
3379
+ native: "italiano",
3380
+ direction: "ltr"
3381
+ },
3382
+ {
3383
+ code: "iw",
3384
+ english: "Hebrew",
3385
+ native: "\u05E2\u05D1\u05E8\u05D9\u05EA",
3386
+ direction: "rtl"
3387
+ },
3388
+ {
3389
+ code: "ja",
3390
+ english: "Japanese",
3391
+ native: "\u65E5\u672C\u8A9E",
3392
+ direction: "ltr"
3393
+ },
3394
+ {
3395
+ code: "jv",
3396
+ english: "Javanese",
3397
+ native: "Jawa",
3398
+ direction: "ltr"
3399
+ },
3400
+ {
3401
+ code: "jw",
3402
+ english: "Javanese",
3403
+ native: "Jawa",
3404
+ direction: "ltr"
3405
+ },
3406
+ {
3407
+ code: "ka",
3408
+ english: "Georgian",
3409
+ native: "\u10E5\u10D0\u10E0\u10D7\u10E3\u10DA\u10D8",
3410
+ direction: "ltr"
3411
+ },
3412
+ {
3413
+ code: "kk",
3414
+ english: "Kazakh",
3415
+ native: "\u049B\u0430\u0437\u0430\u049B \u0442\u0456\u043B\u0456",
3416
+ direction: "ltr"
3417
+ },
3418
+ {
3419
+ code: "km",
3420
+ english: "Khmer",
3421
+ native: "\u1781\u17D2\u1798\u17C2\u179A",
3422
+ direction: "ltr"
3423
+ },
3424
+ {
3425
+ code: "kn",
3426
+ english: "Kannada",
3427
+ native: "\u0C95\u0CA8\u0CCD\u0CA8\u0CA1",
3428
+ direction: "ltr"
3429
+ },
3430
+ {
3431
+ code: "ko",
3432
+ english: "Korean",
3433
+ native: "\uD55C\uAD6D\uC5B4",
3434
+ direction: "ltr"
3435
+ },
3436
+ {
3437
+ code: "kri",
3438
+ english: "Krio",
3439
+ native: "Krio",
3440
+ direction: "ltr"
3441
+ },
3442
+ {
3443
+ code: "ktu",
3444
+ english: "ktu",
3445
+ native: "ktu",
3446
+ direction: "ltr"
3447
+ },
3448
+ {
3449
+ code: "ku",
3450
+ english: "Kurdish",
3451
+ native: "kurd\xEE (kurmanc\xEE)",
3452
+ direction: "ltr"
3453
+ },
3454
+ {
3455
+ code: "ky",
3456
+ english: "Kyrgyz",
3457
+ native: "\u043A\u044B\u0440\u0433\u044B\u0437\u0447\u0430",
3458
+ direction: "ltr"
3459
+ },
3460
+ {
3461
+ code: "la",
3462
+ english: "Latin",
3463
+ native: "Latin",
3464
+ direction: "ltr"
3465
+ },
3466
+ {
3467
+ code: "lb",
3468
+ english: "Luxembourgish",
3469
+ native: "L\xEBtzebuergesch",
3470
+ direction: "ltr"
3471
+ },
3472
+ {
3473
+ code: "lg",
3474
+ english: "Ganda",
3475
+ native: "Luganda",
3476
+ direction: "ltr"
3477
+ },
3478
+ {
3479
+ code: "li",
3480
+ english: "Limburgish",
3481
+ native: "Limburgish",
3482
+ direction: "ltr"
3483
+ },
3484
+ {
3485
+ code: "lij",
3486
+ english: "Ligurian",
3487
+ native: "ligure",
3488
+ direction: "ltr"
3489
+ },
3490
+ {
3491
+ code: "lmo",
3492
+ english: "Lombard",
3493
+ native: "Lombard",
3494
+ direction: "ltr"
3495
+ },
3496
+ {
3497
+ code: "ln",
3498
+ english: "Lingala",
3499
+ native: "ling\xE1la",
3500
+ direction: "ltr"
3501
+ },
3502
+ {
3503
+ code: "lo",
3504
+ english: "Lao",
3505
+ native: "\u0EA5\u0EB2\u0EA7",
3506
+ direction: "ltr"
3507
+ },
3508
+ {
3509
+ code: "lt",
3510
+ english: "Lithuanian",
3511
+ native: "lietuvi\u0173",
3512
+ direction: "ltr"
3513
+ },
3514
+ {
3515
+ code: "ltg",
3516
+ english: "Latgalian",
3517
+ native: "Latgalian",
3518
+ direction: "ltr"
3519
+ },
3520
+ {
3521
+ code: "luo",
3522
+ english: "Luo",
3523
+ native: "Dholuo",
3524
+ direction: "ltr"
3525
+ },
3526
+ {
3527
+ code: "lus",
3528
+ english: "Mizo",
3529
+ native: "Mizo",
3530
+ direction: "ltr"
3531
+ },
3532
+ {
3533
+ code: "lv",
3534
+ english: "Latvian",
3535
+ native: "latvie\u0161u",
3536
+ direction: "ltr"
3537
+ },
3538
+ {
3539
+ code: "mai",
3540
+ english: "Maithili",
3541
+ native: "\u092E\u0948\u0925\u093F\u0932\u0940",
3542
+ direction: "ltr"
3543
+ },
3544
+ {
3545
+ code: "mak",
3546
+ english: "Makasar",
3547
+ native: "Makasar",
3548
+ direction: "ltr"
3549
+ },
3550
+ {
3551
+ code: "mg",
3552
+ english: "Malagasy",
3553
+ native: "Malagasy",
3554
+ direction: "ltr"
3555
+ },
3556
+ {
3557
+ code: "mi",
3558
+ english: "M\u0101ori",
3559
+ native: "M\u0101ori",
3560
+ direction: "ltr"
3561
+ },
3562
+ {
3563
+ code: "min",
3564
+ english: "Minangkabau",
3565
+ native: "Minangkabau",
3566
+ direction: "ltr"
3567
+ },
3568
+ {
3569
+ code: "mk",
3570
+ english: "Macedonian",
3571
+ native: "\u043C\u0430\u043A\u0435\u0434\u043E\u043D\u0441\u043A\u0438",
3572
+ direction: "ltr"
3573
+ },
3574
+ {
3575
+ code: "ml",
3576
+ english: "Malayalam",
3577
+ native: "\u0D2E\u0D32\u0D2F\u0D3E\u0D33\u0D02",
3578
+ direction: "ltr"
3579
+ },
3580
+ {
3581
+ code: "mn",
3582
+ english: "Mongolian",
3583
+ native: "\u043C\u043E\u043D\u0433\u043E\u043B",
3584
+ direction: "ltr"
3585
+ },
3586
+ {
3587
+ code: "mni-mtei",
3588
+ english: "Manipuri (Meitei Mayek)",
3589
+ native: "\u09AE\u09C8\u09A4\u09C8\u09B2\u09CB\u09A8\u09CD (\u09AE\u09C0\u09A4\u09C8 \u09AE\u09AF\u09BC\u09C7\u0995)",
3590
+ direction: "ltr"
3591
+ },
3592
+ {
3593
+ code: "mr",
3594
+ english: "Marathi",
3595
+ native: "\u092E\u0930\u093E\u0920\u0940",
3596
+ direction: "ltr"
3597
+ },
3598
+ {
3599
+ code: "ms",
3600
+ english: "Malay",
3601
+ native: "Melayu",
3602
+ direction: "ltr"
3603
+ },
3604
+ {
3605
+ code: "ms-arab",
3606
+ english: "Malay (Arabic)",
3607
+ native: "Melayu (Arab)",
3608
+ direction: "ltr"
3609
+ },
3610
+ {
3611
+ code: "mt",
3612
+ english: "Maltese",
3613
+ native: "Malti",
3614
+ direction: "ltr"
3615
+ },
3616
+ {
3617
+ code: "my",
3618
+ english: "Burmese",
3619
+ native: "\u1019\u103C\u1014\u103A\u1019\u102C",
3620
+ direction: "ltr"
3621
+ },
3622
+ {
3623
+ code: "nb",
3624
+ english: "Norwegian Bokm\xE5l",
3625
+ native: "norsk bokm\xE5l",
3626
+ direction: "ltr"
3627
+ },
3628
+ {
3629
+ code: "ne",
3630
+ english: "Nepali",
3631
+ native: "\u0928\u0947\u092A\u093E\u0932\u0940",
3632
+ direction: "ltr"
3633
+ },
3634
+ {
3635
+ code: "new",
3636
+ english: "Newari",
3637
+ native: "Newari",
3638
+ direction: "ltr"
3639
+ },
3640
+ {
3641
+ code: "nl",
3642
+ english: "Dutch",
3643
+ native: "Nederlands",
3644
+ direction: "ltr"
3645
+ },
3646
+ {
3647
+ code: "nl-be",
3648
+ english: "Flemish",
3649
+ native: "Vlaams",
3650
+ direction: "ltr"
3651
+ },
3652
+ {
3653
+ code: "no",
3654
+ english: "Norwegian",
3655
+ native: "norsk",
3656
+ direction: "ltr"
3657
+ },
3658
+ {
3659
+ code: "nr",
3660
+ english: "South Ndebele",
3661
+ native: "South Ndebele",
3662
+ direction: "ltr"
3663
+ },
3664
+ {
3665
+ code: "nso",
3666
+ english: "Northern Sotho",
3667
+ native: "Northern Sotho",
3668
+ direction: "ltr"
3669
+ },
3670
+ {
3671
+ code: "nus",
3672
+ english: "Nuer",
3673
+ native: "Thok Nath",
3674
+ direction: "ltr"
3675
+ },
3676
+ {
3677
+ code: "ny",
3678
+ english: "Nyanja",
3679
+ native: "Nyanja",
3680
+ direction: "ltr"
3681
+ },
3682
+ {
3683
+ code: "oc",
3684
+ english: "Occitan",
3685
+ native: "occitan",
3686
+ direction: "ltr"
3687
+ },
3688
+ {
3689
+ code: "om",
3690
+ english: "Oromo",
3691
+ native: "Oromoo",
3692
+ direction: "ltr"
3693
+ },
3694
+ {
3695
+ code: "or",
3696
+ english: "Odia",
3697
+ native: "\u0B13\u0B21\u0B3C\u0B3F\u0B06",
3698
+ direction: "ltr"
3699
+ },
3700
+ {
3701
+ code: "pa",
3702
+ english: "Punjabi",
3703
+ native: "\u0A2A\u0A70\u0A1C\u0A3E\u0A2C\u0A40",
3704
+ direction: "ltr"
3705
+ },
3706
+ {
3707
+ code: "pa-arab",
3708
+ english: "Punjabi (Arabic)",
3709
+ native: "\u067E\u0646\u062C\u0627\u0628\u06CC (\u0639\u0631\u0628\u06CC)",
3710
+ direction: "ltr"
3711
+ },
3712
+ {
3713
+ code: "pa-pk",
3714
+ english: "Punjabi (Pakistan)",
3715
+ native: "\u067E\u0646\u062C\u0627\u0628\u06CC (\u067E\u0627\u06A9\u0633\u062A\u0627\u0646)",
3716
+ direction: "ltr"
3717
+ },
3718
+ {
3719
+ code: "pag",
3720
+ english: "Pangasinan",
3721
+ native: "Pangasinan",
3722
+ direction: "ltr"
3723
+ },
3724
+ {
3725
+ code: "pam",
3726
+ english: "Pampanga",
3727
+ native: "Pampanga",
3728
+ direction: "ltr"
3729
+ },
3730
+ {
3731
+ code: "pap",
3732
+ english: "Papiamento",
3733
+ native: "Papiamento",
3734
+ direction: "ltr"
3735
+ },
3736
+ {
3737
+ code: "pl",
3738
+ english: "Polish",
3739
+ native: "polski",
3740
+ direction: "ltr"
3741
+ },
3742
+ {
3743
+ code: "ps",
3744
+ english: "Pashto",
3745
+ native: "\u067E\u069A\u062A\u0648",
3746
+ direction: "rtl"
3747
+ },
3748
+ {
3749
+ code: "pt",
3750
+ english: "Portuguese",
3751
+ native: "portugu\xEAs",
3752
+ direction: "ltr"
3753
+ },
3754
+ {
3755
+ code: "pt-br",
3756
+ english: "Brazilian Portuguese",
3757
+ native: "portugu\xEAs (Brasil)",
3758
+ direction: "ltr"
3759
+ },
3760
+ {
3761
+ code: "pt-pt",
3762
+ english: "European Portuguese",
3763
+ native: "portugu\xEAs europeu",
3764
+ direction: "ltr"
3765
+ },
3766
+ {
3767
+ code: "qu",
3768
+ english: "Quechua",
3769
+ native: "Runasimi",
3770
+ direction: "ltr"
3771
+ },
3772
+ {
3773
+ code: "rn",
3774
+ english: "Rundi",
3775
+ native: "Ikirundi",
3776
+ direction: "ltr"
3777
+ },
3778
+ {
3779
+ code: "ro",
3780
+ english: "Romanian",
3781
+ native: "rom\xE2n\u0103",
3782
+ direction: "ltr"
3783
+ },
3784
+ {
3785
+ code: "rom",
3786
+ english: "Romany",
3787
+ native: "Romany",
3788
+ direction: "ltr"
3789
+ },
3790
+ {
3791
+ code: "ru",
3792
+ english: "Russian",
3793
+ native: "\u0440\u0443\u0441\u0441\u043A\u0438\u0439",
3794
+ direction: "ltr"
3795
+ },
3796
+ {
3797
+ code: "rw",
3798
+ english: "Kinyarwanda",
3799
+ native: "Kinyarwanda",
3800
+ direction: "ltr"
3801
+ },
3802
+ {
3803
+ code: "sa",
3804
+ english: "Sanskrit",
3805
+ native: "\u0938\u0902\u0938\u094D\u0915\u0943\u0924 \u092D\u093E\u0937\u093E",
3806
+ direction: "ltr"
3807
+ },
3808
+ {
3809
+ code: "scn",
3810
+ english: "Sicilian",
3811
+ native: "Sicilian",
3812
+ direction: "ltr"
3813
+ },
3814
+ {
3815
+ code: "sd",
3816
+ english: "Sindhi",
3817
+ native: "\u0633\u0646\u068C\u064A",
3818
+ direction: "rtl"
3819
+ },
3820
+ {
3821
+ code: "sg",
3822
+ english: "Sango",
3823
+ native: "S\xE4ng\xF6",
3824
+ direction: "ltr"
3825
+ },
3826
+ {
3827
+ code: "shn",
3828
+ english: "Shan",
3829
+ native: "Shan",
3830
+ direction: "ltr"
3831
+ },
3832
+ {
3833
+ code: "si",
3834
+ english: "Sinhala",
3835
+ native: "\u0DC3\u0DD2\u0D82\u0DC4\u0DBD",
3836
+ direction: "ltr"
3837
+ },
3838
+ {
3839
+ code: "sk",
3840
+ english: "Slovak",
3841
+ native: "sloven\u010Dina",
3842
+ direction: "ltr"
3843
+ },
3844
+ {
3845
+ code: "sl",
3846
+ english: "Slovenian",
3847
+ native: "sloven\u0161\u010Dina",
3848
+ direction: "ltr"
3849
+ },
3850
+ {
3851
+ code: "sm",
3852
+ english: "Samoan",
3853
+ native: "Samoan",
3854
+ direction: "ltr"
3855
+ },
3856
+ {
3857
+ code: "sn",
3858
+ english: "Shona",
3859
+ native: "chiShona",
3860
+ direction: "ltr"
3861
+ },
3862
+ {
3863
+ code: "so",
3864
+ english: "Somali",
3865
+ native: "Soomaali",
3866
+ direction: "ltr"
3867
+ },
3868
+ {
3869
+ code: "sq",
3870
+ english: "Albanian",
3871
+ native: "shqip",
3872
+ direction: "ltr"
3873
+ },
3874
+ {
3875
+ code: "sr",
3876
+ english: "Serbian",
3877
+ native: "\u0441\u0440\u043F\u0441\u043A\u0438",
3878
+ direction: "ltr"
3879
+ },
3880
+ {
3881
+ code: "ss",
3882
+ english: "Swati",
3883
+ native: "Swati",
3884
+ direction: "ltr"
3885
+ },
3886
+ {
3887
+ code: "st",
3888
+ english: "Southern Sotho",
3889
+ native: "Southern Sotho",
3890
+ direction: "ltr"
3891
+ },
3892
+ {
3893
+ code: "su",
3894
+ english: "Sundanese",
3895
+ native: "Basa Sunda",
3896
+ direction: "ltr"
3897
+ },
3898
+ {
3899
+ code: "sv",
3900
+ english: "Swedish",
3901
+ native: "svenska",
3902
+ direction: "ltr"
3903
+ },
3904
+ {
3905
+ code: "sw",
3906
+ english: "Swahili",
3907
+ native: "Kiswahili",
3908
+ direction: "ltr"
3909
+ },
3910
+ {
3911
+ code: "szl",
3912
+ english: "Silesian",
3913
+ native: "\u015Bl\u014Dnski",
3914
+ direction: "ltr"
3915
+ },
3916
+ {
3917
+ code: "ta",
3918
+ english: "Tamil",
3919
+ native: "\u0BA4\u0BAE\u0BBF\u0BB4\u0BCD",
3920
+ direction: "ltr"
3921
+ },
3922
+ {
3923
+ code: "te",
3924
+ english: "Telugu",
3925
+ native: "\u0C24\u0C46\u0C32\u0C41\u0C17\u0C41",
3926
+ direction: "ltr"
3927
+ },
3928
+ {
3929
+ code: "tet",
3930
+ english: "Tetum",
3931
+ native: "Tetum",
3932
+ direction: "ltr"
3933
+ },
3934
+ {
3935
+ code: "tg",
3936
+ english: "Tajik",
3937
+ native: "\u0442\u043E\u04B7\u0438\u043A\u04E3",
3938
+ direction: "ltr"
3939
+ },
3940
+ {
3941
+ code: "th",
3942
+ english: "Thai",
3943
+ native: "\u0E44\u0E17\u0E22",
3944
+ direction: "ltr"
3945
+ },
3946
+ {
3947
+ code: "ti",
3948
+ english: "Tigrinya",
3949
+ native: "\u1275\u130D\u122D\u129B",
3950
+ direction: "ltr"
3951
+ },
3952
+ {
3953
+ code: "tk",
3954
+ english: "Turkmen",
3955
+ native: "t\xFCrkmen dili",
3956
+ direction: "ltr"
3957
+ },
3958
+ {
3959
+ code: "tl",
3960
+ english: "Filipino",
3961
+ native: "Filipino",
3962
+ direction: "ltr"
3963
+ },
3964
+ {
3965
+ code: "tn",
3966
+ english: "Tswana",
3967
+ native: "Tswana",
3968
+ direction: "ltr"
3969
+ },
3970
+ {
3971
+ code: "tr",
3972
+ english: "Turkish",
3973
+ native: "T\xFCrk\xE7e",
3974
+ direction: "ltr"
3975
+ },
3976
+ {
3977
+ code: "ts",
3978
+ english: "Tsonga",
3979
+ native: "Tsonga",
3980
+ direction: "ltr"
3981
+ },
3982
+ {
3983
+ code: "tt",
3984
+ english: "Tatar",
3985
+ native: "\u0442\u0430\u0442\u0430\u0440",
3986
+ direction: "ltr"
3987
+ },
3988
+ {
3989
+ code: "ug",
3990
+ english: "Uyghur",
3991
+ native: "\u0626\u06C7\u064A\u063A\u06C7\u0631\u0686\u06D5",
3992
+ direction: "rtl"
3993
+ },
3994
+ {
3995
+ code: "uk",
3996
+ english: "Ukrainian",
3997
+ native: "\u0443\u043A\u0440\u0430\u0457\u043D\u0441\u044C\u043A\u0430",
3998
+ direction: "ltr"
3999
+ },
4000
+ {
4001
+ code: "ur",
4002
+ english: "Urdu",
4003
+ native: "\u0627\u0631\u062F\u0648",
4004
+ direction: "rtl"
4005
+ },
4006
+ {
4007
+ code: "uz",
4008
+ english: "Uzbek",
4009
+ native: "o\u2018zbek",
4010
+ direction: "ltr"
4011
+ },
4012
+ {
4013
+ code: "vi",
4014
+ english: "Vietnamese",
4015
+ native: "Ti\u1EBFng Vi\u1EC7t",
4016
+ direction: "ltr"
4017
+ },
4018
+ {
4019
+ code: "xh",
4020
+ english: "Xhosa",
4021
+ native: "IsiXhosa",
4022
+ direction: "ltr"
4023
+ },
4024
+ {
4025
+ code: "yi",
4026
+ english: "Yiddish",
4027
+ native: "\u05D9\u05D9\u05B4\u05D3\u05D9\u05E9",
4028
+ direction: "rtl"
4029
+ },
4030
+ {
4031
+ code: "yo",
4032
+ english: "Yoruba",
4033
+ native: "\xC8d\xE8 Yor\xF9b\xE1",
4034
+ direction: "ltr"
4035
+ },
4036
+ {
4037
+ code: "yua",
4038
+ english: "yua",
4039
+ native: "yua",
4040
+ direction: "ltr"
4041
+ },
4042
+ {
4043
+ code: "yue",
4044
+ english: "Cantonese",
4045
+ native: "\u7CB5\u8A9E",
4046
+ direction: "ltr"
4047
+ },
4048
+ {
4049
+ code: "zh",
4050
+ english: "Chinese",
4051
+ native: "\u4E2D\u6587",
4052
+ direction: "ltr"
4053
+ },
4054
+ {
4055
+ code: "zh-cn",
4056
+ english: "Chinese (China)",
4057
+ native: "\u4E2D\u6587\uFF08\u4E2D\u56FD\uFF09",
4058
+ direction: "ltr"
4059
+ },
4060
+ {
4061
+ code: "zh-hans",
4062
+ english: "Simplified Chinese",
4063
+ native: "\u7B80\u4F53\u4E2D\u6587",
4064
+ direction: "ltr"
4065
+ },
4066
+ {
4067
+ code: "zh-hant",
4068
+ english: "Traditional Chinese",
4069
+ native: "\u7E41\u9AD4\u4E2D\u6587",
4070
+ direction: "ltr"
4071
+ },
4072
+ {
4073
+ code: "zh-hk",
4074
+ english: "Chinese (Hong Kong SAR China)",
4075
+ native: "\u4E2D\u6587\uFF08\u4E2D\u570B\u9999\u6E2F\u7279\u5225\u884C\u653F\u5340\uFF09",
4076
+ direction: "ltr"
4077
+ },
4078
+ {
4079
+ code: "zh-tw",
4080
+ english: "Chinese (Taiwan)",
4081
+ native: "\u4E2D\u6587\uFF08\u53F0\u7063\uFF09",
4082
+ direction: "ltr"
4083
+ },
4084
+ {
4085
+ code: "zu",
4086
+ english: "Zulu",
4087
+ native: "isiZulu",
4088
+ direction: "ltr"
4089
+ }
4090
+ ];
4091
+
4092
+ // src/shared/languages/catalog/index.ts
4093
+ var generatedLanguageCatalog = languages_default;
4094
+ function buildLanguageCatalog(raw) {
4095
+ return Object.freeze(raw.map((r) => ({ ...r, code: normalizeLanguageCode(r.code) })));
4096
+ }
4097
+ function filterLanguageCatalog(catalog, filter) {
4098
+ const all = [...catalog];
4099
+ const q = filter?.trim().toLowerCase();
4100
+ if (!q) return all.sort((a, b) => a.code.localeCompare(b.code));
4101
+ return all.filter(
4102
+ (r) => r.code.includes(q) || r.english.toLowerCase().includes(q) || r.native.toLowerCase().includes(q)
4103
+ ).sort((a, b) => a.code.localeCompare(b.code));
4104
+ }
4105
+ function getLanguageByCodeFromCatalog(catalog, code) {
4106
+ const n = normalizeLanguageCode(code);
4107
+ return catalog.find((r) => r.code === n);
4108
+ }
4109
+ function suggestCatalogCodesForInvalidInputFromCatalog(catalog, code, maxCodesInCatalogHint = 5) {
4110
+ const n = normalizeLanguageCode(code);
4111
+ const all = [...catalog].sort((a, b) => a.code.localeCompare(b.code));
4112
+ const out = [];
4113
+ const seen = /* @__PURE__ */ new Set();
4114
+ const push = (c) => {
4115
+ if (!seen.has(c)) {
4116
+ seen.add(c);
4117
+ out.push(c);
4118
+ }
4119
+ };
4120
+ for (const r of filterLanguageCatalog(catalog, n)) {
4121
+ push(r.code);
4122
+ if (out.length >= maxCodesInCatalogHint) return out;
4123
+ }
4124
+ if (n.length >= 2) {
4125
+ const prefix = n.slice(0, 2);
4126
+ for (const r of all) {
4127
+ if (r.code.startsWith(prefix)) push(r.code);
4128
+ if (out.length >= maxCodesInCatalogHint) return out;
4129
+ }
4130
+ }
4131
+ for (const r of all) {
4132
+ push(r.code);
4133
+ if (out.length >= maxCodesInCatalogHint) return out;
4134
+ }
4135
+ return out;
4136
+ }
4137
+
4138
+ // src/shared/constants/index.ts
4139
+ var constants_exports = {};
4140
+ __export(constants_exports, {
4141
+ ANALYSIS_BASENAME: () => ANALYSIS_BASENAME,
4142
+ CACHE_PROFILE_DEFAULTS: () => CACHE_PROFILE_DEFAULTS,
4143
+ CACHE_SCHEMA_VERSION: () => CACHE_SCHEMA_VERSION,
4144
+ DEFAULT_CACHE_PROFILE_ID: () => DEFAULT_CACHE_PROFILE_ID,
4145
+ DEFAULT_HEAL_EVERY_RUNS: () => DEFAULT_HEAL_EVERY_RUNS,
4146
+ DEFAULT_LIST_TOP: () => DEFAULT_LIST_TOP,
4147
+ DEFAULT_MAX_SHARE_JSON_BYTES: () => DEFAULT_MAX_SHARE_JSON_BYTES,
4148
+ DEFAULT_MISSING_LEAF_PLACEHOLDER: () => DEFAULT_MISSING_LEAF_PLACEHOLDER,
4149
+ DEFAULT_WORKER_API_URL: () => DEFAULT_WORKER_API_URL,
4150
+ DEMO_REPORT_URL: () => DEMO_REPORT_URL,
4151
+ DEMO_WEB_APP_BASE: () => DEMO_WEB_APP_BASE,
4152
+ DOCS_ISSUES_PAGE_PATH: () => DOCS_ISSUES_PAGE_PATH,
4153
+ DOCS_SITE_BASE: () => DOCS_SITE_BASE,
4154
+ DOCS_SITE_ORIGIN: () => DOCS_SITE_ORIGIN,
4155
+ ENV_TRANSLATE_DEEPL_API_KEY: () => ENV_TRANSLATE_DEEPL_API_KEY,
4156
+ ENV_TRANSLATE_LIBRE_URL: () => ENV_TRANSLATE_LIBRE_URL,
4157
+ ENV_TRANSLATE_LLM_API_KEY: () => ENV_TRANSLATE_LLM_API_KEY,
4158
+ ENV_TRANSLATE_LLM_BASE_URL: () => ENV_TRANSLATE_LLM_BASE_URL,
4159
+ ENV_TRANSLATE_LLM_MODEL: () => ENV_TRANSLATE_LLM_MODEL,
4160
+ ENV_TRANSLATE_MAX_WORKERS: () => ENV_TRANSLATE_MAX_WORKERS,
4161
+ ENV_TRANSLATE_PROVIDER: () => ENV_TRANSLATE_PROVIDER,
4162
+ GITHUB_BASE: () => GITHUB_BASE,
4163
+ GITHUB_DOCS_BASE: () => GITHUB_DOCS_BASE,
4164
+ GITHUB_DOCS_TREE_BASE: () => GITHUB_DOCS_TREE_BASE,
4165
+ GITHUB_OWNER: () => GITHUB_OWNER,
4166
+ GITHUB_REPO: () => GITHUB_REPO,
4167
+ GITHUB_REPO_URL: () => GITHUB_REPO_URL,
4168
+ HOSTED_PROJECT_SNAPSHOT_SCHEMA_VERSION: () => HOSTED_PROJECT_SNAPSHOT_SCHEMA_VERSION,
4169
+ I18NPRUNE_CONFIG_BASENAME: () => I18NPRUNE_CONFIG_BASENAME,
4170
+ I18NPRUNE_CONFIG_JSON_FILE_NAME: () => I18NPRUNE_CONFIG_JSON_FILE_NAME,
4171
+ I18NPRUNE_CONFIG_SCRIPT_FILE_NAMES: () => I18NPRUNE_CONFIG_SCRIPT_FILE_NAMES,
4172
+ I18NPRUNE_CONFIG_SCRIPT_FILE_NAMES_SET: () => I18NPRUNE_CONFIG_SCRIPT_FILE_NAMES_SET,
4173
+ I18NPRUNE_CONFIG_SNAPSHOT_FILE_NAMES: () => I18NPRUNE_CONFIG_SNAPSHOT_FILE_NAMES,
4174
+ I18NPRUNE_CONFIG_SNAPSHOT_FILE_NAMES_SET: () => I18NPRUNE_CONFIG_SNAPSHOT_FILE_NAMES_SET,
4175
+ ISSUE_CLEANUP_RIPGREP_UNAVAILABLE: () => ISSUE_CLEANUP_RIPGREP_UNAVAILABLE,
4176
+ ISSUE_CLEANUP_UNCERTAIN_PATHS_EXCLUDED: () => ISSUE_CLEANUP_UNCERTAIN_PATHS_EXCLUDED,
4177
+ ISSUE_CLI_INVALID_JSON_PRETTY: () => ISSUE_CLI_INVALID_JSON_PRETTY,
4178
+ ISSUE_CONFIG_INVALID: () => ISSUE_CONFIG_INVALID,
4179
+ ISSUE_CONFIG_LOAD_FAILED: () => ISSUE_CONFIG_LOAD_FAILED,
4180
+ ISSUE_CONFIG_MISSING: () => ISSUE_CONFIG_MISSING,
4181
+ ISSUE_CONTEXT_DISCOVERY_WARNING: () => ISSUE_CONTEXT_DISCOVERY_WARNING,
4182
+ ISSUE_CONTEXT_RESOLUTION_FAILED: () => ISSUE_CONTEXT_RESOLUTION_FAILED,
4183
+ ISSUE_DOCTOR_CONFIG_MISSING_FILE: () => ISSUE_DOCTOR_CONFIG_MISSING_FILE,
4184
+ ISSUE_DOCTOR_PATHS_DIRECTORIES_MISSING: () => ISSUE_DOCTOR_PATHS_DIRECTORIES_MISSING,
4185
+ ISSUE_DOCTOR_PATHS_SOURCE_LOCALE_MISSING: () => ISSUE_DOCTOR_PATHS_SOURCE_LOCALE_MISSING,
4186
+ ISSUE_DOCTOR_RUNTIME_UNSUPPORTED_NODE: () => ISSUE_DOCTOR_RUNTIME_UNSUPPORTED_NODE,
4187
+ ISSUE_DOCTOR_TOOLS_RG_NOT_ON_PATH: () => ISSUE_DOCTOR_TOOLS_RG_NOT_ON_PATH,
4188
+ ISSUE_GENERATE_SOURCE_EMPTY_STRING_LEAVES: () => ISSUE_GENERATE_SOURCE_EMPTY_STRING_LEAVES,
4189
+ ISSUE_GENERATE_TRANSLATE_NETWORK_ERROR: () => ISSUE_GENERATE_TRANSLATE_NETWORK_ERROR,
4190
+ ISSUE_GENERATE_TRANSLATE_RATE_LIMITED: () => ISSUE_GENERATE_TRANSLATE_RATE_LIMITED,
4191
+ ISSUE_GENERATE_USAGE: () => ISSUE_GENERATE_USAGE,
4192
+ ISSUE_IO_READ_FAILED: () => ISSUE_IO_READ_FAILED,
4193
+ ISSUE_LANGUAGES_EMPTY_FILTER: () => ISSUE_LANGUAGES_EMPTY_FILTER,
4194
+ ISSUE_LANGUAGES_UNSUPPORTED_LANGUAGE_CODE: () => ISSUE_LANGUAGES_UNSUPPORTED_LANGUAGE_CODE,
4195
+ ISSUE_LOCALES_USAGE: () => ISSUE_LOCALES_USAGE,
4196
+ ISSUE_LOCALE_SOURCE_PLACEHOLDER_LEAVES: () => ISSUE_LOCALE_SOURCE_PLACEHOLDER_LEAVES,
4197
+ ISSUE_LOCALE_TARGET_NOT_FOUND: () => ISSUE_LOCALE_TARGET_NOT_FOUND,
4198
+ ISSUE_LOCALE_TARGET_PLACEHOLDER_LEAVES: () => ISSUE_LOCALE_TARGET_PLACEHOLDER_LEAVES,
4199
+ ISSUE_MISSING_PATHS_NOT_IN_SCAN: () => ISSUE_MISSING_PATHS_NOT_IN_SCAN,
4200
+ ISSUE_PATCHING_CATALOG_MISMATCH_DIRECTION: () => ISSUE_PATCHING_CATALOG_MISMATCH_DIRECTION,
4201
+ ISSUE_PATCHING_CATALOG_MISMATCH_ENGLISH: () => ISSUE_PATCHING_CATALOG_MISMATCH_ENGLISH,
4202
+ ISSUE_PATCHING_CATALOG_MISMATCH_NATIVE: () => ISSUE_PATCHING_CATALOG_MISMATCH_NATIVE,
4203
+ ISSUE_PATCHING_CONFIG_INVALID_SCHEMA: () => ISSUE_PATCHING_CONFIG_INVALID_SCHEMA,
4204
+ ISSUE_PATCHING_CONFIG_LOCALE_MISSING_FILE: () => ISSUE_PATCHING_CONFIG_LOCALE_MISSING_FILE,
4205
+ ISSUE_PATCHING_CONFIG_PARSE_FAILED: () => ISSUE_PATCHING_CONFIG_PARSE_FAILED,
4206
+ ISSUE_PATCHING_CONFIG_SECTION_INCOMPLETE: () => ISSUE_PATCHING_CONFIG_SECTION_INCOMPLETE,
4207
+ ISSUE_PATCHING_CONFIG_SIZE_ANOMALY: () => ISSUE_PATCHING_CONFIG_SIZE_ANOMALY,
4208
+ ISSUE_PATCHING_CONFIG_TOO_LARGE: () => ISSUE_PATCHING_CONFIG_TOO_LARGE,
4209
+ ISSUE_PATCHING_FILE_LOCALE_MISSING_CONFIG: () => ISSUE_PATCHING_FILE_LOCALE_MISSING_CONFIG,
4210
+ ISSUE_PATHS_NETWORK_DRIVE: () => ISSUE_PATHS_NETWORK_DRIVE,
4211
+ ISSUE_PATHS_WINDOWS_LONG_PATH: () => ISSUE_PATHS_WINDOWS_LONG_PATH,
4212
+ ISSUE_PATHS_WINDOWS_RESERVED_NAME: () => ISSUE_PATHS_WINDOWS_RESERVED_NAME,
4213
+ ISSUE_PROJECT_CONFIG_FILE_MISSING: () => ISSUE_PROJECT_CONFIG_FILE_MISSING,
4214
+ ISSUE_PROJECT_HOSTED_SNAPSHOT_INVALID: () => ISSUE_PROJECT_HOSTED_SNAPSHOT_INVALID,
4215
+ ISSUE_PROJECT_HOSTED_SNAPSHOT_SCHEMA_VERSION: () => ISSUE_PROJECT_HOSTED_SNAPSHOT_SCHEMA_VERSION,
4216
+ ISSUE_PROJECT_LOCALES_DIR_UNAVAILABLE: () => ISSUE_PROJECT_LOCALES_DIR_UNAVAILABLE,
4217
+ ISSUE_PROJECT_LOCALES_SOURCE_NOT_IN_BUNDLE: () => ISSUE_PROJECT_LOCALES_SOURCE_NOT_IN_BUNDLE,
4218
+ ISSUE_PROJECT_LOCALES_SOURCE_NOT_LANGUAGE_CODE: () => ISSUE_PROJECT_LOCALES_SOURCE_NOT_LANGUAGE_CODE,
4219
+ ISSUE_PROJECT_LOCALES_STRUCTURE_REQUIRED: () => ISSUE_PROJECT_LOCALES_STRUCTURE_REQUIRED,
4220
+ ISSUE_PROJECT_SOURCE_LOCALE_INVALID_JSON: () => ISSUE_PROJECT_SOURCE_LOCALE_INVALID_JSON,
4221
+ ISSUE_PROJECT_SOURCE_LOCALE_INVALID_SHAPE: () => ISSUE_PROJECT_SOURCE_LOCALE_INVALID_SHAPE,
4222
+ ISSUE_PROJECT_SOURCE_LOCALE_MISSING_SEGMENTS: () => ISSUE_PROJECT_SOURCE_LOCALE_MISSING_SEGMENTS,
4223
+ ISSUE_PROJECT_SOURCE_LOCALE_NOT_FOUND: () => ISSUE_PROJECT_SOURCE_LOCALE_NOT_FOUND,
4224
+ ISSUE_PROJECT_SOURCE_LOCALE_UNAVAILABLE: () => ISSUE_PROJECT_SOURCE_LOCALE_UNAVAILABLE,
4225
+ ISSUE_PROJECT_SRC_ROOT_UNAVAILABLE: () => ISSUE_PROJECT_SRC_ROOT_UNAVAILABLE,
4226
+ ISSUE_PROJECT_UPLOAD_CONFIG_JSON_INVALID: () => ISSUE_PROJECT_UPLOAD_CONFIG_JSON_INVALID,
4227
+ ISSUE_PROJECT_UPLOAD_CONFIG_REQUIRED: () => ISSUE_PROJECT_UPLOAD_CONFIG_REQUIRED,
4228
+ ISSUE_QUALITY_ENGLISH_IDENTICAL_LEAVES: () => ISSUE_QUALITY_ENGLISH_IDENTICAL_LEAVES,
4229
+ ISSUE_REPORT_HOSTED_REPORT_INVALID: () => ISSUE_REPORT_HOSTED_REPORT_INVALID,
4230
+ ISSUE_REPORT_INVALID_FORMAT: () => ISSUE_REPORT_INVALID_FORMAT,
4231
+ ISSUE_SCAN_DYNAMIC_KEY_SITES: () => ISSUE_SCAN_DYNAMIC_KEY_SITES,
4232
+ ISSUE_SHARE_CACHE_EMPTY: () => ISSUE_SHARE_CACHE_EMPTY,
4233
+ ISSUE_SHARE_CACHE_ENTRY_NOT_FOUND: () => ISSUE_SHARE_CACHE_ENTRY_NOT_FOUND,
4234
+ ISSUE_SHARE_JSON_REPAIRED: () => ISSUE_SHARE_JSON_REPAIRED,
4235
+ ISSUE_SHARE_JSON_WRITE_FAILED: () => ISSUE_SHARE_JSON_WRITE_FAILED,
4236
+ ISSUE_SHARE_PREPARE_ANALYSIS_FAILED: () => ISSUE_SHARE_PREPARE_ANALYSIS_FAILED,
4237
+ ISSUE_SHARE_PREPARE_NOTHING_REQUESTED: () => ISSUE_SHARE_PREPARE_NOTHING_REQUESTED,
4238
+ ISSUE_SHARE_PREPARE_REPORT_FROM_ARCHIVE_FAILED: () => ISSUE_SHARE_PREPARE_REPORT_FROM_ARCHIVE_FAILED,
4239
+ ISSUE_SHARE_PREPARE_REPORT_HOST_REQUIRED: () => ISSUE_SHARE_PREPARE_REPORT_HOST_REQUIRED,
4240
+ ISSUE_SHARE_REMOTE_ERROR: () => ISSUE_SHARE_REMOTE_ERROR,
4241
+ ISSUE_SHARE_REMOTE_PAYLOAD_TOO_LARGE: () => ISSUE_SHARE_REMOTE_PAYLOAD_TOO_LARGE,
4242
+ ISSUE_SHARE_REMOTE_PROJECT_NOT_FOUND: () => ISSUE_SHARE_REMOTE_PROJECT_NOT_FOUND,
4243
+ ISSUE_SHARE_REMOTE_REPORT_NOT_FOUND: () => ISSUE_SHARE_REMOTE_REPORT_NOT_FOUND,
4244
+ ISSUE_SHARE_REMOTE_REPORT_REJECTED: () => ISSUE_SHARE_REMOTE_REPORT_REJECTED,
4245
+ ISSUE_SHARE_REMOTE_UNAVAILABLE: () => ISSUE_SHARE_REMOTE_UNAVAILABLE,
4246
+ ISSUE_SHARE_REMOTE_UPLOAD_REJECTED: () => ISSUE_SHARE_REMOTE_UPLOAD_REJECTED,
4247
+ ISSUE_SHARE_SNAPSHOT_EMPTY: () => ISSUE_SHARE_SNAPSHOT_EMPTY,
4248
+ ISSUE_SHARE_STALE_CACHE_ROW_REMOVED: () => ISSUE_SHARE_STALE_CACHE_ROW_REMOVED,
4249
+ ISSUE_SHARE_ZIP_FAILED: () => ISSUE_SHARE_ZIP_FAILED,
4250
+ ISSUE_SYNC_LOCALE_FILE_NOT_FOUND: () => ISSUE_SYNC_LOCALE_FILE_NOT_FOUND,
4251
+ ISSUE_SYNC_METADATA_FLAG_CONFLICT: () => ISSUE_SYNC_METADATA_FLAG_CONFLICT,
4252
+ ISSUE_TRANSLATE_CONFIG_DEFAULT_APPLIED: () => ISSUE_TRANSLATE_CONFIG_DEFAULT_APPLIED,
4253
+ ISSUE_TRANSLATE_HANDOFF_NO_ELIGIBLE_PROVIDER: () => ISSUE_TRANSLATE_HANDOFF_NO_ELIGIBLE_PROVIDER,
4254
+ ISSUE_TRANSLATE_IDENTITY_STREAK_ABORT: () => ISSUE_TRANSLATE_IDENTITY_STREAK_ABORT,
4255
+ ISSUE_TRANSLATE_IDENTITY_STREAK_WARNING: () => ISSUE_TRANSLATE_IDENTITY_STREAK_WARNING,
4256
+ ISSUE_TRANSLATE_MISSING_CREDENTIALS: () => ISSUE_TRANSLATE_MISSING_CREDENTIALS,
4257
+ ISSUE_TRANSLATE_PROVIDER_NOT_IMPLEMENTED_YET: () => ISSUE_TRANSLATE_PROVIDER_NOT_IMPLEMENTED_YET,
4258
+ ISSUE_TRANSLATE_UNKNOWN_TRANSLATION_PROVIDER: () => ISSUE_TRANSLATE_UNKNOWN_TRANSLATION_PROVIDER,
4259
+ ISSUE_VALIDATE_DYNAMIC_KEY_SITES: () => ISSUE_VALIDATE_DYNAMIC_KEY_SITES,
4260
+ ISSUE_VALIDATE_MISSING_LITERAL_KEYS: () => ISSUE_VALIDATE_MISSING_LITERAL_KEYS,
4261
+ ISSUE_VALIDATE_SOURCE_LOCALE_READ_FAILED: () => ISSUE_VALIDATE_SOURCE_LOCALE_READ_FAILED,
4262
+ LICENSE_URL: () => LICENSE_URL,
4263
+ LIST_MORE_HINT: () => LIST_MORE_HINT,
4264
+ MAX_ANALYSIS_BYTES: () => MAX_ANALYSIS_BYTES,
4265
+ MAX_MISSING_TARGET_SUGGESTIONS: () => MAX_MISSING_TARGET_SUGGESTIONS,
4266
+ MAX_PROJECTS_INDEX_BYTES: () => MAX_PROJECTS_INDEX_BYTES,
4267
+ MAX_PROJECT_FILES_BYTES: () => MAX_PROJECT_FILES_BYTES,
4268
+ MAX_TRANSLATIONS_CACHE_BYTES: () => MAX_TRANSLATIONS_CACHE_BYTES,
4269
+ META_WORKER_URL: () => META_WORKER_URL,
4270
+ NPM_PACKAGE_NAME: () => NPM_PACKAGE_NAME,
4271
+ NPM_PACKAGE_URL: () => NPM_PACKAGE_URL,
4272
+ PROJECT_REPORT_KIND: () => PROJECT_REPORT_KIND,
4273
+ PROJECT_REPORT_SCHEMA_VERSION: () => PROJECT_REPORT_SCHEMA_VERSION,
4274
+ PROJECT_SHARE_PREPARED_MAX_BYTES: () => PROJECT_SHARE_PREPARED_MAX_BYTES,
4275
+ PROJECT_UPLOAD_MAX_FILES: () => PROJECT_UPLOAD_MAX_FILES,
4276
+ PROJECT_UPLOAD_MAX_TEXT_BYTES: () => PROJECT_UPLOAD_MAX_TEXT_BYTES,
4277
+ PROJECT_UPLOAD_MAX_ZIP_BYTES: () => PROJECT_UPLOAD_MAX_ZIP_BYTES,
4278
+ PROJECT_UPLOAD_ZIP_LIMITS: () => PROJECT_UPLOAD_ZIP_LIMITS,
4279
+ REPORT_INLINE_PAYLOAD_PLACEHOLDER: () => REPORT_INLINE_PAYLOAD_PLACEHOLDER,
4280
+ REPORT_SHARE_MAX_BYTES: () => REPORT_SHARE_MAX_BYTES,
4281
+ RESULT_API_VERSION: () => RESULT_API_VERSION,
4282
+ SDK_PACKAGE_NAME: () => SDK_PACKAGE_NAME,
4283
+ SDK_VERSION: () => SDK_VERSION,
4284
+ SHARE_BAK_DIRNAME: () => SHARE_BAK_DIRNAME,
4285
+ SHARE_CACHE_REASON_MESSAGES: () => SHARE_CACHE_REASON_MESSAGES,
4286
+ SHARE_JSON_BASENAME: () => SHARE_JSON_BASENAME,
4287
+ TRANSLATE_WORKERS_CAP: () => TRANSLATE_WORKERS_CAP,
4288
+ TRANSLATIONS_DIR: () => TRANSLATIONS_DIR,
4289
+ WORKER_IDLE_RETENTION_MS: () => WORKER_IDLE_RETENTION_MS,
4290
+ WORKER_INGEST_FORCE_QUERY: () => WORKER_INGEST_FORCE_QUERY,
4291
+ formatListOmittedSuffix: () => formatListOmittedSuffix,
4292
+ formatListShownOmitted: () => formatListShownOmitted
4293
+ });
4294
+
4295
+ // src/shared/constants/config.ts
4296
+ var I18NPRUNE_CONFIG_BASENAME = "i18nprune.config";
4297
+ var I18NPRUNE_CONFIG_SCRIPT_FILE_NAMES = [
4298
+ `${I18NPRUNE_CONFIG_BASENAME}.ts`,
4299
+ `${I18NPRUNE_CONFIG_BASENAME}.mts`,
4300
+ `${I18NPRUNE_CONFIG_BASENAME}.cts`,
4301
+ `${I18NPRUNE_CONFIG_BASENAME}.js`,
4302
+ `${I18NPRUNE_CONFIG_BASENAME}.mjs`,
4303
+ `${I18NPRUNE_CONFIG_BASENAME}.cjs`
4304
+ ];
4305
+ var I18NPRUNE_CONFIG_SCRIPT_FILE_NAMES_SET = new Set(I18NPRUNE_CONFIG_SCRIPT_FILE_NAMES);
4306
+ var I18NPRUNE_CONFIG_JSON_FILE_NAME = `${I18NPRUNE_CONFIG_BASENAME}.json`;
4307
+ var I18NPRUNE_CONFIG_SNAPSHOT_FILE_NAMES = [
4308
+ ...I18NPRUNE_CONFIG_SCRIPT_FILE_NAMES,
4309
+ I18NPRUNE_CONFIG_JSON_FILE_NAME
4310
+ ];
4311
+ var I18NPRUNE_CONFIG_SNAPSHOT_FILE_NAMES_SET = new Set(I18NPRUNE_CONFIG_SNAPSHOT_FILE_NAMES);
4312
+
4313
+ // src/shared/constants/listDisplay.ts
4314
+ var DEFAULT_LIST_TOP = 3;
4315
+ var LIST_MORE_HINT = "(use --full or --top <n>)";
4316
+ function formatListOmittedSuffix(omitted) {
4317
+ return `\u2026 ${String(omitted)} more ${LIST_MORE_HINT}`;
4318
+ }
4319
+ function formatListShownOmitted(prefix, omitted) {
4320
+ if (omitted <= 0) return prefix;
4321
+ return `${prefix} + ${formatListOmittedSuffix(omitted)}`;
4322
+ }
4323
+
4324
+ // src/shared/constants/sdk.ts
4325
+ var SDK_PACKAGE_NAME = "@i18nprune/core";
4326
+ var SDK_VERSION = "0.1.0";
4327
+
4328
+ // src/shared/constants/cache.ts
4329
+ var CACHE_SCHEMA_VERSION = 1;
4330
+ var DEFAULT_CACHE_PROFILE_ID = "balanced";
4331
+ var CACHE_PROFILE_DEFAULTS = {
4332
+ safe: {
4333
+ rebuild: "full",
4334
+ fullRescanThresholdPercent: 10,
4335
+ mode: "readWrite"
4336
+ },
4337
+ balanced: {
4338
+ rebuild: "partial",
4339
+ fullRescanThresholdPercent: 40,
4340
+ mode: "readWrite"
4341
+ },
4342
+ fast: {
4343
+ rebuild: "partial",
4344
+ fullRescanThresholdPercent: 70,
4345
+ mode: "readWrite"
4346
+ }
4347
+ };
4348
+ var ANALYSIS_BASENAME = "analysis.json";
4349
+ var TRANSLATIONS_DIR = "translations";
4350
+ var MAX_PROJECTS_INDEX_BYTES = 2 * 1024 * 1024;
4351
+ var MAX_PROJECT_FILES_BYTES = 32 * 1024 * 1024;
4352
+ var MAX_ANALYSIS_BYTES = 16 * 1024 * 1024;
4353
+ var MAX_TRANSLATIONS_CACHE_BYTES = 32 * 1024 * 1024;
4354
+ var DEFAULT_HEAL_EVERY_RUNS = 20;
4355
+
4356
+ // src/shared/constants/project.ts
4357
+ var PROJECT_UPLOAD_ZIP_LIMITS = {
4358
+ maxZipBytes: 50 * 1024 * 1024,
4359
+ maxFiles: 15e3,
4360
+ maxTextBytes: 60 * 1024 * 1024
4361
+ };
4362
+ var PROJECT_UPLOAD_MAX_ZIP_BYTES = PROJECT_UPLOAD_ZIP_LIMITS.maxZipBytes;
4363
+ var PROJECT_UPLOAD_MAX_FILES = PROJECT_UPLOAD_ZIP_LIMITS.maxFiles;
4364
+ var PROJECT_UPLOAD_MAX_TEXT_BYTES = PROJECT_UPLOAD_ZIP_LIMITS.maxTextBytes;
4365
+ var HOSTED_PROJECT_SNAPSHOT_SCHEMA_VERSION = 1;
4366
+
4367
+ // src/shared/constants/report.ts
4368
+ var PROJECT_REPORT_KIND = "i18nprune.projectReport";
4369
+ var PROJECT_REPORT_SCHEMA_VERSION = 1;
4370
+ var REPORT_INLINE_PAYLOAD_PLACEHOLDER = "__I18NPRUNE_REPORT__";
4371
+
4372
+ // src/shared/constants/share.ts
4373
+ var SHARE_JSON_BASENAME = "share.json";
4374
+ var SHARE_BAK_DIRNAME = "share.bak";
4375
+ var DEFAULT_MAX_SHARE_JSON_BYTES = 512 * 1024;
4376
+ var REPORT_SHARE_MAX_BYTES = 8 * 1024 * 1024;
4377
+ var PROJECT_SHARE_PREPARED_MAX_BYTES = PROJECT_UPLOAD_MAX_ZIP_BYTES;
4378
+ var SHARE_CACHE_REASON_MESSAGES = {
4379
+ cache_hit: "analysis cache hit",
4380
+ no_cache: "project cache is disabled",
4381
+ cache_unavailable: "project cache is unavailable",
4382
+ run_missing: "cached analysis run is missing",
4383
+ files_changed: "tracked files changed since last analysis",
4384
+ files_index_recovered: "cache files index was recovered",
4385
+ run_binding_stale: "cached analysis binding is stale",
4386
+ producer_succeeded: "analysis recomputed and cache updated",
4387
+ run_invalid: "cached analysis run is invalid",
4388
+ archive_ingest_no_project_cache: "archive uploads do not use persistent project cache"
4389
+ };
4390
+
4391
+ // src/shared/constants/worker.ts
4392
+ var WORKER_INGEST_FORCE_QUERY = "force";
4393
+ var WORKER_IDLE_RETENTION_MS = 7 * 24 * 60 * 60 * 1e3;
4394
+
4395
+ // src/shared/locales/targets/segmentWritePlan.ts
4396
+ function swapLocaleInSegmentRelativePath(input) {
4397
+ const target = normalizeLanguageCode(input.targetLocale);
4398
+ const rel = input.relativePath.replace(/\\/g, "/");
4399
+ if (input.structure === "locale_file") {
4400
+ if (rel.includes("/")) return null;
4401
+ return `${target}.json`;
4402
+ }
4403
+ if (input.structure === "locale_per_dir") {
4404
+ const slash = rel.indexOf("/");
4405
+ if (slash < 0) return null;
4406
+ const rest = rel.slice(slash + 1);
4407
+ if (!rest) return null;
4408
+ return `${target}/${rest}`;
4409
+ }
4410
+ if (input.structure === "feature_bundle") {
4411
+ const slash = rel.lastIndexOf("/");
4412
+ if (slash < 0) return null;
4413
+ const feature = rel.slice(0, slash);
4414
+ if (!feature) return null;
4415
+ return `${feature}/${target}.json`;
4416
+ }
4417
+ return null;
4418
+ }
4419
+ function segmentTargetFromRef(ref, role) {
4420
+ return {
4421
+ locale: normalizeLanguageCode(ref.locale),
4422
+ relativePath: ref.relativePath,
4423
+ absolutePath: ref.absolutePath,
4424
+ role
4425
+ };
4426
+ }
4427
+ function deriveTargetSegmentFromSource(ctx, layout, targetLocale) {
4428
+ const sourceRef = localeSegmentRefFromAbsolute({
4429
+ layout,
4430
+ path: ctx.adapters.path,
4431
+ absolutePath: ctx.adapters.path.resolve(ctx.paths.sourceLocale)
4432
+ });
4433
+ if (sourceRef === null) {
4434
+ throw new I18nPruneError(
4435
+ `generate: source locale path does not match layout mode=${layout.mode} structure=${layout.structure}: ${ctx.paths.sourceLocale}`,
4436
+ "USAGE"
4437
+ );
4438
+ }
4439
+ const nextRelative = swapLocaleInSegmentRelativePath({
4440
+ structure: layout.structure,
4441
+ relativePath: sourceRef.relativePath,
4442
+ targetLocale
4443
+ });
4444
+ if (nextRelative === null) {
4445
+ throw new I18nPruneError(
4446
+ `generate: cannot derive target segment from source ${sourceRef.relativePath} for structure=${layout.structure}`,
4447
+ "USAGE"
4448
+ );
4449
+ }
4450
+ const absolutePath = resolveLocaleSegmentAbsolutePath({
4451
+ layout,
4452
+ path: ctx.adapters.path,
4453
+ locale: targetLocale,
4454
+ segmentRelativePath: nextRelative
4455
+ });
4456
+ return {
4457
+ locale: normalizeLanguageCode(targetLocale),
4458
+ relativePath: nextRelative,
4459
+ absolutePath,
4460
+ role: "target"
4461
+ };
4462
+ }
4463
+ function listSourceLocaleWriteTargets(ctx) {
4464
+ const source = sourceLocaleCodeFromContext(ctx);
4465
+ return segmentsForLocaleCode(ctx, source).map((s) => segmentTargetFromRef(s, "source"));
4466
+ }
4467
+ function resolveTargetLocaleWritePlan(ctx, targetLocale) {
4468
+ const layout = resolveLocalesLayoutFromContext(ctx);
4469
+ const target = normalizeLanguageCode(targetLocale);
4470
+ const { fs } = ctx.adapters;
4471
+ if (layout.mode === "flat_file") {
4472
+ const existing = segmentsForLocaleCode(ctx, target);
4473
+ if (existing.length > 0) {
4474
+ const primary = primarySegmentForLocale(ctx, target);
4475
+ const segments2 = [segmentTargetFromRef(primary, "existing_target")];
4476
+ return {
4477
+ targetLocale: target,
4478
+ layout,
4479
+ segments: segments2,
4480
+ missingSegments: existsRuntimeFsSync(primary.absolutePath, fs) ? [] : segments2
4481
+ };
4482
+ }
4483
+ const derived = deriveTargetSegmentFromSource(ctx, layout, target);
4484
+ const missingSegments2 = existsRuntimeFsSync(derived.absolutePath, fs) ? [] : [derived];
4485
+ return { targetLocale: target, layout, segments: [derived], missingSegments: missingSegments2 };
4486
+ }
4487
+ const sourceSegments = listSourceLocaleWriteTargets(ctx);
4488
+ const existingByRel = new Map(
4489
+ segmentsForLocaleCode(ctx, target).map((s) => [s.relativePath, s])
4490
+ );
4491
+ const segments = [];
4492
+ for (const src of sourceSegments) {
4493
+ const targetRel = swapLocaleInSegmentRelativePath({
4494
+ structure: layout.structure,
4495
+ relativePath: src.relativePath,
4496
+ targetLocale: target
4497
+ });
4498
+ if (targetRel === null) {
4499
+ throw new I18nPruneError(
4500
+ `generate: cannot derive target segment from source ${src.relativePath} for structure=${layout.structure}`,
4501
+ "USAGE"
4502
+ );
4503
+ }
4504
+ const onDisk = existingByRel.get(targetRel);
4505
+ if (onDisk) {
4506
+ segments.push(segmentTargetFromRef(onDisk, "existing_target"));
4507
+ continue;
4508
+ }
4509
+ const absolutePath = resolveLocaleSegmentAbsolutePath({
4510
+ layout,
4511
+ path: ctx.adapters.path,
4512
+ locale: target,
4513
+ segmentRelativePath: targetRel
4514
+ });
4515
+ segments.push({
4516
+ locale: target,
4517
+ relativePath: targetRel,
4518
+ absolutePath,
4519
+ role: "target"
4520
+ });
4521
+ }
4522
+ segments.sort((a, b) => a.relativePath.localeCompare(b.relativePath));
4523
+ const missingSegments = segments.filter((s) => !existsRuntimeFsSync(s.absolutePath, fs));
4524
+ return { targetLocale: target, layout, segments, missingSegments };
4525
+ }
4526
+ function resolvePrimaryTargetWritePath(ctx, targetLocale) {
4527
+ const plan = resolveTargetLocaleWritePlan(ctx, targetLocale);
4528
+ const primary = plan.segments[0];
4529
+ if (!primary) {
4530
+ throw new I18nPruneError(`generate: no write path for target locale ${targetLocale}`, "USAGE");
4531
+ }
4532
+ return primary.absolutePath;
4533
+ }
4534
+
4535
+ // src/shared/locales/projection.ts
4536
+ function isPlainObject7(x) {
4537
+ return typeof x === "object" && x !== null && !Array.isArray(x);
4538
+ }
4539
+ function pushLeaf(out, leaf, winner) {
4540
+ const cur = out.get(leaf.path);
4541
+ if (!cur) {
4542
+ out.set(leaf.path, { leaf, winner });
4543
+ return { conflictsAdded: 0 };
4544
+ }
4545
+ if (cur.winner === "nested") {
4546
+ return { conflictsAdded: winner === "dotted" ? 1 : 0 };
4547
+ }
4548
+ if (winner === "nested") {
4549
+ out.set(leaf.path, { leaf, winner });
4550
+ return { conflictsAdded: 1 };
4551
+ }
4552
+ return { conflictsAdded: 0 };
4553
+ }
4554
+ function collectLeavesPreferNested(input) {
4555
+ let sawDottedKey = false;
4556
+ let conflicts = 0;
4557
+ const { root, prefix } = input;
4558
+ if (typeof root === "string") {
4559
+ if (prefix) {
4560
+ const { conflictsAdded } = pushLeaf(input.out, {
4561
+ path: prefix,
4562
+ value: root,
4563
+ shape: "legacy_string",
4564
+ confidence: null,
4565
+ needsReview: null
4566
+ }, input.winner);
4567
+ conflicts += conflictsAdded;
4568
+ }
4569
+ return { sawDottedKey, conflicts };
4570
+ }
4571
+ if (isStructuredLocaleLeafNode(root)) {
4572
+ if (prefix) {
4573
+ const { conflictsAdded } = pushLeaf(
4574
+ input.out,
4575
+ {
4576
+ path: prefix,
4577
+ value: root.value,
4578
+ shape: "legacy_string",
4579
+ confidence: null,
4580
+ needsReview: null
4581
+ },
4582
+ input.winner
4583
+ );
4584
+ conflicts += conflictsAdded;
4585
+ }
4586
+ return { sawDottedKey, conflicts };
4587
+ }
4588
+ if (Array.isArray(root)) {
4589
+ root.forEach((item, i) => {
4590
+ const p = prefix ? `${prefix}[${i}]` : `[${i}]`;
4591
+ const r = collectLeavesPreferNested({ root: item, prefix: p, out: input.out, winner: input.winner });
4592
+ if (r.sawDottedKey) sawDottedKey = true;
4593
+ conflicts += r.conflicts;
4594
+ });
4595
+ return { sawDottedKey, conflicts };
4596
+ }
4597
+ if (isPlainObject7(root)) {
4598
+ const keys = Object.keys(root);
4599
+ const nestedKeys = keys.filter((k) => !k.includes("."));
4600
+ const dottedKeys = keys.filter((k) => k.includes("."));
4601
+ for (const k of nestedKeys) {
4602
+ const p = prefix ? `${prefix}.${k}` : k;
4603
+ const r = collectLeavesPreferNested({ root: root[k], prefix: p, out: input.out, winner: input.winner });
4604
+ if (r.sawDottedKey) sawDottedKey = true;
4605
+ conflicts += r.conflicts;
4606
+ }
4607
+ for (const k of dottedKeys) {
4608
+ sawDottedKey = true;
4609
+ const p = prefix ? `${prefix}.${k}` : k;
4610
+ const r = collectLeavesPreferNested({ root: root[k], prefix: p, out: input.out, winner: "dotted" });
4611
+ if (r.sawDottedKey) sawDottedKey = true;
4612
+ conflicts += r.conflicts;
4613
+ }
4614
+ }
4615
+ return { sawDottedKey, conflicts };
4616
+ }
4617
+ function projectLocaleLeaves(localeJson) {
4618
+ const tmp = /* @__PURE__ */ new Map();
4619
+ const r = collectLeavesPreferNested({ root: localeJson, prefix: "", out: tmp, winner: "nested" });
4620
+ const byPath = /* @__PURE__ */ new Map();
4621
+ for (const [k, v] of tmp) byPath.set(k, v.leaf);
4622
+ return { byPath, sawDottedKey: r.sawDottedKey, conflicts: r.conflicts };
4623
+ }
4624
+ function getProjectedLeafString(proj, path) {
4625
+ const leaf = proj.byPath.get(path);
4626
+ if (!leaf) return void 0;
4627
+ return leaf.value;
4628
+ }
4629
+
4630
+ // src/shared/locales/targets/segmentMaterialize.ts
4631
+ function localeJsonFromTranslationSurfaceLeaves(leaves) {
4632
+ let out = {};
4633
+ for (const leaf of leaves) {
4634
+ out = setAtPath(out, leaf.path, leaf.value);
4635
+ }
4636
+ return out;
4637
+ }
4638
+ function pathsForSourceSegment(input) {
4639
+ const fromOrigin = input.sourceLeaves.filter((l) => l.fileOrigin?.relativePath === input.sourceRelativePath);
4640
+ if (fromOrigin.length > 0) {
4641
+ return new Set(fromOrigin.map((l) => l.path));
4642
+ }
4643
+ const absoluteFile = resolveLocaleSegmentAbsolutePath({
4644
+ layout: input.layout,
4645
+ path: input.path,
4646
+ locale: input.sourceLocaleCode,
4647
+ segmentRelativePath: input.sourceRelativePath
4648
+ });
4649
+ const read = readFlatLocaleJsonSurface({
4650
+ fs: input.fs,
4651
+ path: input.path,
4652
+ absoluteFile,
4653
+ localesDir: input.layout.directoryAbsolute,
4654
+ structure: input.layout.structure
4655
+ });
4656
+ if (read.ok) {
4657
+ const filePaths = new Set(read.leaves.map((l) => l.path));
4658
+ const intersected = input.sourceLeaves.filter((l) => filePaths.has(l.path)).map((l) => l.path);
4659
+ if (intersected.length > 0) {
4660
+ return new Set(intersected);
4661
+ }
4662
+ }
4663
+ if (input.singleSegmentFallback) {
4664
+ return new Set(input.sourceLeaves.map((l) => l.path));
4665
+ }
4666
+ return /* @__PURE__ */ new Set();
4667
+ }
4668
+ function materializeGenerateWorkingBySegment(input) {
4669
+ const sourceLocale = input.sourceLocaleCode;
4670
+ const projected = projectLocaleLeaves(input.working);
4671
+ const singleSegmentFallback = input.segments.length === 1;
4672
+ return input.segments.map((segment) => {
4673
+ const sourceRel = swapLocaleInSegmentRelativePath({
4674
+ structure: input.structure,
4675
+ relativePath: segment.relativePath,
4676
+ targetLocale: sourceLocale
4677
+ }) ?? segment.relativePath;
4678
+ const pathsForSegment = pathsForSourceSegment({
4679
+ layout: input.layout,
4680
+ fs: input.fs,
4681
+ path: input.path,
4682
+ sourceLocaleCode: sourceLocale,
4683
+ sourceRelativePath: sourceRel,
4684
+ sourceLeaves: input.sourceLeaves,
4685
+ singleSegmentFallback
4686
+ });
4687
+ let document = {};
4688
+ for (const leafPath of pathsForSegment) {
4689
+ const workingValue = getLocaleLeafAtPath(input.working, leafPath);
4690
+ let value;
4691
+ if (isStructuredLocaleLeafNode(workingValue)) {
4692
+ value = workingValue;
4693
+ } else {
4694
+ const projectedValue = getProjectedLeafString(projected, leafPath);
4695
+ value = projectedValue !== void 0 ? projectedValue : workingValue;
4696
+ }
4697
+ if (value !== void 0) {
4698
+ document = setAtPath(document, leafPath, value);
4699
+ }
4700
+ }
4701
+ return { segment, document };
4702
+ });
4703
+ }
4704
+
4705
+ // src/shared/locales/archive/buildLocaleJsonByTag.ts
4706
+ function segmentRelUnderLocalesDir(localesDirAbsolute, absolutePath) {
4707
+ const root = localesDirAbsolute.replace(/\\/g, "/").replace(/\/$/, "");
4708
+ const abs = absolutePath.replace(/\\/g, "/");
4709
+ if (abs === root) return "";
4710
+ const prefix = `${root}/`;
4711
+ if (!abs.startsWith(prefix)) return null;
4712
+ return abs.slice(prefix.length);
4713
+ }
4714
+ function collectArchiveLocaleSegments(input) {
4715
+ const { path, localesDirAbsolute, archiveRelPaths, locales, resolveArchiveAbsolute } = input;
4716
+ const layout = resolveLocalesLayout(locales, localesDirAbsolute);
4717
+ const recursive = layout.structure !== "locale_file";
4718
+ const segments = [];
4719
+ for (const archiveRelPath of archiveRelPaths) {
4720
+ if (!archiveRelPath.endsWith(".json")) continue;
4721
+ const absolutePath = resolveArchiveAbsolute(archiveRelPath);
4722
+ const segmentRel = segmentRelUnderLocalesDir(localesDirAbsolute, absolutePath);
4723
+ if (segmentRel === null) continue;
4724
+ if (!recursive && segmentRel.includes("/")) continue;
4725
+ const locale = localeCodeForSegment(layout.structure, path, { absolutePath, relativePath: segmentRel });
4726
+ if (locale === null) continue;
4727
+ segments.push({ locale, relativePath: segmentRel, absolutePath, archiveRelPath });
4728
+ }
4729
+ segments.sort((a, b) => {
4730
+ const byLocale = a.locale.localeCompare(b.locale);
4731
+ if (byLocale !== 0) return byLocale;
4732
+ return a.relativePath.localeCompare(b.relativePath);
4733
+ });
4734
+ return segments;
4735
+ }
4736
+ function listLocaleCodesFromArchive(input) {
4737
+ const segments = collectArchiveLocaleSegments(input);
4738
+ return [...new Set(segments.map((s) => s.locale))].sort((a, b) => a.localeCompare(b));
4739
+ }
4740
+ function buildLocaleJsonByTagFromArchive(input) {
4741
+ const { readText, sourceLocaleAbsolute } = input;
4742
+ const segments = collectArchiveLocaleSegments(input);
4743
+ const byLocale = /* @__PURE__ */ new Map();
4744
+ for (const segment of segments) {
4745
+ const list = byLocale.get(segment.locale) ?? [];
4746
+ list.push(segment);
4747
+ byLocale.set(segment.locale, list);
4748
+ }
4749
+ const out = {};
4750
+ for (const [locale, localeSegments] of byLocale) {
4751
+ let primary = localeSegments[0];
4752
+ if (sourceLocaleAbsolute !== void 0) {
4753
+ const sourceMatch = localeSegments.find((s) => s.absolutePath === sourceLocaleAbsolute);
4754
+ if (sourceMatch) primary = sourceMatch;
4755
+ }
4756
+ const raw = readText(primary.archiveRelPath);
4757
+ if (raw === void 0) continue;
4758
+ try {
4759
+ const parsed = JSON.parse(raw);
4760
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) continue;
4761
+ out[locale] = parsed;
4762
+ } catch {
4763
+ }
4764
+ }
4765
+ return out;
4766
+ }
4767
+
4768
+ // src/shared/locales/surface/localeSurface.ts
4769
+ function readLocaleLeavesForCode(ctx, localeCode) {
4770
+ const read = readLocaleCodeSurfaceFromContext(ctx, localeCode);
4771
+ if (!read.ok) return [];
4772
+ return read.leaves;
4773
+ }
4774
+ function readSourceLocaleLeaves(ctx) {
4775
+ return readLocaleLeavesForCode(ctx, sourceLocaleCodeFromContext(ctx));
4776
+ }
4777
+
4778
+ // src/shared/locales/surface/readJson.ts
4779
+ function readLocaleJsonOrEmpty(ctx, absolutePath) {
4780
+ if (!existsRuntimeFsSync(absolutePath, ctx.adapters.fs)) {
4781
+ return {};
4782
+ }
4783
+ const read = readLocaleSegmentFromContext(ctx, absolutePath);
4784
+ if (!read.ok) return {};
4785
+ return read.document;
4786
+ }
4787
+
4788
+ // src/shared/locales/surface/segmentPairing.ts
4789
+ function pairedSourceSegmentRelativePath(ctx, targetSegmentRelativePath, _targetLocaleCode) {
4790
+ const layout = resolveLocalesLayoutFromContext(ctx);
4791
+ const sourceCode = sourceLocaleCodeFromContext(ctx);
4792
+ return swapLocaleInSegmentRelativePath({
4793
+ structure: layout.structure,
4794
+ relativePath: targetSegmentRelativePath,
4795
+ targetLocale: sourceCode
4796
+ });
4797
+ }
4798
+ function resolvePairedSourceSegmentAbsolutePath(ctx, targetSegmentRelativePath, targetLocaleCode) {
4799
+ const layout = resolveLocalesLayoutFromContext(ctx);
4800
+ const sourceCode = sourceLocaleCodeFromContext(ctx);
4801
+ const sourceRel = pairedSourceSegmentRelativePath(ctx, targetSegmentRelativePath) ?? targetSegmentRelativePath;
4802
+ return resolveLocaleSegmentAbsolutePath({
4803
+ layout,
4804
+ path: ctx.adapters.path,
4805
+ locale: sourceCode,
4806
+ segmentRelativePath: sourceRel
4807
+ });
4808
+ }
4809
+ function inferSourceSegmentRelativePath(ctx, key) {
4810
+ const sourceCode = sourceLocaleCodeFromContext(ctx);
4811
+ const segments = segmentsForLocaleCode(ctx, sourceCode);
4812
+ const layout = resolveLocalesLayoutFromContext(ctx);
4813
+ const primary = primarySegmentForLocale(ctx, sourceCode);
4814
+ const fallback = primary?.relativePath ?? segments[0]?.relativePath ?? `${sourceCode}.json`;
4815
+ if (layout.structure !== "feature_bundle" || segments.length <= 1) {
4816
+ return fallback;
4817
+ }
4818
+ const featureDirs = new Set(
4819
+ segments.map((s) => {
4820
+ const slash = s.relativePath.indexOf("/");
4821
+ return slash >= 0 ? s.relativePath.slice(0, slash) : null;
4822
+ }).filter((name) => name !== null && name.length > 0)
4823
+ );
4824
+ const top = key.includes(".") ? key.slice(0, key.indexOf(".")) : key;
4825
+ if (featureDirs.has(top)) {
4826
+ return `${top}/${sourceCode}.json`;
4827
+ }
4828
+ return fallback;
4829
+ }
4830
+ function sourceSegmentRelativePathForKey(ctx, key, sourceLeaves) {
4831
+ const existing = sourceLeaves.find((leaf) => leaf.path === key);
4832
+ if (existing?.fileOrigin?.relativePath) {
4833
+ return existing.fileOrigin.relativePath;
4834
+ }
4835
+ return inferSourceSegmentRelativePath(ctx, key);
4836
+ }
4837
+ function targetSegmentRelativePathForKey(ctx, localeCode, key, sourceLeaves) {
4838
+ const layout = resolveLocalesLayoutFromContext(ctx);
4839
+ const sourceCode = sourceLocaleCodeFromContext(ctx);
4840
+ const sourceRel = sourceSegmentRelativePathForKey(ctx, key, sourceLeaves);
4841
+ if (localeCode === sourceCode) {
4842
+ return sourceRel;
4843
+ }
4844
+ const swapped = swapLocaleInSegmentRelativePath({
4845
+ structure: layout.structure,
4846
+ relativePath: sourceRel,
4847
+ targetLocale: localeCode
4848
+ });
4849
+ if (swapped !== null) {
4850
+ return swapped;
4851
+ }
4852
+ const primary = primarySegmentForLocale(ctx, localeCode);
4853
+ return primary?.relativePath ?? `${localeCode}.json`;
4854
+ }
4855
+
4856
+ // src/shared/locales/surface/syncSegment.ts
4857
+ function buildSegmentTemplateFromSource(_sourceRaw, leaves) {
4858
+ let template = {};
4859
+ for (const leaf of leaves) {
4860
+ template = setAtPath(template, leaf.path, leaf.value);
4861
+ }
4862
+ return template;
4863
+ }
4864
+ function resolveSyncSegmentSourcePlan(ctx, input) {
4865
+ const sourceRelativePath = pairedSourceSegmentRelativePath(ctx, input.targetSegmentRelativePath, input.targetLocaleCode) ?? input.targetSegmentRelativePath;
4866
+ const sourceAbsolutePath = resolvePairedSourceSegmentAbsolutePath(
4867
+ ctx,
4868
+ input.targetSegmentRelativePath,
4869
+ input.targetLocaleCode
4870
+ );
4871
+ let sourceRaw = {};
4872
+ let allSourceLeaves = [];
4873
+ if (existsRuntimeFsSync(sourceAbsolutePath, ctx.adapters.fs)) {
4874
+ const read = readLocaleSegmentFromContext(ctx, sourceAbsolutePath);
4875
+ if (read.ok) {
4876
+ sourceRaw = read.document;
4877
+ allSourceLeaves = read.leaves;
4878
+ }
4879
+ }
4880
+ const effectiveSchemaPaths = input.schemaPaths.size > 0 ? input.schemaPaths : new Set(allSourceLeaves.map((l) => l.path));
4881
+ const effectiveSourceLeaves = allSourceLeaves.filter((l) => effectiveSchemaPaths.has(l.path));
4882
+ const template = buildSegmentTemplateFromSource(sourceRaw, effectiveSourceLeaves);
4883
+ return {
4884
+ sourceRelativePath,
4885
+ sourceAbsolutePath,
4886
+ sourceRaw,
4887
+ effectiveSourceLeaves,
4888
+ template,
4889
+ sourceMap: new Map(effectiveSourceLeaves.map((l) => [l.path, l.value]))
4890
+ };
4891
+ }
4892
+ function resolveGlobalSyncSchemaPaths(ctx, schemaPaths) {
4893
+ if (schemaPaths.size > 0) return schemaPaths;
4894
+ return new Set(readSourceLocaleLeaves(ctx).map((l) => l.path));
4895
+ }
4896
+
4897
+ export { ANALYSIS_BASENAME, CACHE_PROFILE_DEFAULTS, CACHE_SCHEMA_VERSION, DEFAULT_CACHE_PROFILE_ID, DEFAULT_HEAL_EVERY_RUNS, DEFAULT_LIST_TOP, DEFAULT_MAX_SHARE_JSON_BYTES, DEFAULT_MISSING_LEAF_PLACEHOLDER, DEFAULT_WORKER_API_URL, DEMO_REPORT_URL, DEMO_WEB_APP_BASE, DOCS_ISSUES_PAGE_PATH, DOCS_SITE_BASE, DOCS_SITE_ORIGIN, ENV_TRANSLATE_DEEPL_API_KEY, ENV_TRANSLATE_LIBRE_URL, ENV_TRANSLATE_LLM_API_KEY, ENV_TRANSLATE_LLM_BASE_URL, ENV_TRANSLATE_LLM_MODEL, ENV_TRANSLATE_MAX_WORKERS, ENV_TRANSLATE_PROVIDER, GITHUB_BASE, GITHUB_DOCS_BASE, GITHUB_DOCS_TREE_BASE, GITHUB_OWNER, GITHUB_REPO, GITHUB_REPO_URL, HOSTED_PROJECT_SNAPSHOT_SCHEMA_VERSION, I18NPRUNE_CONFIG_BASENAME, I18NPRUNE_CONFIG_JSON_FILE_NAME, I18NPRUNE_CONFIG_SCRIPT_FILE_NAMES, I18NPRUNE_CONFIG_SCRIPT_FILE_NAMES_SET, I18NPRUNE_CONFIG_SNAPSHOT_FILE_NAMES, I18NPRUNE_CONFIG_SNAPSHOT_FILE_NAMES_SET, I18nPruneError, I18nPruneJsonParseError, ISSUE_CLEANUP_RIPGREP_UNAVAILABLE, ISSUE_CLEANUP_UNCERTAIN_PATHS_EXCLUDED, ISSUE_CLI_INVALID_JSON_PRETTY, ISSUE_CONFIG_INVALID, ISSUE_CONFIG_LOAD_FAILED, ISSUE_CONFIG_MISSING, ISSUE_CONTEXT_DISCOVERY_WARNING, ISSUE_CONTEXT_RESOLUTION_FAILED, ISSUE_DOCTOR_CONFIG_MISSING_FILE, ISSUE_DOCTOR_PATHS_DIRECTORIES_MISSING, ISSUE_DOCTOR_PATHS_SOURCE_LOCALE_MISSING, ISSUE_DOCTOR_RUNTIME_UNSUPPORTED_NODE, ISSUE_DOCTOR_TOOLS_RG_NOT_ON_PATH, ISSUE_GENERATE_SOURCE_EMPTY_STRING_LEAVES, ISSUE_GENERATE_TRANSLATE_NETWORK_ERROR, ISSUE_GENERATE_TRANSLATE_RATE_LIMITED, ISSUE_GENERATE_USAGE, ISSUE_IO_READ_FAILED, ISSUE_LANGUAGES_EMPTY_FILTER, ISSUE_LANGUAGES_UNSUPPORTED_LANGUAGE_CODE, ISSUE_LOCALES_USAGE, ISSUE_LOCALE_SOURCE_PLACEHOLDER_LEAVES, ISSUE_LOCALE_TARGET_NOT_FOUND, ISSUE_LOCALE_TARGET_PLACEHOLDER_LEAVES, ISSUE_MISSING_PATHS_NOT_IN_SCAN, ISSUE_PATCHING_CATALOG_MISMATCH_DIRECTION, ISSUE_PATCHING_CATALOG_MISMATCH_ENGLISH, ISSUE_PATCHING_CATALOG_MISMATCH_NATIVE, ISSUE_PATCHING_CONFIG_INVALID_SCHEMA, ISSUE_PATCHING_CONFIG_LOCALE_MISSING_FILE, ISSUE_PATCHING_CONFIG_PARSE_FAILED, ISSUE_PATCHING_CONFIG_SECTION_INCOMPLETE, ISSUE_PATCHING_CONFIG_SIZE_ANOMALY, ISSUE_PATCHING_CONFIG_TOO_LARGE, ISSUE_PATCHING_FILE_LOCALE_MISSING_CONFIG, ISSUE_PATHS_NETWORK_DRIVE, ISSUE_PATHS_WINDOWS_LONG_PATH, ISSUE_PATHS_WINDOWS_RESERVED_NAME, ISSUE_PROJECT_CONFIG_FILE_MISSING, ISSUE_PROJECT_HOSTED_SNAPSHOT_INVALID, ISSUE_PROJECT_HOSTED_SNAPSHOT_SCHEMA_VERSION, ISSUE_PROJECT_LOCALES_DIR_UNAVAILABLE, ISSUE_PROJECT_LOCALES_SOURCE_NOT_IN_BUNDLE, ISSUE_PROJECT_LOCALES_SOURCE_NOT_LANGUAGE_CODE, ISSUE_PROJECT_LOCALES_STRUCTURE_REQUIRED, ISSUE_PROJECT_SOURCE_LOCALE_INVALID_JSON, ISSUE_PROJECT_SOURCE_LOCALE_INVALID_SHAPE, ISSUE_PROJECT_SOURCE_LOCALE_MISSING_SEGMENTS, ISSUE_PROJECT_SOURCE_LOCALE_NOT_FOUND, ISSUE_PROJECT_SOURCE_LOCALE_UNAVAILABLE, ISSUE_PROJECT_SRC_ROOT_UNAVAILABLE, ISSUE_PROJECT_UPLOAD_CONFIG_JSON_INVALID, ISSUE_PROJECT_UPLOAD_CONFIG_REQUIRED, ISSUE_QUALITY_ENGLISH_IDENTICAL_LEAVES, ISSUE_REPORT_HOSTED_REPORT_INVALID, ISSUE_REPORT_INVALID_FORMAT, ISSUE_SCAN_DYNAMIC_KEY_SITES, ISSUE_SHARE_CACHE_EMPTY, ISSUE_SHARE_CACHE_ENTRY_NOT_FOUND, ISSUE_SHARE_JSON_REPAIRED, ISSUE_SHARE_JSON_WRITE_FAILED, ISSUE_SHARE_PREPARE_ANALYSIS_FAILED, ISSUE_SHARE_PREPARE_NOTHING_REQUESTED, ISSUE_SHARE_PREPARE_REPORT_FROM_ARCHIVE_FAILED, ISSUE_SHARE_PREPARE_REPORT_HOST_REQUIRED, ISSUE_SHARE_REMOTE_ERROR, ISSUE_SHARE_REMOTE_PAYLOAD_TOO_LARGE, ISSUE_SHARE_REMOTE_PROJECT_NOT_FOUND, ISSUE_SHARE_REMOTE_REPORT_NOT_FOUND, ISSUE_SHARE_REMOTE_REPORT_REJECTED, ISSUE_SHARE_REMOTE_UNAVAILABLE, ISSUE_SHARE_REMOTE_UPLOAD_REJECTED, ISSUE_SHARE_SNAPSHOT_EMPTY, ISSUE_SHARE_STALE_CACHE_ROW_REMOVED, ISSUE_SHARE_ZIP_FAILED, ISSUE_SYNC_LOCALE_FILE_NOT_FOUND, ISSUE_SYNC_METADATA_FLAG_CONFLICT, ISSUE_TRANSLATE_CONFIG_DEFAULT_APPLIED, ISSUE_TRANSLATE_HANDOFF_NO_ELIGIBLE_PROVIDER, ISSUE_TRANSLATE_IDENTITY_STREAK_ABORT, ISSUE_TRANSLATE_IDENTITY_STREAK_WARNING, ISSUE_TRANSLATE_MISSING_CREDENTIALS, ISSUE_TRANSLATE_PROVIDER_NOT_IMPLEMENTED_YET, ISSUE_TRANSLATE_UNKNOWN_TRANSLATION_PROVIDER, ISSUE_VALIDATE_DYNAMIC_KEY_SITES, ISSUE_VALIDATE_MISSING_LITERAL_KEYS, ISSUE_VALIDATE_SOURCE_LOCALE_READ_FAILED, LICENSE_URL, LIST_MORE_HINT, LIST_WINDOW_DEFAULT_TOP, LIST_WINDOW_HARD_CAP, MAX_ANALYSIS_BYTES, MAX_MISSING_TARGET_SUGGESTIONS, MAX_PROJECTS_INDEX_BYTES, MAX_PROJECT_FILES_BYTES, MAX_TRANSLATIONS_CACHE_BYTES, META_WORKER_URL, NPM_PACKAGE_NAME, NPM_PACKAGE_URL, PROJECT_REPORT_KIND, PROJECT_REPORT_SCHEMA_VERSION, PROJECT_SHARE_PREPARED_MAX_BYTES, PROJECT_UPLOAD_MAX_FILES, PROJECT_UPLOAD_MAX_TEXT_BYTES, PROJECT_UPLOAD_MAX_ZIP_BYTES, PROJECT_UPLOAD_ZIP_LIMITS, REPORT_INLINE_PAYLOAD_PLACEHOLDER, REPORT_SHARE_MAX_BYTES, RESULT_API_VERSION, SDK_PACKAGE_NAME, SDK_VERSION, SHARE_BAK_DIRNAME, SHARE_CACHE_REASON_MESSAGES, SHARE_JSON_BASENAME, TRANSLATE_WORKERS_CAP, TRANSLATIONS_DIR, WORKER_IDLE_RETENTION_MS, WORKER_INGEST_FORCE_QUERY, applyListWindow, applyLocaleLeafMode, applyLocaleLeafNormalization, applyPreserveFromSource, buildCliJsonEnvelope, buildLanguageCatalog, buildLocaleJsonByTagFromArchive, buildSegmentTemplateFromSource, collectLocaleStructuralParityDiagnostics, collectSourceLocaleMissingSegmentDiagnostics, collectTranslationSurfaceLeaves, constants_exports as constants, createLocaleReadCache, deepClone, deleteAtPath, detectLocalePlaceholderLeaves, detectSourcePlaceholderLeaves, docsCommandUrl, emitIssuesAsRunErrors, emitRunErrorFromUnknown, emitRunEvent, emitRunMessage, enrichIssuesWithDocHrefs, errors_exports as errors, filterLanguageCatalog, formatListOmittedSuffix, formatListShownOmitted, formatSourcePlaceholderMessage, formatSyncSourcePlaceholderMessage, formatTargetPlaceholderMessage, generatedLanguageCatalog, getAtPath, getDocsUrl, getJsonParseLocation, getLanguageByCodeFromCatalog, getProjectedLeafString, getRunOptions, invalidateLocaleReadCacheForAbsolutePath, invalidateLocaleReadCacheForLocaleCode, isCompleteStructuredLocaleLeafMeta, isErrnoCode, isLocalesLayoutReadSupported, isLocalesLayoutWriteSupported, isProgressEvent, isStructuredLocaleLeafNode, issueCodeDocHref, issueCodeRepoDocPathForIssueCode, issueFromI18nPruneError, issuesFromSourcePlaceholderLeaves, issuesFromTargetPlaceholderLeaves, json_exports as json, catalog_exports as languagesCatalog, listLocaleCodes, listLocaleCodesFromArchive, listLocaleCodesFromContext, listLocaleSegmentTargets, listLocaleSegments, listLocaleSegmentsFromContext, listSourceLocaleWriteTargets, localeCodeForSegment, localeCodesFromContext, localeJsonFromTranslationSurfaceLeaves, localeJsonValueFromTranslation, leaves_exports as localeLeaves, localeSegmentRefFromAbsolute, localeSegmentSourceForFile, localeStructuralSlot, layout_exports as localesLayout, read_exports as localesRead, write_exports as localesWrite, mask, materializeGenerateWorkingBySegment, mergeToTemplateShape, metadataModeEnabledFromConfig, noopRunEmitter, normalizeRepoDocPath, normalizeUnknownError, nowMs, options_exports as options, pairedSourceSegmentRelativePath, parseJsonText, placeholders_exports as placeholders, primarySegmentForLocale, projectLocaleLeaves, projects_exports as projects, pruneToTemplateShape, readFlatLocaleJsonSurface, readLocaleBundle, readLocaleCodeSurfaceFromContext, readLocaleJsonFromContextSync, readLocaleJsonOrEmpty, readLocaleLeavesForCode, readLocalePerDirLocaleSurface, readLocaleSegmentFromContext, readSourceLocaleLeaves, paths_exports as reference, resetRunOptions, resolveGlobalSyncSchemaPaths, resolveIssueCodeDocLink, resolveListWindow, resolveLocaleLeafMode, resolveLocaleSegmentAbsolutePath, resolveLocaleSegmentTargets, resolveLocalesLayout, resolveLocalesLayoutFromContext, resolvePairedSourceSegmentAbsolutePath, resolvePrimaryTargetWritePath, resolveSyncSegmentSourcePlan, resolveTargetLocaleWritePlan, restore, result_exports as result, rethrowAsI18n, run_exports as run, scanSources, scanner_exports as scanner, segmentsForLocaleCode, setAtPath, setRunOptions, sourceLocaleCodeForLayout, sourceLocaleCodeFromContext, sourcePlaceholderValues, sourcePlaceholders_exports as sourcePlaceholders, sourceSegmentRelativePathForKey, splitPath, stringifyCliCommandJson, stringifyEnvelope, suggestCatalogCodesForInvalidInputFromCatalog, swapLocaleInSegmentRelativePath, targetLocaleCodesFromContext, targetLocaleCoversAllSourcePaths, targetSegmentRelativePathForKey, translateLeaf, translationSurfacePathValueMap, translator_exports as translator, tryParseJsonText, validateLeafTranslationString, validateRestored, walkLocaleJsonSegments, writeFlatLocaleJsonDocument, writeLocaleBundle, writeLocaleJsonFromContextSync };