@fluenti/cli 0.3.3 → 0.4.0-rc.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 (59) hide show
  1. package/dist/ai-provider.d.ts +4 -3
  2. package/dist/ai-provider.d.ts.map +1 -1
  3. package/dist/cli.cjs +13 -12
  4. package/dist/cli.cjs.map +1 -1
  5. package/dist/cli.js +486 -289
  6. package/dist/cli.js.map +1 -1
  7. package/dist/{compile-B4y2UPsX.js → compile-CdA4EZ-p.js} +36 -33
  8. package/dist/compile-CdA4EZ-p.js.map +1 -0
  9. package/dist/compile-cache.d.ts.map +1 -1
  10. package/dist/compile-kXClO6q4.cjs +8 -0
  11. package/dist/compile-kXClO6q4.cjs.map +1 -0
  12. package/dist/compile-worker.cjs +1 -1
  13. package/dist/compile-worker.cjs.map +1 -1
  14. package/dist/compile-worker.d.ts +1 -0
  15. package/dist/compile-worker.d.ts.map +1 -1
  16. package/dist/compile-worker.js +19 -7
  17. package/dist/compile-worker.js.map +1 -1
  18. package/dist/compile.d.ts.map +1 -1
  19. package/dist/{extract-cache-idNfsd7n.cjs → extract-cache-BioSaoFo.cjs} +5 -5
  20. package/dist/extract-cache-BioSaoFo.cjs.map +1 -0
  21. package/dist/{extract-cache-DYoHe5P-.js → extract-cache-C-MI1_ll.js} +57 -44
  22. package/dist/extract-cache-C-MI1_ll.js.map +1 -0
  23. package/dist/extract-cache.d.ts.map +1 -1
  24. package/dist/extract-runner.d.ts.map +1 -1
  25. package/dist/glossary.d.ts.map +1 -1
  26. package/dist/index.cjs +1 -1
  27. package/dist/index.cjs.map +1 -1
  28. package/dist/index.js +10 -4
  29. package/dist/index.js.map +1 -1
  30. package/dist/lint.d.ts.map +1 -1
  31. package/dist/migrate.d.ts.map +1 -1
  32. package/dist/parallel-compile.d.ts.map +1 -1
  33. package/dist/po-format.d.ts.map +1 -1
  34. package/dist/translate-parse.d.ts +10 -0
  35. package/dist/translate-parse.d.ts.map +1 -0
  36. package/dist/translate-prompt.d.ts +9 -0
  37. package/dist/translate-prompt.d.ts.map +1 -0
  38. package/dist/translate.d.ts +11 -9
  39. package/dist/translate.d.ts.map +1 -1
  40. package/dist/{tsx-extractor-C-9_TnCW.cjs → tsx-extractor-B0vFXziu.cjs} +2 -2
  41. package/dist/tsx-extractor-B0vFXziu.cjs.map +1 -0
  42. package/dist/{tsx-extractor-CjQIMvKo.js → tsx-extractor-C-HZNobu.js} +2 -2
  43. package/dist/tsx-extractor-C-HZNobu.js.map +1 -0
  44. package/dist/tsx-extractor.d.ts.map +1 -1
  45. package/dist/validation.d.ts +4 -1
  46. package/dist/validation.d.ts.map +1 -1
  47. package/dist/vue-extractor.cjs +2 -2
  48. package/dist/vue-extractor.cjs.map +1 -1
  49. package/dist/vue-extractor.d.ts.map +1 -1
  50. package/dist/vue-extractor.js +3 -3
  51. package/dist/vue-extractor.js.map +1 -1
  52. package/package.json +2 -2
  53. package/dist/compile-B4y2UPsX.js.map +0 -1
  54. package/dist/compile-Brygn0bn.cjs +0 -8
  55. package/dist/compile-Brygn0bn.cjs.map +0 -1
  56. package/dist/extract-cache-DYoHe5P-.js.map +0 -1
  57. package/dist/extract-cache-idNfsd7n.cjs.map +0 -1
  58. package/dist/tsx-extractor-C-9_TnCW.cjs.map +0 -1
  59. package/dist/tsx-extractor-CjQIMvKo.js.map +0 -1
@@ -106,7 +106,7 @@ var b = "fluenti-id:";
106
106
  function x(t, n, r) {
107
107
  for (let [i, a] of Object.entries(t)) for (let [t, o] of Object.entries(a)) {
108
108
  if (!t) continue;
109
- let a = i || o.msgctxt || void 0, s = o.msgstr?.[0] ?? void 0, c = o.comments?.reference ?? void 0, l = c?.includes("\n") ? c.split("\n").map((e) => e.trim()).filter(Boolean) : c?.includes(" ") ? c.split(/\s+/).filter(Boolean) : c, u = Array.isArray(l) && l.length === 1 ? l[0] : l, d = !r && (o.comments?.flag?.includes("fuzzy") ?? !1), { comment: f, customId: p, sourceMessage: m } = w(o.comments?.extracted), h = m && e(m, a) === t ? m : void 0, g = p ?? (h ? t : e(t, a));
109
+ let a = i || o.msgctxt || void 0, s = o.msgstr?.[0] ?? void 0, c = o.comments?.reference ?? void 0, l = c?.includes("\n") ? c.split("\n").map((e) => e.trim()).filter(Boolean) : c?.includes(" ") ? c.split(/\s+/).filter(Boolean) : c, u = Array.isArray(l) && l.length === 1 ? l[0] : l, d = !r && (o.comments?.flag?.includes("fuzzy") ?? !1), { comment: f, customId: p, sourceMessage: m } = w(o.comments?.extracted), h = m && (p !== void 0 || e(m, a) === t) ? m : void 0, g = p ?? (h ? t : e(t, a));
110
110
  n[g] = {
111
111
  message: h ?? t,
112
112
  ...a === void 0 ? {} : { context: a },
@@ -122,33 +122,33 @@ function S(e) {
122
122
  let n = t.po.parse(e), r = {};
123
123
  return x(n.translations ?? {}, r, !1), n.obsolete && x(n.obsolete, r, !0), r;
124
124
  }
125
- function C(e) {
126
- let n = { "": { "": {
125
+ function C(n) {
126
+ let r = { "": { "": {
127
127
  msgid: "",
128
128
  msgstr: ["Content-Type: text/plain; charset=UTF-8\n"]
129
- } } }, r = {};
130
- for (let [t, i] of Object.entries(e)) {
131
- let e = {
132
- msgid: i.message ?? t,
133
- ...i.context === void 0 ? {} : { msgctxt: i.context },
134
- msgstr: [i.translation ?? ""]
135
- }, a = {};
136
- i.origin && !i.obsolete && (a.reference = Array.isArray(i.origin) ? i.origin.join("\n") : i.origin);
137
- let o = E(t, i.message ?? t, i.context, i.comment);
138
- if (o && (a.extracted = o), i.fuzzy && !i.obsolete && (a.flag = "fuzzy"), (a.reference || a.extracted || a.flag) && (e.comments = a), i.obsolete) {
139
- let t = i.context ?? "";
140
- r[t] ??= {}, r[t][e.msgid] = e;
129
+ } } }, i = {};
130
+ for (let [t, a] of Object.entries(n)) {
131
+ let n = {
132
+ msgid: a.message !== void 0 && e(a.message, a.context) === t ? a.message ?? t : t,
133
+ ...a.context === void 0 ? {} : { msgctxt: a.context },
134
+ msgstr: [a.translation ?? ""]
135
+ }, o = {};
136
+ a.origin && !a.obsolete && (o.reference = Array.isArray(a.origin) ? a.origin.join("\n") : a.origin);
137
+ let s = E(t, a.message ?? t, a.context, a.comment);
138
+ if (s && (o.extracted = s), a.fuzzy && !a.obsolete && (o.flag = "fuzzy"), (o.reference || o.extracted || o.flag) && (n.comments = o), a.obsolete) {
139
+ let e = a.context ?? "";
140
+ i[e] ??= {}, i[e][n.msgid] = n;
141
141
  } else {
142
- let t = i.context ?? "";
143
- n[t] ??= {}, n[t][e.msgid] = e;
142
+ let e = a.context ?? "";
143
+ r[e] ??= {}, r[e][n.msgid] = n;
144
144
  }
145
145
  }
146
- let i = {
146
+ let a = {
147
147
  headers: { "Content-Type": "text/plain; charset=UTF-8" },
148
- translations: n,
149
- ...Object.keys(r).length > 0 ? { obsolete: r } : {}
148
+ translations: r,
149
+ ...Object.keys(i).length > 0 ? { obsolete: i } : {}
150
150
  };
151
- return t.po.compile(i).toString();
151
+ return t.po.compile(a).toString();
152
152
  }
153
153
  function w(e) {
154
154
  if (!e) return {};
@@ -194,25 +194,26 @@ function T(e) {
194
194
  }
195
195
  function E(t, n, r, i) {
196
196
  let a = [];
197
- return i && a.push(i), t !== e(n, r) && a.push(`${b} ${t}`), a.length > 0 ? a.join("\n") : void 0;
197
+ return i && a.push(i), t !== e(n, r) && (a.push(`${b} ${t}`), a.push(`msg\`${n}\``)), a.length > 0 ? a.join("\n") : void 0;
198
198
  }
199
199
  //#endregion
200
200
  //#region src/parallel-compile.ts
201
- function D() {
201
+ var D = 3e4;
202
+ function O() {
202
203
  return l(typeof __dirname < "u" ? __dirname : c(f(import.meta.url)), "compile-worker.js");
203
204
  }
204
- async function O(e, t) {
205
+ async function k(e, t) {
205
206
  if (e.length === 0) return [];
206
207
  if (e.length === 1) {
207
- let { compileCatalog: t } = await import("./compile-B4y2UPsX.js").then((e) => e.a), n = e[0], { code: r, stats: i } = t(n.catalog, n.locale, n.allIds, n.sourceLocale, n.options);
208
+ let { compileCatalog: t } = await import("./compile-CdA4EZ-p.js").then((e) => e.a), n = e[0], { code: r, stats: i } = t(n.catalog, n.locale, n.allIds, n.sourceLocale, n.options);
208
209
  return [{
209
210
  locale: n.locale,
210
211
  code: r,
211
212
  stats: i
212
213
  }];
213
214
  }
214
- let n = D();
215
- if (!r(n)) return k(e);
215
+ let n = O();
216
+ if (!r(n)) return A(e);
216
217
  let i = t ?? Math.min(e.length, d()), a = [], o = [...e], s = !1;
217
218
  return new Promise((e, t) => {
218
219
  let r = 0;
@@ -224,31 +225,41 @@ async function O(e, t) {
224
225
  return;
225
226
  }
226
227
  r++;
227
- let l = new u(n);
228
+ let l = new u(n), d = setTimeout(() => {
229
+ s || (s = !0, r--, l.terminate(), t(/* @__PURE__ */ Error(`Worker timed out after ${D}ms compiling locale "${i.locale}"`)));
230
+ }, D);
228
231
  l.on("message", (e) => {
229
- a.push({
230
- locale: e.locale,
231
- code: e.code,
232
- stats: e.stats
233
- }), r--, l.terminate(), c();
232
+ if (clearTimeout(d), !s) {
233
+ if (e.error) {
234
+ s = !0, r--, l.terminate(), t(/* @__PURE__ */ Error(`Failed to compile locale "${e.locale}": ${e.error}`));
235
+ return;
236
+ }
237
+ a.push({
238
+ locale: e.locale,
239
+ code: e.code,
240
+ stats: e.stats
241
+ }), r--, l.terminate(), c();
242
+ }
234
243
  }), l.on("error", (e) => {
235
- s || (s = !0, l.terminate(), t(/* @__PURE__ */ Error(`Worker error compiling locale "${i.locale}": ${e.message}`)));
244
+ clearTimeout(d), s || (s = !0, l.terminate(), t(/* @__PURE__ */ Error(`Worker error compiling locale "${i.locale}": ${e.message}`)));
245
+ }), l.on("exit", (e) => {
246
+ clearTimeout(d), e !== 0 && !s && (s = !0, t(/* @__PURE__ */ Error(`Worker exited with code ${e} while compiling locale "${i.locale}"`)));
236
247
  });
237
- let d = {
248
+ let f = {
238
249
  locale: i.locale,
239
250
  catalog: i.catalog,
240
251
  allIds: i.allIds,
241
252
  sourceLocale: i.sourceLocale,
242
253
  options: i.options
243
254
  };
244
- l.postMessage(d);
255
+ l.postMessage(f);
245
256
  }
246
257
  let l = Math.min(i, o.length);
247
258
  for (let e = 0; e < l; e++) c();
248
259
  });
249
260
  }
250
- async function k(e) {
251
- let { compileCatalog: t } = await import("./compile-B4y2UPsX.js").then((e) => e.a);
261
+ async function A(e) {
262
+ let { compileCatalog: t } = await import("./compile-CdA4EZ-p.js").then((e) => e.a);
252
263
  return Promise.all(e.map((e) => {
253
264
  let { code: n, stats: r } = t(e.catalog, e.locale, e.allIds, e.sourceLocale, e.options);
254
265
  return {
@@ -260,7 +271,7 @@ async function k(e) {
260
271
  }
261
272
  //#endregion
262
273
  //#region src/extract-cache.ts
263
- var A = "1", j = class {
274
+ var j = "1", M = class {
264
275
  data;
265
276
  cachePath;
266
277
  dirty = !1;
@@ -288,7 +299,9 @@ var A = "1", j = class {
288
299
  for (let t of Object.keys(this.data.entries)) e.has(t) || (delete this.data.entries[t], this.dirty = !0);
289
300
  }
290
301
  save() {
291
- this.dirty &&= (i(c(this.cachePath), { recursive: !0 }), s(this.cachePath, JSON.stringify(this.data), "utf-8"), !1);
302
+ if (this.dirty) try {
303
+ i(c(this.cachePath), { recursive: !0 }), s(this.cachePath, JSON.stringify(this.data), "utf-8"), this.dirty = !1;
304
+ } catch {}
292
305
  }
293
306
  get size() {
294
307
  return Object.keys(this.data.entries).length;
@@ -297,16 +310,16 @@ var A = "1", j = class {
297
310
  try {
298
311
  if (r(this.cachePath)) {
299
312
  let e = a(this.cachePath, "utf-8"), t = JSON.parse(e);
300
- if (t.version === A) return t;
313
+ if (t.version === j) return t;
301
314
  }
302
315
  } catch {}
303
316
  return {
304
- version: A,
317
+ version: j,
305
318
  entries: {}
306
319
  };
307
320
  }
308
321
  };
309
322
  //#endregion
310
- export { C as a, p as c, S as i, O as n, v as o, n as r, y as s, j as t };
323
+ export { C as a, p as c, S as i, k as n, v as o, n as r, y as s, M as t };
311
324
 
312
- //# sourceMappingURL=extract-cache-DYoHe5P-.js.map
325
+ //# sourceMappingURL=extract-cache-C-MI1_ll.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extract-cache-C-MI1_ll.js","names":[],"sources":["../src/catalog.ts","../src/json-format.ts","../src/po-format.ts","../src/parallel-compile.ts","../src/extract-cache.ts"],"sourcesContent":["import type { ExtractedMessage } from '@fluenti/core/internal'\n\nexport interface CatalogEntry {\n message?: string | undefined\n context?: string | undefined\n comment?: string | undefined\n translation?: string | undefined\n origin?: string | string[] | undefined\n obsolete?: boolean | undefined\n fuzzy?: boolean | undefined\n}\n\nexport type CatalogData = Record<string, CatalogEntry>\n\nexport interface UpdateResult {\n added: number\n unchanged: number\n obsolete: number\n}\n\nexport interface UpdateCatalogOptions {\n stripFuzzy?: boolean\n}\n\n/** Update catalog with newly extracted messages */\nexport function updateCatalog(\n existing: CatalogData,\n extracted: ExtractedMessage[],\n options?: UpdateCatalogOptions,\n): { catalog: CatalogData; result: UpdateResult } {\n const extractedIds = new Set(extracted.map((m) => m.id))\n const consumedCarryForwardIds = new Set<string>()\n const catalog: CatalogData = {}\n let added = 0\n let unchanged = 0\n let obsolete = 0\n\n for (const msg of extracted) {\n const existingEntry = existing[msg.id]\n const carried = existingEntry\n ? undefined\n : findCarryForwardEntry(existing, msg, consumedCarryForwardIds)\n const origin = `${msg.origin.file}:${msg.origin.line}`\n const baseEntry = existingEntry ?? carried?.entry\n\n if (carried) {\n consumedCarryForwardIds.add(carried.id)\n }\n\n if (baseEntry) {\n catalog[msg.id] = {\n ...baseEntry,\n message: msg.message ?? baseEntry.message,\n context: msg.context,\n comment: msg.comment,\n origin,\n obsolete: false,\n }\n unchanged++\n } else if (catalog[msg.id]) {\n // Same ID already seen in this extraction batch — merge origin\n const existing = catalog[msg.id]!\n catalog[msg.id] = {\n ...existing,\n origin: mergeOrigins(existing.origin, origin),\n }\n } else {\n catalog[msg.id] = {\n message: msg.message,\n context: msg.context,\n comment: msg.comment,\n origin,\n }\n added++\n }\n\n if (options?.stripFuzzy) {\n const { fuzzy: _fuzzy, ...rest } = catalog[msg.id]!\n catalog[msg.id] = rest\n }\n }\n\n for (const [id, entry] of Object.entries(existing)) {\n if (!extractedIds.has(id)) {\n const { fuzzy: _fuzzy, ...rest } = entry\n const obsoleteEntry = options?.stripFuzzy\n ? { ...rest, obsolete: true }\n : { ...entry, obsolete: true }\n catalog[id] = obsoleteEntry\n obsolete++\n }\n }\n\n return { catalog, result: { added, unchanged, obsolete } }\n}\n\nfunction mergeOrigins(\n existing: string | string[] | undefined,\n newOrigin: string,\n): string | string[] {\n if (!existing) return newOrigin\n const existingArray = Array.isArray(existing) ? existing : [existing]\n const merged = [...new Set([...existingArray, newOrigin])]\n return merged.length === 1 ? merged[0]! : merged\n}\n\nfunction findCarryForwardEntry(\n existing: CatalogData,\n extracted: ExtractedMessage,\n consumedCarryForwardIds: Set<string>,\n): { id: string; entry: CatalogEntry } | undefined {\n if (!extracted.context) {\n return undefined\n }\n\n const extractedOrigin = `${extracted.origin.file}:${extracted.origin.line}`\n for (const [id, entry] of Object.entries(existing)) {\n if (consumedCarryForwardIds.has(id)) continue\n if (entry.context !== undefined) continue\n if (entry.message !== extracted.message) continue\n if (!sameOrigin(entry.origin, extractedOrigin)) continue\n return { id, entry }\n }\n\n return undefined\n}\n\nfunction sameOrigin(previous: string | string[] | undefined, next: string): boolean {\n if (!previous) return false\n const origins = Array.isArray(previous) ? previous : [previous]\n return origins.some((o) => o === next || originFile(o) === originFile(next))\n}\n\nfunction originFile(origin: string): string {\n const match = origin.match(/^(.*):\\d+$/)\n return match?.[1] ?? origin\n}\n","import type { CatalogData } from './catalog'\n\n/** Read a JSON catalog file */\nexport function readJsonCatalog(content: string): CatalogData {\n const raw = JSON.parse(content) as Record<string, unknown>\n const catalog: CatalogData = {}\n\n for (const [id, entry] of Object.entries(raw)) {\n if (typeof entry === 'object' && entry !== null) {\n const e = entry as Record<string, unknown>\n catalog[id] = {\n message: typeof e['message'] === 'string' ? e['message'] : undefined,\n context: typeof e['context'] === 'string' ? e['context'] : undefined,\n comment: typeof e['comment'] === 'string' ? e['comment'] : undefined,\n translation: typeof e['translation'] === 'string' ? e['translation'] : undefined,\n origin: typeof e['origin'] === 'string'\n ? e['origin']\n : Array.isArray(e['origin']) && (e['origin'] as unknown[]).every((v) => typeof v === 'string')\n ? (e['origin'] as string[])\n : undefined,\n obsolete: typeof e['obsolete'] === 'boolean' ? e['obsolete'] : undefined,\n fuzzy: typeof e['fuzzy'] === 'boolean' ? e['fuzzy'] : undefined,\n }\n }\n }\n\n return catalog\n}\n\n/** Write a catalog to JSON format */\nexport function writeJsonCatalog(catalog: CatalogData): string {\n const output: Record<string, Record<string, unknown>> = {}\n\n for (const [id, entry] of Object.entries(catalog)) {\n const obj: Record<string, unknown> = {}\n if (entry.message !== undefined) obj['message'] = entry.message\n if (entry.context !== undefined) obj['context'] = entry.context\n if (entry.comment !== undefined) obj['comment'] = entry.comment\n if (entry.translation !== undefined) obj['translation'] = entry.translation\n if (entry.origin !== undefined) obj['origin'] = entry.origin\n if (entry.obsolete) obj['obsolete'] = true\n if (entry.fuzzy) obj['fuzzy'] = true\n output[id] = obj\n }\n\n return JSON.stringify(output, null, 2) + '\\n'\n}\n","import type { CatalogData } from './catalog'\nimport { hashMessage } from '@fluenti/core/internal'\nimport * as gettextParser from 'gettext-parser'\n\nconst CUSTOM_ID_MARKER = 'fluenti-id:'\n\ninterface POTranslation {\n msgid: string\n msgctxt?: string\n msgstr: string[]\n comments?: {\n reference?: string\n extracted?: string\n flag?: string\n translator?: string\n previous?: string\n }\n}\n\ninterface POData {\n headers?: Record<string, string>\n translations: Record<string, Record<string, POTranslation>>\n obsolete?: Record<string, Record<string, POTranslation>>\n}\n\ninterface ParsedExtractedComment {\n comment?: string\n customId?: string\n sourceMessage?: string\n}\n\nfunction processPoEntries(\n contextMap: Record<string, Record<string, POTranslation>>,\n catalog: CatalogData,\n isObsolete: boolean,\n): void {\n for (const [contextKey, entries] of Object.entries(contextMap)) {\n for (const [msgid, entry] of Object.entries(entries)) {\n if (!msgid) continue\n\n const context = contextKey || entry.msgctxt || undefined\n const translation = entry.msgstr?.[0] ?? undefined\n const rawReference = entry.comments?.reference ?? undefined\n const origin = rawReference?.includes('\\n')\n ? rawReference.split('\\n').map((r: string) => r.trim()).filter(Boolean)\n : rawReference?.includes(' ')\n ? rawReference.split(/\\s+/).filter(Boolean)\n : rawReference\n const normalizedOrigin = Array.isArray(origin) && origin.length === 1 ? origin[0] : origin\n const isFuzzy = !isObsolete && (entry.comments?.flag?.includes('fuzzy') ?? false)\n const { comment, customId, sourceMessage } = parseExtractedComment(entry.comments?.extracted)\n // When a custom ID is present, the msgid may be the custom key (not source text),\n // so accept sourceMessage directly without requiring a hash match.\n // For hash-ID entries (no customId), verify the hash to prevent double-hashing.\n const resolvedSourceMessage = sourceMessage\n && (customId !== undefined || hashMessage(sourceMessage, context) === msgid)\n ? sourceMessage\n : undefined\n const id = customId\n ?? (resolvedSourceMessage ? msgid : hashMessage(msgid, context))\n\n catalog[id] = {\n message: resolvedSourceMessage ?? msgid,\n ...(context !== undefined ? { context } : {}),\n ...(comment !== undefined ? { comment } : {}),\n ...(translation ? { translation } : {}),\n ...(normalizedOrigin !== undefined ? { origin: normalizedOrigin } : {}),\n ...(isFuzzy ? { fuzzy: true } : {}),\n ...(isObsolete ? { obsolete: true } : {}),\n }\n }\n }\n}\n\n/** Read a PO catalog file */\nexport function readPoCatalog(content: string): CatalogData {\n const po = gettextParser.po.parse(content) as POData\n const catalog: CatalogData = {}\n\n processPoEntries(po.translations ?? {}, catalog, false)\n if (po.obsolete) {\n processPoEntries(po.obsolete, catalog, true)\n }\n\n return catalog\n}\n\n/** Write a catalog to PO format */\nexport function writePoCatalog(catalog: CatalogData): string {\n const translations: POData['translations'] = {\n '': {\n '': {\n msgid: '',\n msgstr: ['Content-Type: text/plain; charset=UTF-8\\n'],\n },\n },\n }\n const obsolete: POData['obsolete'] = {}\n\n for (const [id, entry] of Object.entries(catalog)) {\n // Use custom ID as msgid for non-hash entries to prevent collision when two\n // entries share the same source message but have different custom IDs.\n // Hash-ID entries keep source message as msgid (PO-friendly for translators).\n const isHashId = entry.message !== undefined && hashMessage(entry.message, entry.context) === id\n const msgid = isHashId ? (entry.message ?? id) : id\n const poEntry: POTranslation = {\n msgid,\n ...(entry.context !== undefined ? { msgctxt: entry.context } : {}),\n msgstr: [entry.translation ?? ''],\n }\n\n const comments: POTranslation['comments'] = {}\n if (entry.origin && !entry.obsolete) {\n comments.reference = Array.isArray(entry.origin)\n ? entry.origin.join('\\n')\n : entry.origin\n }\n const extractedComment = buildExtractedComment(id, entry.message ?? id, entry.context, entry.comment)\n if (extractedComment) {\n comments.extracted = extractedComment\n }\n if (entry.fuzzy && !entry.obsolete) {\n comments.flag = 'fuzzy'\n }\n if (comments.reference || comments.extracted || comments.flag) {\n poEntry.comments = comments\n }\n\n if (entry.obsolete) {\n const contextKey = entry.context ?? ''\n obsolete[contextKey] ??= {}\n obsolete[contextKey]![poEntry.msgid] = poEntry\n } else {\n const contextKey = entry.context ?? ''\n translations[contextKey] ??= {}\n translations[contextKey]![poEntry.msgid] = poEntry\n }\n }\n\n const poData: POData = {\n headers: {\n 'Content-Type': 'text/plain; charset=UTF-8',\n },\n translations,\n ...(Object.keys(obsolete).length > 0 ? { obsolete } : {}),\n }\n\n const buffer = gettextParser.po.compile(poData as Parameters<typeof gettextParser.po.compile>[0])\n return buffer.toString()\n}\n\nfunction parseExtractedComment(\n extracted: string | undefined,\n): ParsedExtractedComment {\n if (!extracted) {\n return {}\n }\n\n const lines = extracted.split('\\n').map((line) => line.trim()).filter(Boolean)\n let customId: string | undefined\n let sourceMessage: string | undefined\n const commentLines: string[] = []\n\n for (const line of lines) {\n if (line.startsWith(CUSTOM_ID_MARKER)) {\n customId = line.slice(CUSTOM_ID_MARKER.length).trim() || undefined\n continue\n }\n if (line.startsWith('msg`') && line.endsWith('`')) {\n sourceMessage = line.slice(4, -1)\n continue\n }\n if (line.startsWith('Trans: ')) {\n sourceMessage = normalizeRichTextComment(line.slice('Trans: '.length))\n continue\n }\n commentLines.push(line)\n }\n\n return {\n ...(commentLines.length > 0 ? { comment: commentLines.join('\\n') } : {}),\n ...(customId ? { customId } : {}),\n ...(sourceMessage ? { sourceMessage } : {}),\n }\n}\n\nfunction normalizeRichTextComment(comment: string): string {\n let stack: Array<{ tag: string; index: number }> = []\n let nextIndex = 0\n\n return comment.replace(/<\\/?([a-zA-Z][\\w-]*)>/g, (match, rawTag: string) => {\n const tag = rawTag\n if (match.startsWith('</')) {\n for (let index = stack.length - 1; index >= 0; index--) {\n const entry = stack[index]\n if (entry?.tag !== tag) continue\n stack = stack.filter((_, i) => i !== index)\n return `</${entry.index}>`\n }\n return match\n }\n\n const index = nextIndex++\n stack.push({ tag, index })\n return `<${index}>`\n })\n}\n\nfunction buildExtractedComment(\n id: string,\n message: string,\n context: string | undefined,\n comment: string | undefined,\n): string | undefined {\n const lines: string[] = []\n\n if (comment) {\n lines.push(comment)\n }\n\n if (id !== hashMessage(message, context)) {\n lines.push(`${CUSTOM_ID_MARKER} ${id}`)\n // Preserve source message so round-trip works when msgid is the custom ID (not source text)\n lines.push(`msg\\`${message}\\``)\n }\n\n return lines.length > 0 ? lines.join('\\n') : undefined\n}\n","import { Worker } from 'node:worker_threads'\nimport { availableParallelism } from 'node:os'\nimport { existsSync } from 'node:fs'\nimport { resolve, dirname } from 'node:path'\nimport { fileURLToPath } from 'node:url'\nimport type { CatalogData } from './catalog'\nimport type { CompileOptions, CompileStats } from './compile'\nimport type { CompileWorkerRequest, CompileWorkerResponse } from './compile-worker'\n\nexport interface ParallelCompileTask {\n locale: string\n catalog: CatalogData\n allIds: string[]\n sourceLocale: string\n options?: CompileOptions\n}\n\nexport interface ParallelCompileResult {\n locale: string\n code: string\n stats: CompileStats\n}\n\n/** Default timeout per worker in milliseconds (30 seconds) */\nconst WORKER_TIMEOUT_MS = 30_000\n\nfunction getWorkerPath(): string {\n const thisDir = typeof __dirname !== 'undefined'\n ? __dirname\n : dirname(fileURLToPath(import.meta.url))\n return resolve(thisDir, 'compile-worker.js')\n}\n\n/**\n * Compile multiple locales in parallel using worker threads.\n *\n * - Single task → returns result directly (no worker overhead)\n * - Multiple tasks → spawns min(tasks, availableParallelism()) workers\n * - Workers are created per-call and destroyed after completion\n *\n * Falls back to in-process compilation when the compiled worker is unavailable\n * (e.g. when running from TypeScript source in development/tests).\n */\nexport async function parallelCompile(\n tasks: ParallelCompileTask[],\n concurrency?: number,\n): Promise<ParallelCompileResult[]> {\n if (tasks.length === 0) return []\n\n // Single task: compile in-process, no worker overhead\n if (tasks.length === 1) {\n const { compileCatalog } = await import('./compile')\n const task = tasks[0]!\n const { code, stats } = compileCatalog(task.catalog, task.locale, task.allIds, task.sourceLocale, task.options)\n return [{ locale: task.locale, code, stats }]\n }\n\n const workerPath = getWorkerPath()\n\n // If compiled worker doesn't exist (dev/test), fall back to concurrent in-process compilation\n if (!existsSync(workerPath)) {\n return inProcessParallelCompile(tasks)\n }\n\n const maxWorkers = concurrency ?? Math.min(tasks.length, availableParallelism())\n const results: ParallelCompileResult[] = []\n const queue = [...tasks]\n let rejected = false\n\n return new Promise<ParallelCompileResult[]>((resolveAll, rejectAll) => {\n let activeWorkers = 0\n\n function spawnNext(): void {\n if (rejected) return\n const task = queue.shift()\n if (!task) {\n if (activeWorkers === 0) {\n resolveAll(results)\n }\n return\n }\n\n activeWorkers++\n const worker = new Worker(workerPath)\n\n const timer = setTimeout(() => {\n if (!rejected) {\n rejected = true\n activeWorkers--\n worker.terminate()\n rejectAll(new Error(`Worker timed out after ${WORKER_TIMEOUT_MS}ms compiling locale \"${task.locale}\"`))\n }\n }, WORKER_TIMEOUT_MS)\n\n worker.on('message', (response: CompileWorkerResponse) => {\n clearTimeout(timer)\n if (rejected) return\n if (response.error) {\n rejected = true\n activeWorkers--\n worker.terminate()\n rejectAll(new Error(`Failed to compile locale \"${response.locale}\": ${response.error}`))\n return\n }\n results.push({\n locale: response.locale,\n code: response.code,\n stats: response.stats,\n })\n activeWorkers--\n worker.terminate()\n spawnNext()\n })\n\n worker.on('error', (err: Error) => {\n clearTimeout(timer)\n if (!rejected) {\n rejected = true\n worker.terminate()\n rejectAll(new Error(`Worker error compiling locale \"${task.locale}\": ${err.message}`))\n }\n })\n\n worker.on('exit', (code) => {\n clearTimeout(timer)\n if (code !== 0 && !rejected) {\n rejected = true\n rejectAll(new Error(`Worker exited with code ${code} while compiling locale \"${task.locale}\"`))\n }\n })\n\n const request: CompileWorkerRequest = {\n locale: task.locale,\n catalog: task.catalog,\n allIds: task.allIds,\n sourceLocale: task.sourceLocale,\n options: task.options,\n }\n worker.postMessage(request)\n }\n\n // Start initial batch of workers\n const initialBatch = Math.min(maxWorkers, queue.length)\n for (let i = 0; i < initialBatch; i++) {\n spawnNext()\n }\n })\n}\n\n/**\n * In-process fallback for parallel compilation.\n * Uses Promise.all for concurrency when workers are unavailable.\n */\nasync function inProcessParallelCompile(\n tasks: ParallelCompileTask[],\n): Promise<ParallelCompileResult[]> {\n const { compileCatalog } = await import('./compile')\n return Promise.all(\n tasks.map((task) => {\n const { code, stats } = compileCatalog(task.catalog, task.locale, task.allIds, task.sourceLocale, task.options)\n return { locale: task.locale, code, stats }\n }),\n )\n}\n","import { readFileSync, writeFileSync, existsSync, mkdirSync, statSync } from 'node:fs'\nimport { dirname, resolve } from 'node:path'\nimport type { ExtractedMessage } from '@fluenti/core/internal'\n\n/** Cache format version — bump when the structure changes */\nconst CACHE_VERSION = '1'\n\ninterface ExtractCacheEntry {\n mtime: number\n size: number\n messages: ExtractedMessage[]\n}\n\ninterface ExtractCacheData {\n version: string\n entries: Record<string, ExtractCacheEntry>\n}\n\n/**\n * File-level extract cache that skips re-extraction for unchanged files.\n *\n * Cache is keyed by file path, with mtime + size as change detection.\n */\nexport class ExtractCache {\n private data: ExtractCacheData\n private cachePath: string\n private dirty = false\n\n constructor(catalogDir: string, projectId?: string) {\n const cacheDir = projectId\n ? resolve(catalogDir, '.cache', projectId)\n : resolve(catalogDir, '.cache')\n this.cachePath = resolve(cacheDir, 'extract-cache.json')\n this.data = this.load()\n }\n\n /**\n * Check if a file has changed since the last extraction.\n * Returns cached messages if unchanged, undefined if re-extraction needed.\n */\n get(filePath: string): ExtractedMessage[] | undefined {\n const entry = this.data.entries[filePath]\n if (!entry) return undefined\n\n try {\n const stat = statSync(filePath)\n if (stat.mtimeMs === entry.mtime && stat.size === entry.size) {\n return entry.messages\n }\n } catch {\n // File no longer exists or can't be stat'd — cache miss\n }\n\n return undefined\n }\n\n /**\n * Update the cache for a file after extraction.\n */\n set(filePath: string, messages: ExtractedMessage[]): void {\n try {\n const stat = statSync(filePath)\n this.data.entries[filePath] = {\n mtime: stat.mtimeMs,\n size: stat.size,\n messages,\n }\n this.dirty = true\n } catch {\n // File doesn't exist — skip caching\n }\n }\n\n /**\n * Remove entries for files that no longer exist in the file list.\n */\n prune(currentFiles: Set<string>): void {\n for (const filePath of Object.keys(this.data.entries)) {\n if (!currentFiles.has(filePath)) {\n delete this.data.entries[filePath]\n this.dirty = true\n }\n }\n }\n\n /**\n * Write the cache to disk if any changes were made.\n */\n save(): void {\n if (!this.dirty) return\n\n try {\n mkdirSync(dirname(this.cachePath), { recursive: true })\n writeFileSync(this.cachePath, JSON.stringify(this.data), 'utf-8')\n this.dirty = false\n } catch {\n // Cache write failure is non-fatal — next run will re-extract\n }\n }\n\n /** Number of cached entries */\n get size(): number {\n return Object.keys(this.data.entries).length\n }\n\n private load(): ExtractCacheData {\n try {\n if (existsSync(this.cachePath)) {\n const raw = readFileSync(this.cachePath, 'utf-8')\n const parsed = JSON.parse(raw) as ExtractCacheData\n if (parsed.version === CACHE_VERSION) {\n return parsed\n }\n }\n } catch {\n // Corrupt or unreadable cache — start fresh\n }\n\n return { version: CACHE_VERSION, entries: {} }\n }\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"extract-cache.d.ts","sourceRoot":"","sources":["../src/extract-cache.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAA;AAgB9D;;;;GAIG;AACH,qBAAa,YAAY;IACvB,OAAO,CAAC,IAAI,CAAkB;IAC9B,OAAO,CAAC,SAAS,CAAQ;IACzB,OAAO,CAAC,KAAK,CAAQ;gBAET,UAAU,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM;IAQlD;;;OAGG;IACH,GAAG,CAAC,QAAQ,EAAE,MAAM,GAAG,gBAAgB,EAAE,GAAG,SAAS;IAgBrD;;OAEG;IACH,GAAG,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,gBAAgB,EAAE,GAAG,IAAI;IAczD;;OAEG;IACH,KAAK,CAAC,YAAY,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,IAAI;IAStC;;OAEG;IACH,IAAI,IAAI,IAAI;IAQZ,+BAA+B;IAC/B,IAAI,IAAI,IAAI,MAAM,CAEjB;IAED,OAAO,CAAC,IAAI;CAeb"}
1
+ {"version":3,"file":"extract-cache.d.ts","sourceRoot":"","sources":["../src/extract-cache.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAA;AAgB9D;;;;GAIG;AACH,qBAAa,YAAY;IACvB,OAAO,CAAC,IAAI,CAAkB;IAC9B,OAAO,CAAC,SAAS,CAAQ;IACzB,OAAO,CAAC,KAAK,CAAQ;gBAET,UAAU,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM;IAQlD;;;OAGG;IACH,GAAG,CAAC,QAAQ,EAAE,MAAM,GAAG,gBAAgB,EAAE,GAAG,SAAS;IAgBrD;;OAEG;IACH,GAAG,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,gBAAgB,EAAE,GAAG,IAAI;IAczD;;OAEG;IACH,KAAK,CAAC,YAAY,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,IAAI;IAStC;;OAEG;IACH,IAAI,IAAI,IAAI;IAYZ,+BAA+B;IAC/B,IAAI,IAAI,IAAI,MAAM,CAEjB;IAED,OAAO,CAAC,IAAI;CAeb"}
@@ -1 +1 @@
1
- {"version":3,"file":"extract-runner.d.ts","sourceRoot":"","sources":["../src/extract-runner.ts"],"names":[],"mappings":"AAmBA,MAAM,WAAW,iBAAiB;IAChC,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB;AA2BD;;;;GAIG;AACH,wBAAsB,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CAmExF"}
1
+ {"version":3,"file":"extract-runner.d.ts","sourceRoot":"","sources":["../src/extract-runner.ts"],"names":[],"mappings":"AAmBA,MAAM,WAAW,iBAAiB;IAChC,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB;AAgCD;;;;GAIG;AACH,wBAAsB,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CAmExF"}
@@ -1 +1 @@
1
- {"version":3,"file":"glossary.d.ts","sourceRoot":"","sources":["../src/glossary.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,YAAY,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAA;AAEjE,wBAAgB,YAAY,CAAC,YAAY,EAAE,MAAM,GAAG,YAAY,CAgC/D;AAED,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,YAAY,EACtB,MAAM,EAAE,MAAM,GACb,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAQxB;AAED,wBAAgB,0BAA0B,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,MAAM,CAUhF"}
1
+ {"version":3,"file":"glossary.d.ts","sourceRoot":"","sources":["../src/glossary.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,YAAY,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAA;AAIjE,wBAAgB,YAAY,CAAC,YAAY,EAAE,MAAM,GAAG,YAAY,CAuC/D;AAED,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,YAAY,EACtB,MAAM,EAAE,MAAM,GACb,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAQxB;AAWD,wBAAgB,0BAA0B,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,MAAM,CAUhF"}
package/dist/index.cjs CHANGED
@@ -1,2 +1,2 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require(`./extract-cache-idNfsd7n.cjs`),t=require(`./tsx-extractor-C-9_TnCW.cjs`),n=require(`./compile-Brygn0bn.cjs`);let r=require(`@fluenti/core/internal`),i=require(`node:fs`),a=require(`node:path`),o=require(`fast-glob`);o=e.l(o);let s=require(`node:crypto`),c=require(`@fluenti/core/config`);function l(e){return e}function u(t,n){if(!(0,i.existsSync)(t))return{};let r=(0,i.readFileSync)(t,`utf-8`);return n===`json`?e.a(r):e.r(r)}function d(e){let t={};for(let[n,r]of Object.entries(e))r.obsolete||(t[n]=r.translation??r.message??n);return t}async function f(t,o){let s=await(0,c.loadConfig)(void 0,t),l=(0,r.resolveLocaleCodes)(s.locales),f=s.format===`json`?`.json`:`.po`,p=(0,a.resolve)(t,s.compileOutDir);(0,i.mkdirSync)(p,{recursive:!0});let m=s.plugins?.length?(0,r.createPluginRunner)(s.plugins):void 0,h={};for(let e of l)h[e]=u((0,a.resolve)(t,s.catalogDir,`${e}${f}`),s.format);let g=n.t(h);for(let e of l)if(m){let t={locale:e,messages:d(h[e]),outDir:p,config:s};await m.runBeforeCompile(t)}if(o?.parallel&&l.length>1){let t=await e.n(l.map(e=>({locale:e,catalog:h[e],allIds:g,sourceLocale:s.sourceLocale})));for(let e of t)(0,i.writeFileSync)((0,a.resolve)(p,`${e.locale}.js`),e.code,`utf-8`)}else for(let e of l){let{code:t}=n.n(h[e],e,g,s.sourceLocale);(0,i.writeFileSync)((0,a.resolve)(p,`${e}.js`),t,`utf-8`)}let _=n.r(l,s.compileOutDir);(0,i.writeFileSync)((0,a.resolve)(p,`index.js`),_,`utf-8`);let v=n.i(g,h,s.sourceLocale);(0,i.writeFileSync)((0,a.resolve)(p,`messages.d.ts`),v,`utf-8`);for(let e of l)if(m){let t={locale:e,messages:d(h[e]),outDir:p,config:s};await m.runAfterCompile(t)}}function p(e){return(0,s.createHash)(`md5`).update(e).digest(`hex`).slice(0,8)}function m(t,n){if(!(0,i.existsSync)(t))return{};let r=(0,i.readFileSync)(t,`utf-8`);return n===`json`?e.a(r):e.r(r)}function h(t,n,r){(0,i.mkdirSync)((0,a.dirname)(t),{recursive:!0}),(0,i.writeFileSync)(t,r===`json`?e.o(n):e.i(n),`utf-8`)}async function g(e,n){if((0,a.extname)(e)===`.vue`)try{let{extractFromVue:t}=await Promise.resolve().then(()=>require(`./vue-extractor.cjs`));return t(n,e)}catch{return[]}return t.t(n,e)}async function _(t,n){let s=await(0,c.loadConfig)(void 0,t),l=(0,r.resolveLocaleCodes)(s.locales),u=await(0,o.default)(s.include,{cwd:t,ignore:s.exclude??[]}),d=[],f=n?.useCache===!1?null:new e.t((0,a.resolve)(t,s.catalogDir),p(t));for(let e of u){let n=(0,a.resolve)(t,e);if(f){let e=f.get(n);if(e){d.push(...e);continue}}let r=await g(n,(0,i.readFileSync)(n,`utf-8`));d.push(...r),f&&f.set(n,r)}f&&(f.prune(new Set(u.map(e=>(0,a.resolve)(t,e)))),f.save());let _=s.plugins?.length?(0,r.createPluginRunner)(s.plugins):void 0;if(_){let e=new Map;for(let t of d)e.set(t.id,t);let t={messages:e,sourceLocale:s.sourceLocale,targetLocales:l.filter(e=>e!==s.sourceLocale),config:s};await _.runAfterExtract(t)}let v=s.format===`json`?`.json`:`.po`,y=n?.clean??!1,b=n?.stripFuzzy??!1;for(let n of l){let r=(0,a.resolve)(t,s.catalogDir,`${n}${v}`),{catalog:i}=e.s(m(r,s.format),d,{stripFuzzy:b});h(r,y?Object.fromEntries(Object.entries(i).filter(([,e])=>!e.obsolete)):i,s.format)}}exports.collectAllIds=n.t,exports.compileCatalog=n.n,exports.compileIndex=n.r,exports.defineConfig=l,exports.extractFromTsx=t.t,Object.defineProperty(exports,`hashMessage`,{enumerable:!0,get:function(){return r.hashMessage}}),Object.defineProperty(exports,`loadConfig`,{enumerable:!0,get:function(){return c.loadConfig}}),exports.readJsonCatalog=e.a,exports.readPoCatalog=e.r,exports.runCompile=f,exports.runExtract=_,exports.updateCatalog=e.s,exports.writeJsonCatalog=e.o,exports.writePoCatalog=e.i;
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require(`./extract-cache-BioSaoFo.cjs`),t=require(`./tsx-extractor-B0vFXziu.cjs`),n=require(`./compile-kXClO6q4.cjs`);let r=require(`@fluenti/core/internal`),i=require(`node:fs`),a=require(`node:path`),o=require(`fast-glob`);o=e.l(o);let s=require(`node:crypto`),c=require(`@fluenti/core/config`);function l(e){return e}function u(t,n){if(!(0,i.existsSync)(t))return{};let r=(0,i.readFileSync)(t,`utf-8`);return n===`json`?e.a(r):e.r(r)}function d(e){let t={};for(let[n,r]of Object.entries(e))r.obsolete||(t[n]=r.translation??r.message??n);return t}async function f(t,o){let s=await(0,c.loadConfig)(void 0,t),l=(0,r.resolveLocaleCodes)(s.locales),f=s.format===`json`?`.json`:`.po`,p=(0,a.resolve)(t,s.compileOutDir);(0,i.mkdirSync)(p,{recursive:!0});let m=s.plugins?.length?(0,r.createPluginRunner)(s.plugins):void 0,h={};for(let e of l)h[e]=u((0,a.resolve)(t,s.catalogDir,`${e}${f}`),s.format);let g=n.t(h);for(let e of l)if(m){let t={locale:e,messages:d(h[e]),outDir:p,config:s};await m.runBeforeCompile(t)}if(o?.parallel&&l.length>1){let t=await e.n(l.map(e=>({locale:e,catalog:h[e],allIds:g,sourceLocale:s.sourceLocale})));for(let e of t)(0,i.writeFileSync)((0,a.resolve)(p,`${e.locale}.js`),e.code,`utf-8`)}else for(let e of l){let{code:t}=n.n(h[e],e,g,s.sourceLocale);(0,i.writeFileSync)((0,a.resolve)(p,`${e}.js`),t,`utf-8`)}let _=n.r(l,s.compileOutDir);(0,i.writeFileSync)((0,a.resolve)(p,`index.js`),_,`utf-8`);let v=n.i(g,h,s.sourceLocale);(0,i.writeFileSync)((0,a.resolve)(p,`messages.d.ts`),v,`utf-8`);for(let e of l)if(m){let t={locale:e,messages:d(h[e]),outDir:p,config:s};await m.runAfterCompile(t)}}function p(e){return(0,s.createHash)(`md5`).update(e).digest(`hex`).slice(0,8)}function m(t,n){if(!(0,i.existsSync)(t))return{};let r=(0,i.readFileSync)(t,`utf-8`);return n===`json`?e.a(r):e.r(r)}function h(t,n,r){let o=r===`json`?e.o(n):e.i(n);try{(0,i.mkdirSync)((0,a.dirname)(t),{recursive:!0}),(0,i.writeFileSync)(t,o,`utf-8`)}catch(e){let n=e instanceof Error?e.message:String(e);throw Error(`Failed to write catalog "${t}": ${n}`)}}async function g(e,n){if((0,a.extname)(e)===`.vue`)try{let{extractFromVue:t}=await Promise.resolve().then(()=>require(`./vue-extractor.cjs`));return t(n,e)}catch{return[]}return t.t(n,e)}async function _(t,n){let s=await(0,c.loadConfig)(void 0,t),l=(0,r.resolveLocaleCodes)(s.locales),u=await(0,o.default)(s.include,{cwd:t,ignore:s.exclude??[]}),d=[],f=n?.useCache===!1?null:new e.t((0,a.resolve)(t,s.catalogDir),p(t));for(let e of u){let n=(0,a.resolve)(t,e);if(f){let e=f.get(n);if(e){d.push(...e);continue}}let r=await g(n,(0,i.readFileSync)(n,`utf-8`));d.push(...r),f&&f.set(n,r)}f&&(f.prune(new Set(u.map(e=>(0,a.resolve)(t,e)))),f.save());let _=s.plugins?.length?(0,r.createPluginRunner)(s.plugins):void 0;if(_){let e=new Map;for(let t of d)e.set(t.id,t);let t={messages:e,sourceLocale:s.sourceLocale,targetLocales:l.filter(e=>e!==s.sourceLocale),config:s};await _.runAfterExtract(t)}let v=s.format===`json`?`.json`:`.po`,y=n?.clean??!1,b=n?.stripFuzzy??!1;for(let n of l){let r=(0,a.resolve)(t,s.catalogDir,`${n}${v}`),{catalog:i}=e.s(m(r,s.format),d,{stripFuzzy:b});h(r,y?Object.fromEntries(Object.entries(i).filter(([,e])=>!e.obsolete)):i,s.format)}}exports.collectAllIds=n.t,exports.compileCatalog=n.n,exports.compileIndex=n.r,exports.defineConfig=l,exports.extractFromTsx=t.t,Object.defineProperty(exports,`hashMessage`,{enumerable:!0,get:function(){return r.hashMessage}}),Object.defineProperty(exports,`loadConfig`,{enumerable:!0,get:function(){return c.loadConfig}}),exports.readJsonCatalog=e.a,exports.readPoCatalog=e.r,exports.runCompile=f,exports.runExtract=_,exports.updateCatalog=e.s,exports.writeJsonCatalog=e.o,exports.writePoCatalog=e.i;
2
2
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","names":[],"sources":["../src/config.ts","../src/compile-runner.ts","../src/extract-runner.ts"],"sourcesContent":["import type { FluentiBuildConfig } from '@fluenti/core/internal'\n\n/**\n * Define a Fluenti configuration with full type inference and IDE autocompletion.\n *\n * @example\n * ```ts\n * // fluenti.config.ts\n * import { defineConfig } from '@fluenti/cli'\n *\n * export default defineConfig({\n * sourceLocale: 'en',\n * locales: ['en', 'ja', 'zh-CN'],\n * catalogDir: './locales',\n * format: 'po',\n * include: ['./src/**\\/*.{vue,tsx,ts}'],\n * compileOutDir: './src/locales/compiled',\n * })\n * ```\n */\nexport function defineConfig(config: Partial<FluentiBuildConfig>): Partial<FluentiBuildConfig> {\n return config\n}\n","import { readFileSync, writeFileSync, mkdirSync, existsSync } from 'node:fs'\nimport { resolve } from 'node:path'\nimport { resolveLocaleCodes, createPluginRunner } from '@fluenti/core/internal'\nimport type { PluginCompileContext } from '@fluenti/core/internal'\nimport { loadConfig } from './config-loader'\nimport { compileCatalog, compileIndex, collectAllIds, compileTypeDeclaration } from './compile'\nimport { parallelCompile } from './parallel-compile'\nimport type { CatalogData } from './catalog'\nimport { readJsonCatalog } from './json-format'\nimport { readPoCatalog } from './po-format'\n\nfunction readCatalog(filePath: string, format: 'json' | 'po'): CatalogData {\n if (!existsSync(filePath)) return {}\n const content = readFileSync(filePath, 'utf-8')\n return format === 'json' ? readJsonCatalog(content) : readPoCatalog(content)\n}\n\n/** Build a messages record (id → translation or message) from catalog data */\nfunction catalogToMessages(catalog: CatalogData): Record<string, string> {\n const messages: Record<string, string> = {}\n for (const [id, entry] of Object.entries(catalog)) {\n if (entry.obsolete) continue\n const text = entry.translation ?? entry.message ?? id\n messages[id] = text\n }\n return messages\n}\n\nexport interface RunCompileOptions {\n parallel?: boolean\n}\n\n/**\n * Programmatic compile entry point.\n * Loads config from `cwd`, reads catalogs, and writes compiled output.\n * This is the in-process equivalent of `fluenti compile`.\n */\nexport async function runCompile(cwd: string, options?: RunCompileOptions): Promise<void> {\n const config = await loadConfig(undefined, cwd)\n const localeCodes = resolveLocaleCodes(config.locales)\n const ext = config.format === 'json' ? '.json' : '.po'\n\n const outDir = resolve(cwd, config.compileOutDir)\n mkdirSync(outDir, { recursive: true })\n\n const pluginRunner = config.plugins?.length\n ? createPluginRunner(config.plugins)\n : undefined\n\n const allCatalogs: Record<string, CatalogData> = {}\n for (const locale of localeCodes) {\n const catalogPath = resolve(cwd, config.catalogDir, `${locale}${ext}`)\n allCatalogs[locale] = readCatalog(catalogPath, config.format)\n }\n\n const allIds = collectAllIds(allCatalogs)\n\n // Run plugin hooks around compilation\n for (const locale of localeCodes) {\n if (pluginRunner) {\n const compileContext: PluginCompileContext = {\n locale,\n messages: catalogToMessages(allCatalogs[locale]!),\n outDir,\n config,\n }\n await pluginRunner.runBeforeCompile(compileContext)\n }\n }\n\n if (options?.parallel && localeCodes.length > 1) {\n const tasks = localeCodes.map((locale) => ({\n locale,\n catalog: allCatalogs[locale]!,\n allIds,\n sourceLocale: config.sourceLocale,\n }))\n\n const results = await parallelCompile(tasks)\n\n for (const result of results) {\n writeFileSync(resolve(outDir, `${result.locale}.js`), result.code, 'utf-8')\n }\n } else {\n for (const locale of localeCodes) {\n const { code } = compileCatalog(allCatalogs[locale]!, locale, allIds, config.sourceLocale)\n writeFileSync(resolve(outDir, `${locale}.js`), code, 'utf-8')\n }\n }\n\n const indexCode = compileIndex(localeCodes, config.compileOutDir)\n writeFileSync(resolve(outDir, 'index.js'), indexCode, 'utf-8')\n\n const typesCode = compileTypeDeclaration(allIds, allCatalogs, config.sourceLocale)\n writeFileSync(resolve(outDir, 'messages.d.ts'), typesCode, 'utf-8')\n\n // Run after-compile hooks\n for (const locale of localeCodes) {\n if (pluginRunner) {\n const compileContext: PluginCompileContext = {\n locale,\n messages: catalogToMessages(allCatalogs[locale]!),\n outDir,\n config,\n }\n await pluginRunner.runAfterCompile(compileContext)\n }\n }\n}\n","import fg from 'fast-glob'\nimport { readFileSync, writeFileSync, mkdirSync, existsSync } from 'node:fs'\nimport { createHash } from 'node:crypto'\nimport { resolve, dirname, extname } from 'node:path'\nimport { extractFromTsx } from './tsx-extractor'\nimport { updateCatalog } from './catalog'\nimport type { CatalogData } from './catalog'\nimport { readJsonCatalog, writeJsonCatalog } from './json-format'\nimport { readPoCatalog, writePoCatalog } from './po-format'\nimport { ExtractCache } from './extract-cache'\nimport { loadConfig } from './config-loader'\nimport type { ExtractedMessage } from '@fluenti/core/internal'\nimport { resolveLocaleCodes, createPluginRunner } from '@fluenti/core/internal'\nimport type { PluginExtractContext } from '@fluenti/core/internal'\n\nfunction deriveProjectId(cwd: string): string {\n return createHash('md5').update(cwd).digest('hex').slice(0, 8)\n}\n\nexport interface RunExtractOptions {\n clean?: boolean\n stripFuzzy?: boolean\n useCache?: boolean\n}\n\nfunction readCatalog(filePath: string, format: 'json' | 'po'): CatalogData {\n if (!existsSync(filePath)) return {}\n const content = readFileSync(filePath, 'utf-8')\n return format === 'json' ? readJsonCatalog(content) : readPoCatalog(content)\n}\n\nfunction writeCatalog(filePath: string, catalog: CatalogData, format: 'json' | 'po'): void {\n mkdirSync(dirname(filePath), { recursive: true })\n const content = format === 'json' ? writeJsonCatalog(catalog) : writePoCatalog(catalog)\n writeFileSync(filePath, content, 'utf-8')\n}\n\nasync function extractFromFile(filePath: string, code: string): Promise<ExtractedMessage[]> {\n const ext = extname(filePath)\n if (ext === '.vue') {\n try {\n const { extractFromVue } = await import('./vue-extractor')\n return extractFromVue(code, filePath)\n } catch {\n return []\n }\n }\n return extractFromTsx(code, filePath)\n}\n\n/**\n * Programmatic extract entry point.\n * Loads config from `cwd`, extracts messages, and writes catalogs.\n * This is the in-process equivalent of `fluenti extract`.\n */\nexport async function runExtract(cwd: string, options?: RunExtractOptions): Promise<void> {\n const config = await loadConfig(undefined, cwd)\n const localeCodes = resolveLocaleCodes(config.locales)\n\n const files = await fg(config.include, { cwd, ignore: config.exclude ?? [] })\n const allMessages: ExtractedMessage[] = []\n const useCache = options?.useCache !== false\n const cache = useCache ? new ExtractCache(resolve(cwd, config.catalogDir), deriveProjectId(cwd)) : null\n\n for (const file of files) {\n const absFile = resolve(cwd, file)\n if (cache) {\n const cached = cache.get(absFile)\n if (cached) {\n allMessages.push(...cached)\n continue\n }\n }\n\n const code = readFileSync(absFile, 'utf-8')\n const messages = await extractFromFile(absFile, code)\n allMessages.push(...messages)\n\n if (cache) {\n cache.set(absFile, messages)\n }\n }\n\n if (cache) {\n cache.prune(new Set(files.map((f) => resolve(cwd, f))))\n cache.save()\n }\n\n // Run onAfterExtract plugin hooks\n const pluginRunner = config.plugins?.length\n ? createPluginRunner(config.plugins)\n : undefined\n\n if (pluginRunner) {\n const messageMap = new Map<string, ExtractedMessage>()\n for (const msg of allMessages) {\n messageMap.set(msg.id, msg)\n }\n const extractContext: PluginExtractContext = {\n messages: messageMap,\n sourceLocale: config.sourceLocale,\n targetLocales: localeCodes.filter((l) => l !== config.sourceLocale),\n config,\n }\n await pluginRunner.runAfterExtract(extractContext)\n }\n\n const ext = config.format === 'json' ? '.json' : '.po'\n const clean = options?.clean ?? false\n const stripFuzzy = options?.stripFuzzy ?? false\n\n for (const locale of localeCodes) {\n const catalogPath = resolve(cwd, config.catalogDir, `${locale}${ext}`)\n const existing = readCatalog(catalogPath, config.format)\n const { catalog } = updateCatalog(existing, allMessages, { stripFuzzy })\n\n const finalCatalog = clean\n ? Object.fromEntries(Object.entries(catalog).filter(([, entry]) => !entry.obsolete))\n : catalog\n\n writeCatalog(catalogPath, finalCatalog, config.format)\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs","names":[],"sources":["../src/config.ts","../src/compile-runner.ts","../src/extract-runner.ts"],"sourcesContent":["import type { FluentiBuildConfig } from '@fluenti/core/internal'\n\n/**\n * Define a Fluenti configuration with full type inference and IDE autocompletion.\n *\n * @example\n * ```ts\n * // fluenti.config.ts\n * import { defineConfig } from '@fluenti/cli'\n *\n * export default defineConfig({\n * sourceLocale: 'en',\n * locales: ['en', 'ja', 'zh-CN'],\n * catalogDir: './locales',\n * format: 'po',\n * include: ['./src/**\\/*.{vue,tsx,ts}'],\n * compileOutDir: './src/locales/compiled',\n * })\n * ```\n */\nexport function defineConfig(config: Partial<FluentiBuildConfig>): Partial<FluentiBuildConfig> {\n return config\n}\n","import { readFileSync, writeFileSync, mkdirSync, existsSync } from 'node:fs'\nimport { resolve } from 'node:path'\nimport { resolveLocaleCodes, createPluginRunner } from '@fluenti/core/internal'\nimport type { PluginCompileContext } from '@fluenti/core/internal'\nimport { loadConfig } from './config-loader'\nimport { compileCatalog, compileIndex, collectAllIds, compileTypeDeclaration } from './compile'\nimport { parallelCompile } from './parallel-compile'\nimport type { CatalogData } from './catalog'\nimport { readJsonCatalog } from './json-format'\nimport { readPoCatalog } from './po-format'\n\nfunction readCatalog(filePath: string, format: 'json' | 'po'): CatalogData {\n if (!existsSync(filePath)) return {}\n const content = readFileSync(filePath, 'utf-8')\n return format === 'json' ? readJsonCatalog(content) : readPoCatalog(content)\n}\n\n/** Build a messages record (id → translation or message) from catalog data */\nfunction catalogToMessages(catalog: CatalogData): Record<string, string> {\n const messages: Record<string, string> = {}\n for (const [id, entry] of Object.entries(catalog)) {\n if (entry.obsolete) continue\n const text = entry.translation ?? entry.message ?? id\n messages[id] = text\n }\n return messages\n}\n\nexport interface RunCompileOptions {\n parallel?: boolean\n}\n\n/**\n * Programmatic compile entry point.\n * Loads config from `cwd`, reads catalogs, and writes compiled output.\n * This is the in-process equivalent of `fluenti compile`.\n */\nexport async function runCompile(cwd: string, options?: RunCompileOptions): Promise<void> {\n const config = await loadConfig(undefined, cwd)\n const localeCodes = resolveLocaleCodes(config.locales)\n const ext = config.format === 'json' ? '.json' : '.po'\n\n const outDir = resolve(cwd, config.compileOutDir)\n mkdirSync(outDir, { recursive: true })\n\n const pluginRunner = config.plugins?.length\n ? createPluginRunner(config.plugins)\n : undefined\n\n const allCatalogs: Record<string, CatalogData> = {}\n for (const locale of localeCodes) {\n const catalogPath = resolve(cwd, config.catalogDir, `${locale}${ext}`)\n allCatalogs[locale] = readCatalog(catalogPath, config.format)\n }\n\n const allIds = collectAllIds(allCatalogs)\n\n // Run plugin hooks around compilation\n for (const locale of localeCodes) {\n if (pluginRunner) {\n const compileContext: PluginCompileContext = {\n locale,\n messages: catalogToMessages(allCatalogs[locale]!),\n outDir,\n config,\n }\n await pluginRunner.runBeforeCompile(compileContext)\n }\n }\n\n if (options?.parallel && localeCodes.length > 1) {\n const tasks = localeCodes.map((locale) => ({\n locale,\n catalog: allCatalogs[locale]!,\n allIds,\n sourceLocale: config.sourceLocale,\n }))\n\n const results = await parallelCompile(tasks)\n\n for (const result of results) {\n writeFileSync(resolve(outDir, `${result.locale}.js`), result.code, 'utf-8')\n }\n } else {\n for (const locale of localeCodes) {\n const { code } = compileCatalog(allCatalogs[locale]!, locale, allIds, config.sourceLocale)\n writeFileSync(resolve(outDir, `${locale}.js`), code, 'utf-8')\n }\n }\n\n const indexCode = compileIndex(localeCodes, config.compileOutDir)\n writeFileSync(resolve(outDir, 'index.js'), indexCode, 'utf-8')\n\n const typesCode = compileTypeDeclaration(allIds, allCatalogs, config.sourceLocale)\n writeFileSync(resolve(outDir, 'messages.d.ts'), typesCode, 'utf-8')\n\n // Run after-compile hooks\n for (const locale of localeCodes) {\n if (pluginRunner) {\n const compileContext: PluginCompileContext = {\n locale,\n messages: catalogToMessages(allCatalogs[locale]!),\n outDir,\n config,\n }\n await pluginRunner.runAfterCompile(compileContext)\n }\n }\n}\n","import fg from 'fast-glob'\nimport { readFileSync, writeFileSync, mkdirSync, existsSync } from 'node:fs'\nimport { createHash } from 'node:crypto'\nimport { resolve, dirname, extname } from 'node:path'\nimport { extractFromTsx } from './tsx-extractor'\nimport { updateCatalog } from './catalog'\nimport type { CatalogData } from './catalog'\nimport { readJsonCatalog, writeJsonCatalog } from './json-format'\nimport { readPoCatalog, writePoCatalog } from './po-format'\nimport { ExtractCache } from './extract-cache'\nimport { loadConfig } from './config-loader'\nimport type { ExtractedMessage } from '@fluenti/core/internal'\nimport { resolveLocaleCodes, createPluginRunner } from '@fluenti/core/internal'\nimport type { PluginExtractContext } from '@fluenti/core/internal'\n\nfunction deriveProjectId(cwd: string): string {\n return createHash('md5').update(cwd).digest('hex').slice(0, 8)\n}\n\nexport interface RunExtractOptions {\n clean?: boolean\n stripFuzzy?: boolean\n useCache?: boolean\n}\n\nfunction readCatalog(filePath: string, format: 'json' | 'po'): CatalogData {\n if (!existsSync(filePath)) return {}\n const content = readFileSync(filePath, 'utf-8')\n return format === 'json' ? readJsonCatalog(content) : readPoCatalog(content)\n}\n\nfunction writeCatalog(filePath: string, catalog: CatalogData, format: 'json' | 'po'): void {\n const content = format === 'json' ? writeJsonCatalog(catalog) : writePoCatalog(catalog)\n try {\n mkdirSync(dirname(filePath), { recursive: true })\n writeFileSync(filePath, content, 'utf-8')\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err)\n throw new Error(`Failed to write catalog \"${filePath}\": ${message}`)\n }\n}\n\nasync function extractFromFile(filePath: string, code: string): Promise<ExtractedMessage[]> {\n const ext = extname(filePath)\n if (ext === '.vue') {\n try {\n const { extractFromVue } = await import('./vue-extractor')\n return extractFromVue(code, filePath)\n } catch {\n return []\n }\n }\n return extractFromTsx(code, filePath)\n}\n\n/**\n * Programmatic extract entry point.\n * Loads config from `cwd`, extracts messages, and writes catalogs.\n * This is the in-process equivalent of `fluenti extract`.\n */\nexport async function runExtract(cwd: string, options?: RunExtractOptions): Promise<void> {\n const config = await loadConfig(undefined, cwd)\n const localeCodes = resolveLocaleCodes(config.locales)\n\n const files = await fg(config.include, { cwd, ignore: config.exclude ?? [] })\n const allMessages: ExtractedMessage[] = []\n const useCache = options?.useCache !== false\n const cache = useCache ? new ExtractCache(resolve(cwd, config.catalogDir), deriveProjectId(cwd)) : null\n\n for (const file of files) {\n const absFile = resolve(cwd, file)\n if (cache) {\n const cached = cache.get(absFile)\n if (cached) {\n allMessages.push(...cached)\n continue\n }\n }\n\n const code = readFileSync(absFile, 'utf-8')\n const messages = await extractFromFile(absFile, code)\n allMessages.push(...messages)\n\n if (cache) {\n cache.set(absFile, messages)\n }\n }\n\n if (cache) {\n cache.prune(new Set(files.map((f) => resolve(cwd, f))))\n cache.save()\n }\n\n // Run onAfterExtract plugin hooks\n const pluginRunner = config.plugins?.length\n ? createPluginRunner(config.plugins)\n : undefined\n\n if (pluginRunner) {\n const messageMap = new Map<string, ExtractedMessage>()\n for (const msg of allMessages) {\n messageMap.set(msg.id, msg)\n }\n const extractContext: PluginExtractContext = {\n messages: messageMap,\n sourceLocale: config.sourceLocale,\n targetLocales: localeCodes.filter((l) => l !== config.sourceLocale),\n config,\n }\n await pluginRunner.runAfterExtract(extractContext)\n }\n\n const ext = config.format === 'json' ? '.json' : '.po'\n const clean = options?.clean ?? false\n const stripFuzzy = options?.stripFuzzy ?? false\n\n for (const locale of localeCodes) {\n const catalogPath = resolve(cwd, config.catalogDir, `${locale}${ext}`)\n const existing = readCatalog(catalogPath, config.format)\n const { catalog } = updateCatalog(existing, allMessages, { stripFuzzy })\n\n const finalCatalog = clean\n ? Object.fromEntries(Object.entries(catalog).filter(([, entry]) => !entry.obsolete))\n : catalog\n\n writeCatalog(catalogPath, finalCatalog, config.format)\n }\n}\n"],"mappings":"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"}
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
- import { i as e, n as t, r as n, t as r } from "./compile-B4y2UPsX.js";
2
- import { t as i } from "./tsx-extractor-CjQIMvKo.js";
3
- import { a, c as o, i as s, n as c, o as l, r as u, s as d, t as f } from "./extract-cache-DYoHe5P-.js";
1
+ import { i as e, n as t, r as n, t as r } from "./compile-CdA4EZ-p.js";
2
+ import { t as i } from "./tsx-extractor-C-HZNobu.js";
3
+ import { a, c as o, i as s, n as c, o as l, r as u, s as d, t as f } from "./extract-cache-C-MI1_ll.js";
4
4
  import { createPluginRunner as p, hashMessage as m, resolveLocaleCodes as h } from "@fluenti/core/internal";
5
5
  import { existsSync as g, mkdirSync as _, readFileSync as v, writeFileSync as y } from "node:fs";
6
6
  import { dirname as b, extname as x, resolve as S } from "node:path";
@@ -74,7 +74,13 @@ function A(e, t) {
74
74
  return t === "json" ? l(n) : s(n);
75
75
  }
76
76
  function j(e, t, n) {
77
- _(b(e), { recursive: !0 }), y(e, n === "json" ? d(t) : a(t), "utf-8");
77
+ let r = n === "json" ? d(t) : a(t);
78
+ try {
79
+ _(b(e), { recursive: !0 }), y(e, r, "utf-8");
80
+ } catch (t) {
81
+ let n = t instanceof Error ? t.message : String(t);
82
+ throw Error(`Failed to write catalog "${e}": ${n}`);
83
+ }
78
84
  }
79
85
  async function M(e, t) {
80
86
  if (x(e) === ".vue") try {
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../src/config.ts","../src/compile-runner.ts","../src/extract-runner.ts"],"sourcesContent":["import type { FluentiBuildConfig } from '@fluenti/core/internal'\n\n/**\n * Define a Fluenti configuration with full type inference and IDE autocompletion.\n *\n * @example\n * ```ts\n * // fluenti.config.ts\n * import { defineConfig } from '@fluenti/cli'\n *\n * export default defineConfig({\n * sourceLocale: 'en',\n * locales: ['en', 'ja', 'zh-CN'],\n * catalogDir: './locales',\n * format: 'po',\n * include: ['./src/**\\/*.{vue,tsx,ts}'],\n * compileOutDir: './src/locales/compiled',\n * })\n * ```\n */\nexport function defineConfig(config: Partial<FluentiBuildConfig>): Partial<FluentiBuildConfig> {\n return config\n}\n","import { readFileSync, writeFileSync, mkdirSync, existsSync } from 'node:fs'\nimport { resolve } from 'node:path'\nimport { resolveLocaleCodes, createPluginRunner } from '@fluenti/core/internal'\nimport type { PluginCompileContext } from '@fluenti/core/internal'\nimport { loadConfig } from './config-loader'\nimport { compileCatalog, compileIndex, collectAllIds, compileTypeDeclaration } from './compile'\nimport { parallelCompile } from './parallel-compile'\nimport type { CatalogData } from './catalog'\nimport { readJsonCatalog } from './json-format'\nimport { readPoCatalog } from './po-format'\n\nfunction readCatalog(filePath: string, format: 'json' | 'po'): CatalogData {\n if (!existsSync(filePath)) return {}\n const content = readFileSync(filePath, 'utf-8')\n return format === 'json' ? readJsonCatalog(content) : readPoCatalog(content)\n}\n\n/** Build a messages record (id → translation or message) from catalog data */\nfunction catalogToMessages(catalog: CatalogData): Record<string, string> {\n const messages: Record<string, string> = {}\n for (const [id, entry] of Object.entries(catalog)) {\n if (entry.obsolete) continue\n const text = entry.translation ?? entry.message ?? id\n messages[id] = text\n }\n return messages\n}\n\nexport interface RunCompileOptions {\n parallel?: boolean\n}\n\n/**\n * Programmatic compile entry point.\n * Loads config from `cwd`, reads catalogs, and writes compiled output.\n * This is the in-process equivalent of `fluenti compile`.\n */\nexport async function runCompile(cwd: string, options?: RunCompileOptions): Promise<void> {\n const config = await loadConfig(undefined, cwd)\n const localeCodes = resolveLocaleCodes(config.locales)\n const ext = config.format === 'json' ? '.json' : '.po'\n\n const outDir = resolve(cwd, config.compileOutDir)\n mkdirSync(outDir, { recursive: true })\n\n const pluginRunner = config.plugins?.length\n ? createPluginRunner(config.plugins)\n : undefined\n\n const allCatalogs: Record<string, CatalogData> = {}\n for (const locale of localeCodes) {\n const catalogPath = resolve(cwd, config.catalogDir, `${locale}${ext}`)\n allCatalogs[locale] = readCatalog(catalogPath, config.format)\n }\n\n const allIds = collectAllIds(allCatalogs)\n\n // Run plugin hooks around compilation\n for (const locale of localeCodes) {\n if (pluginRunner) {\n const compileContext: PluginCompileContext = {\n locale,\n messages: catalogToMessages(allCatalogs[locale]!),\n outDir,\n config,\n }\n await pluginRunner.runBeforeCompile(compileContext)\n }\n }\n\n if (options?.parallel && localeCodes.length > 1) {\n const tasks = localeCodes.map((locale) => ({\n locale,\n catalog: allCatalogs[locale]!,\n allIds,\n sourceLocale: config.sourceLocale,\n }))\n\n const results = await parallelCompile(tasks)\n\n for (const result of results) {\n writeFileSync(resolve(outDir, `${result.locale}.js`), result.code, 'utf-8')\n }\n } else {\n for (const locale of localeCodes) {\n const { code } = compileCatalog(allCatalogs[locale]!, locale, allIds, config.sourceLocale)\n writeFileSync(resolve(outDir, `${locale}.js`), code, 'utf-8')\n }\n }\n\n const indexCode = compileIndex(localeCodes, config.compileOutDir)\n writeFileSync(resolve(outDir, 'index.js'), indexCode, 'utf-8')\n\n const typesCode = compileTypeDeclaration(allIds, allCatalogs, config.sourceLocale)\n writeFileSync(resolve(outDir, 'messages.d.ts'), typesCode, 'utf-8')\n\n // Run after-compile hooks\n for (const locale of localeCodes) {\n if (pluginRunner) {\n const compileContext: PluginCompileContext = {\n locale,\n messages: catalogToMessages(allCatalogs[locale]!),\n outDir,\n config,\n }\n await pluginRunner.runAfterCompile(compileContext)\n }\n }\n}\n","import fg from 'fast-glob'\nimport { readFileSync, writeFileSync, mkdirSync, existsSync } from 'node:fs'\nimport { createHash } from 'node:crypto'\nimport { resolve, dirname, extname } from 'node:path'\nimport { extractFromTsx } from './tsx-extractor'\nimport { updateCatalog } from './catalog'\nimport type { CatalogData } from './catalog'\nimport { readJsonCatalog, writeJsonCatalog } from './json-format'\nimport { readPoCatalog, writePoCatalog } from './po-format'\nimport { ExtractCache } from './extract-cache'\nimport { loadConfig } from './config-loader'\nimport type { ExtractedMessage } from '@fluenti/core/internal'\nimport { resolveLocaleCodes, createPluginRunner } from '@fluenti/core/internal'\nimport type { PluginExtractContext } from '@fluenti/core/internal'\n\nfunction deriveProjectId(cwd: string): string {\n return createHash('md5').update(cwd).digest('hex').slice(0, 8)\n}\n\nexport interface RunExtractOptions {\n clean?: boolean\n stripFuzzy?: boolean\n useCache?: boolean\n}\n\nfunction readCatalog(filePath: string, format: 'json' | 'po'): CatalogData {\n if (!existsSync(filePath)) return {}\n const content = readFileSync(filePath, 'utf-8')\n return format === 'json' ? readJsonCatalog(content) : readPoCatalog(content)\n}\n\nfunction writeCatalog(filePath: string, catalog: CatalogData, format: 'json' | 'po'): void {\n mkdirSync(dirname(filePath), { recursive: true })\n const content = format === 'json' ? writeJsonCatalog(catalog) : writePoCatalog(catalog)\n writeFileSync(filePath, content, 'utf-8')\n}\n\nasync function extractFromFile(filePath: string, code: string): Promise<ExtractedMessage[]> {\n const ext = extname(filePath)\n if (ext === '.vue') {\n try {\n const { extractFromVue } = await import('./vue-extractor')\n return extractFromVue(code, filePath)\n } catch {\n return []\n }\n }\n return extractFromTsx(code, filePath)\n}\n\n/**\n * Programmatic extract entry point.\n * Loads config from `cwd`, extracts messages, and writes catalogs.\n * This is the in-process equivalent of `fluenti extract`.\n */\nexport async function runExtract(cwd: string, options?: RunExtractOptions): Promise<void> {\n const config = await loadConfig(undefined, cwd)\n const localeCodes = resolveLocaleCodes(config.locales)\n\n const files = await fg(config.include, { cwd, ignore: config.exclude ?? [] })\n const allMessages: ExtractedMessage[] = []\n const useCache = options?.useCache !== false\n const cache = useCache ? new ExtractCache(resolve(cwd, config.catalogDir), deriveProjectId(cwd)) : null\n\n for (const file of files) {\n const absFile = resolve(cwd, file)\n if (cache) {\n const cached = cache.get(absFile)\n if (cached) {\n allMessages.push(...cached)\n continue\n }\n }\n\n const code = readFileSync(absFile, 'utf-8')\n const messages = await extractFromFile(absFile, code)\n allMessages.push(...messages)\n\n if (cache) {\n cache.set(absFile, messages)\n }\n }\n\n if (cache) {\n cache.prune(new Set(files.map((f) => resolve(cwd, f))))\n cache.save()\n }\n\n // Run onAfterExtract plugin hooks\n const pluginRunner = config.plugins?.length\n ? createPluginRunner(config.plugins)\n : undefined\n\n if (pluginRunner) {\n const messageMap = new Map<string, ExtractedMessage>()\n for (const msg of allMessages) {\n messageMap.set(msg.id, msg)\n }\n const extractContext: PluginExtractContext = {\n messages: messageMap,\n sourceLocale: config.sourceLocale,\n targetLocales: localeCodes.filter((l) => l !== config.sourceLocale),\n config,\n }\n await pluginRunner.runAfterExtract(extractContext)\n }\n\n const ext = config.format === 'json' ? '.json' : '.po'\n const clean = options?.clean ?? false\n const stripFuzzy = options?.stripFuzzy ?? false\n\n for (const locale of localeCodes) {\n const catalogPath = resolve(cwd, config.catalogDir, `${locale}${ext}`)\n const existing = readCatalog(catalogPath, config.format)\n const { catalog } = updateCatalog(existing, allMessages, { stripFuzzy })\n\n const finalCatalog = clean\n ? Object.fromEntries(Object.entries(catalog).filter(([, entry]) => !entry.obsolete))\n : catalog\n\n writeCatalog(catalogPath, finalCatalog, config.format)\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../src/config.ts","../src/compile-runner.ts","../src/extract-runner.ts"],"sourcesContent":["import type { FluentiBuildConfig } from '@fluenti/core/internal'\n\n/**\n * Define a Fluenti configuration with full type inference and IDE autocompletion.\n *\n * @example\n * ```ts\n * // fluenti.config.ts\n * import { defineConfig } from '@fluenti/cli'\n *\n * export default defineConfig({\n * sourceLocale: 'en',\n * locales: ['en', 'ja', 'zh-CN'],\n * catalogDir: './locales',\n * format: 'po',\n * include: ['./src/**\\/*.{vue,tsx,ts}'],\n * compileOutDir: './src/locales/compiled',\n * })\n * ```\n */\nexport function defineConfig(config: Partial<FluentiBuildConfig>): Partial<FluentiBuildConfig> {\n return config\n}\n","import { readFileSync, writeFileSync, mkdirSync, existsSync } from 'node:fs'\nimport { resolve } from 'node:path'\nimport { resolveLocaleCodes, createPluginRunner } from '@fluenti/core/internal'\nimport type { PluginCompileContext } from '@fluenti/core/internal'\nimport { loadConfig } from './config-loader'\nimport { compileCatalog, compileIndex, collectAllIds, compileTypeDeclaration } from './compile'\nimport { parallelCompile } from './parallel-compile'\nimport type { CatalogData } from './catalog'\nimport { readJsonCatalog } from './json-format'\nimport { readPoCatalog } from './po-format'\n\nfunction readCatalog(filePath: string, format: 'json' | 'po'): CatalogData {\n if (!existsSync(filePath)) return {}\n const content = readFileSync(filePath, 'utf-8')\n return format === 'json' ? readJsonCatalog(content) : readPoCatalog(content)\n}\n\n/** Build a messages record (id → translation or message) from catalog data */\nfunction catalogToMessages(catalog: CatalogData): Record<string, string> {\n const messages: Record<string, string> = {}\n for (const [id, entry] of Object.entries(catalog)) {\n if (entry.obsolete) continue\n const text = entry.translation ?? entry.message ?? id\n messages[id] = text\n }\n return messages\n}\n\nexport interface RunCompileOptions {\n parallel?: boolean\n}\n\n/**\n * Programmatic compile entry point.\n * Loads config from `cwd`, reads catalogs, and writes compiled output.\n * This is the in-process equivalent of `fluenti compile`.\n */\nexport async function runCompile(cwd: string, options?: RunCompileOptions): Promise<void> {\n const config = await loadConfig(undefined, cwd)\n const localeCodes = resolveLocaleCodes(config.locales)\n const ext = config.format === 'json' ? '.json' : '.po'\n\n const outDir = resolve(cwd, config.compileOutDir)\n mkdirSync(outDir, { recursive: true })\n\n const pluginRunner = config.plugins?.length\n ? createPluginRunner(config.plugins)\n : undefined\n\n const allCatalogs: Record<string, CatalogData> = {}\n for (const locale of localeCodes) {\n const catalogPath = resolve(cwd, config.catalogDir, `${locale}${ext}`)\n allCatalogs[locale] = readCatalog(catalogPath, config.format)\n }\n\n const allIds = collectAllIds(allCatalogs)\n\n // Run plugin hooks around compilation\n for (const locale of localeCodes) {\n if (pluginRunner) {\n const compileContext: PluginCompileContext = {\n locale,\n messages: catalogToMessages(allCatalogs[locale]!),\n outDir,\n config,\n }\n await pluginRunner.runBeforeCompile(compileContext)\n }\n }\n\n if (options?.parallel && localeCodes.length > 1) {\n const tasks = localeCodes.map((locale) => ({\n locale,\n catalog: allCatalogs[locale]!,\n allIds,\n sourceLocale: config.sourceLocale,\n }))\n\n const results = await parallelCompile(tasks)\n\n for (const result of results) {\n writeFileSync(resolve(outDir, `${result.locale}.js`), result.code, 'utf-8')\n }\n } else {\n for (const locale of localeCodes) {\n const { code } = compileCatalog(allCatalogs[locale]!, locale, allIds, config.sourceLocale)\n writeFileSync(resolve(outDir, `${locale}.js`), code, 'utf-8')\n }\n }\n\n const indexCode = compileIndex(localeCodes, config.compileOutDir)\n writeFileSync(resolve(outDir, 'index.js'), indexCode, 'utf-8')\n\n const typesCode = compileTypeDeclaration(allIds, allCatalogs, config.sourceLocale)\n writeFileSync(resolve(outDir, 'messages.d.ts'), typesCode, 'utf-8')\n\n // Run after-compile hooks\n for (const locale of localeCodes) {\n if (pluginRunner) {\n const compileContext: PluginCompileContext = {\n locale,\n messages: catalogToMessages(allCatalogs[locale]!),\n outDir,\n config,\n }\n await pluginRunner.runAfterCompile(compileContext)\n }\n }\n}\n","import fg from 'fast-glob'\nimport { readFileSync, writeFileSync, mkdirSync, existsSync } from 'node:fs'\nimport { createHash } from 'node:crypto'\nimport { resolve, dirname, extname } from 'node:path'\nimport { extractFromTsx } from './tsx-extractor'\nimport { updateCatalog } from './catalog'\nimport type { CatalogData } from './catalog'\nimport { readJsonCatalog, writeJsonCatalog } from './json-format'\nimport { readPoCatalog, writePoCatalog } from './po-format'\nimport { ExtractCache } from './extract-cache'\nimport { loadConfig } from './config-loader'\nimport type { ExtractedMessage } from '@fluenti/core/internal'\nimport { resolveLocaleCodes, createPluginRunner } from '@fluenti/core/internal'\nimport type { PluginExtractContext } from '@fluenti/core/internal'\n\nfunction deriveProjectId(cwd: string): string {\n return createHash('md5').update(cwd).digest('hex').slice(0, 8)\n}\n\nexport interface RunExtractOptions {\n clean?: boolean\n stripFuzzy?: boolean\n useCache?: boolean\n}\n\nfunction readCatalog(filePath: string, format: 'json' | 'po'): CatalogData {\n if (!existsSync(filePath)) return {}\n const content = readFileSync(filePath, 'utf-8')\n return format === 'json' ? readJsonCatalog(content) : readPoCatalog(content)\n}\n\nfunction writeCatalog(filePath: string, catalog: CatalogData, format: 'json' | 'po'): void {\n const content = format === 'json' ? writeJsonCatalog(catalog) : writePoCatalog(catalog)\n try {\n mkdirSync(dirname(filePath), { recursive: true })\n writeFileSync(filePath, content, 'utf-8')\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err)\n throw new Error(`Failed to write catalog \"${filePath}\": ${message}`)\n }\n}\n\nasync function extractFromFile(filePath: string, code: string): Promise<ExtractedMessage[]> {\n const ext = extname(filePath)\n if (ext === '.vue') {\n try {\n const { extractFromVue } = await import('./vue-extractor')\n return extractFromVue(code, filePath)\n } catch {\n return []\n }\n }\n return extractFromTsx(code, filePath)\n}\n\n/**\n * Programmatic extract entry point.\n * Loads config from `cwd`, extracts messages, and writes catalogs.\n * This is the in-process equivalent of `fluenti extract`.\n */\nexport async function runExtract(cwd: string, options?: RunExtractOptions): Promise<void> {\n const config = await loadConfig(undefined, cwd)\n const localeCodes = resolveLocaleCodes(config.locales)\n\n const files = await fg(config.include, { cwd, ignore: config.exclude ?? [] })\n const allMessages: ExtractedMessage[] = []\n const useCache = options?.useCache !== false\n const cache = useCache ? new ExtractCache(resolve(cwd, config.catalogDir), deriveProjectId(cwd)) : null\n\n for (const file of files) {\n const absFile = resolve(cwd, file)\n if (cache) {\n const cached = cache.get(absFile)\n if (cached) {\n allMessages.push(...cached)\n continue\n }\n }\n\n const code = readFileSync(absFile, 'utf-8')\n const messages = await extractFromFile(absFile, code)\n allMessages.push(...messages)\n\n if (cache) {\n cache.set(absFile, messages)\n }\n }\n\n if (cache) {\n cache.prune(new Set(files.map((f) => resolve(cwd, f))))\n cache.save()\n }\n\n // Run onAfterExtract plugin hooks\n const pluginRunner = config.plugins?.length\n ? createPluginRunner(config.plugins)\n : undefined\n\n if (pluginRunner) {\n const messageMap = new Map<string, ExtractedMessage>()\n for (const msg of allMessages) {\n messageMap.set(msg.id, msg)\n }\n const extractContext: PluginExtractContext = {\n messages: messageMap,\n sourceLocale: config.sourceLocale,\n targetLocales: localeCodes.filter((l) => l !== config.sourceLocale),\n config,\n }\n await pluginRunner.runAfterExtract(extractContext)\n }\n\n const ext = config.format === 'json' ? '.json' : '.po'\n const clean = options?.clean ?? false\n const stripFuzzy = options?.stripFuzzy ?? false\n\n for (const locale of localeCodes) {\n const catalogPath = resolve(cwd, config.catalogDir, `${locale}${ext}`)\n const existing = readCatalog(catalogPath, config.format)\n const { catalog } = updateCatalog(existing, allMessages, { stripFuzzy })\n\n const finalCatalog = clean\n ? Object.fromEntries(Object.entries(catalog).filter(([, entry]) => !entry.obsolete))\n : catalog\n\n writeCatalog(catalogPath, finalCatalog, config.format)\n }\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"lint.d.ts","sourceRoot":"","sources":["../src/lint.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,WAAW,CAAA;AAE5C,2CAA2C;AAC3C,MAAM,MAAM,YAAY,GAAG,OAAO,GAAG,SAAS,GAAG,MAAM,CAAA;AAEvD,+BAA+B;AAC/B,MAAM,WAAW,cAAc;IAC7B,8CAA8C;IAC9C,IAAI,EAAE,MAAM,CAAA;IACZ,qBAAqB;IACrB,QAAQ,EAAE,YAAY,CAAA;IACtB,6BAA6B;IAC7B,OAAO,EAAE,MAAM,CAAA;IACf,0BAA0B;IAC1B,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,sBAAsB;IACtB,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB;AAED,4CAA4C;AAC5C,MAAM,WAAW,WAAW;IAC1B,qCAAqC;IACrC,OAAO,CAAC,EAAE,MAAM,EAAE,CAAA;IAClB,mCAAmC;IACnC,YAAY,EAAE,MAAM,CAAA;IACpB,mDAAmD;IACnD,MAAM,CAAC,EAAE,OAAO,CAAA;CACjB;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAC1B,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,EACrC,OAAO,EAAE,WAAW,GACnB,cAAc,EAAE,CAgIlB;AAkBD;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,WAAW,EAAE,cAAc,EAAE,GAAG,MAAM,CAsBvE"}
1
+ {"version":3,"file":"lint.d.ts","sourceRoot":"","sources":["../src/lint.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,WAAW,CAAA;AAG5C,2CAA2C;AAC3C,MAAM,MAAM,YAAY,GAAG,OAAO,GAAG,SAAS,GAAG,MAAM,CAAA;AAEvD,+BAA+B;AAC/B,MAAM,WAAW,cAAc;IAC7B,8CAA8C;IAC9C,IAAI,EAAE,MAAM,CAAA;IACZ,qBAAqB;IACrB,QAAQ,EAAE,YAAY,CAAA;IACtB,6BAA6B;IAC7B,OAAO,EAAE,MAAM,CAAA;IACf,0BAA0B;IAC1B,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,sBAAsB;IACtB,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB;AAED,4CAA4C;AAC5C,MAAM,WAAW,WAAW;IAC1B,qCAAqC;IACrC,OAAO,CAAC,EAAE,MAAM,EAAE,CAAA;IAClB,mCAAmC;IACnC,YAAY,EAAE,MAAM,CAAA;IACpB,mDAAmD;IACnD,MAAM,CAAC,EAAE,OAAO,CAAA;CACjB;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAC1B,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,EACrC,OAAO,EAAE,WAAW,GACnB,cAAc,EAAE,CAgIlB;AAGD;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,WAAW,EAAE,cAAc,EAAE,GAAG,MAAM,CAsBvE"}
@@ -1 +1 @@
1
- {"version":3,"file":"migrate.d.ts","sourceRoot":"","sources":["../src/migrate.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AAI7C,MAAM,MAAM,gBAAgB,GACxB,UAAU,GACV,WAAW,GACX,eAAe,GACf,WAAW,GACX,cAAc,GACd,QAAQ,CAAA;AAEZ,UAAU,WAAW;IACnB,IAAI,EAAE,gBAAgB,CAAA;IACtB,SAAS,EAAE,MAAM,CAAA;IACjB,cAAc,EAAE,MAAM,EAAE,CAAA;IACxB,cAAc,EAAE,MAAM,EAAE,CAAA;IACxB,cAAc,EAAE,MAAM,EAAE,CAAA;IACxB,cAAc,EAAE,MAAM,CAAA;CACvB;AAuDD,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,gBAAgB,GAAG,SAAS,CAGzE;AAED,MAAM,WAAW,aAAa;IAC5B,WAAW,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;IACrD,WAAW,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;IACrD,aAAa,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;IACvD,WAAW,EAAE,MAAM,GAAG,SAAS,CAAA;CAChC;AAyED,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,WAAW,EACpB,QAAQ,EAAE,aAAa,EACvB,cAAc,EAAE,MAAM,GACrB,MAAM,CA6ER;AA2BD,UAAU,aAAa;IACrB,MAAM,EAAE,MAAM,GAAG,SAAS,CAAA;IAC1B,WAAW,EAAE,KAAK,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;IACvD,KAAK,EAAE,MAAM,GAAG,SAAS,CAAA;IACzB,eAAe,EAAE,MAAM,GAAG,SAAS,CAAA;CACpC;AAED,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,aAAa,CAwC7D;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,UAAU,CAAA;IACpB,KAAK,EAAE,OAAO,CAAA;CACf;AAED,wBAAsB,UAAU,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAmGvE"}
1
+ {"version":3,"file":"migrate.d.ts","sourceRoot":"","sources":["../src/migrate.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AAI7C,MAAM,MAAM,gBAAgB,GACxB,UAAU,GACV,WAAW,GACX,eAAe,GACf,WAAW,GACX,cAAc,GACd,QAAQ,CAAA;AAEZ,UAAU,WAAW;IACnB,IAAI,EAAE,gBAAgB,CAAA;IACtB,SAAS,EAAE,MAAM,CAAA;IACjB,cAAc,EAAE,MAAM,EAAE,CAAA;IACxB,cAAc,EAAE,MAAM,EAAE,CAAA;IACxB,cAAc,EAAE,MAAM,EAAE,CAAA;IACxB,cAAc,EAAE,MAAM,CAAA;CACvB;AAuDD,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,gBAAgB,GAAG,SAAS,CAGzE;AAED,MAAM,WAAW,aAAa;IAC5B,WAAW,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;IACrD,WAAW,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;IACrD,aAAa,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;IACvD,WAAW,EAAE,MAAM,GAAG,SAAS,CAAA;CAChC;AAyED,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,WAAW,EACpB,QAAQ,EAAE,aAAa,EACvB,cAAc,EAAE,MAAM,GACrB,MAAM,CA6ER;AA2BD,UAAU,aAAa;IACrB,MAAM,EAAE,MAAM,GAAG,SAAS,CAAA;IAC1B,WAAW,EAAE,KAAK,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;IACvD,KAAK,EAAE,MAAM,GAAG,SAAS,CAAA;IACzB,eAAe,EAAE,MAAM,GAAG,SAAS,CAAA;CACpC;AAED,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,aAAa,CA6C7D;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,UAAU,CAAA;IACpB,KAAK,EAAE,OAAO,CAAA;CACf;AAED,wBAAsB,UAAU,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAmGvE"}
@@ -1 +1 @@
1
- {"version":3,"file":"parallel-compile.d.ts","sourceRoot":"","sources":["../src/parallel-compile.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,WAAW,CAAA;AAC5C,OAAO,KAAK,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,WAAW,CAAA;AAG7D,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,MAAM,CAAA;IACd,OAAO,EAAE,WAAW,CAAA;IACpB,MAAM,EAAE,MAAM,EAAE,CAAA;IAChB,YAAY,EAAE,MAAM,CAAA;IACpB,OAAO,CAAC,EAAE,cAAc,CAAA;CACzB;AAED,MAAM,WAAW,qBAAqB;IACpC,MAAM,EAAE,MAAM,CAAA;IACd,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE,YAAY,CAAA;CACpB;AASD;;;;;;;;;GASG;AACH,wBAAsB,eAAe,CACnC,KAAK,EAAE,mBAAmB,EAAE,EAC5B,WAAW,CAAC,EAAE,MAAM,GACnB,OAAO,CAAC,qBAAqB,EAAE,CAAC,CA0ElC"}
1
+ {"version":3,"file":"parallel-compile.d.ts","sourceRoot":"","sources":["../src/parallel-compile.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,WAAW,CAAA;AAC5C,OAAO,KAAK,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,WAAW,CAAA;AAG7D,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,MAAM,CAAA;IACd,OAAO,EAAE,WAAW,CAAA;IACpB,MAAM,EAAE,MAAM,EAAE,CAAA;IAChB,YAAY,EAAE,MAAM,CAAA;IACpB,OAAO,CAAC,EAAE,cAAc,CAAA;CACzB;AAED,MAAM,WAAW,qBAAqB;IACpC,MAAM,EAAE,MAAM,CAAA;IACd,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE,YAAY,CAAA;CACpB;AAYD;;;;;;;;;GASG;AACH,wBAAsB,eAAe,CACnC,KAAK,EAAE,mBAAmB,EAAE,EAC5B,WAAW,CAAC,EAAE,MAAM,GACnB,OAAO,CAAC,qBAAqB,EAAE,CAAC,CAqGlC"}
@@ -1 +1 @@
1
- {"version":3,"file":"po-format.d.ts","sourceRoot":"","sources":["../src/po-format.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,WAAW,CAAA;AAuE5C,6BAA6B;AAC7B,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,WAAW,CAU1D;AAED,mCAAmC;AACnC,wBAAgB,cAAc,CAAC,OAAO,EAAE,WAAW,GAAG,MAAM,CAwD3D"}
1
+ {"version":3,"file":"po-format.d.ts","sourceRoot":"","sources":["../src/po-format.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,WAAW,CAAA;AA0E5C,6BAA6B;AAC7B,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,WAAW,CAU1D;AAED,mCAAmC;AACnC,wBAAgB,cAAc,CAAC,OAAO,EAAE,WAAW,GAAG,MAAM,CA6D3D"}
@@ -0,0 +1,10 @@
1
+ export interface ParseResult {
2
+ readonly translations: Record<string, string>;
3
+ readonly warnings: string[];
4
+ }
5
+ /**
6
+ * Parse AI translation response and validate against source messages.
7
+ * Returns translations with warnings for any QA issues.
8
+ */
9
+ export declare function parseTranslateResponse(response: string, sourceMessages: Record<string, string>): ParseResult;
10
+ //# sourceMappingURL=translate-parse.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"translate-parse.d.ts","sourceRoot":"","sources":["../src/translate-parse.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC7C,QAAQ,CAAC,QAAQ,EAAE,MAAM,EAAE,CAAA;CAC5B;AAsCD;;;GAGG;AACH,wBAAgB,sBAAsB,CACpC,QAAQ,EAAE,MAAM,EAChB,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GACrC,WAAW,CAyEb"}
@@ -0,0 +1,9 @@
1
+ export interface PromptOptions {
2
+ readonly sourceLocale: string;
3
+ readonly targetLocale: string;
4
+ readonly messages: Record<string, string>;
5
+ readonly glossary?: Record<string, string> | undefined;
6
+ readonly context?: string | undefined;
7
+ }
8
+ export declare function buildTranslatePrompt(options: PromptOptions): string;
9
+ //# sourceMappingURL=translate-prompt.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"translate-prompt.d.ts","sourceRoot":"","sources":["../src/translate-prompt.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAA;IAC7B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAA;IAC7B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACzC,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,CAAA;IACtD,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;CACtC;AAED,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,aAAa,GAAG,MAAM,CA6BnE"}
@@ -1,19 +1,21 @@
1
1
  import { CatalogData } from './catalog';
2
- export type AIProvider = 'claude' | 'codex';
3
- export declare function buildPrompt(sourceLocale: string, targetLocale: string, messages: Record<string, string>, context?: string): string;
4
- export declare function extractJSON(text: string): Record<string, string>;
2
+ import { AIProvider } from './ai-provider';
3
+ export type { AIProvider } from './ai-provider';
5
4
  export declare function getUntranslatedEntries(catalog: CatalogData): Record<string, string>;
6
5
  export declare function chunkEntries(entries: Record<string, string>, batchSize: number): Array<Record<string, string>>;
7
6
  export interface TranslateOptions {
8
- provider: AIProvider;
9
- sourceLocale: string;
10
- targetLocale: string;
11
- catalog: CatalogData;
12
- batchSize: number;
13
- context?: string;
7
+ readonly provider: AIProvider;
8
+ readonly sourceLocale: string;
9
+ readonly targetLocale: string;
10
+ readonly catalog: CatalogData;
11
+ readonly batchSize: number;
12
+ readonly context?: string | undefined;
13
+ readonly glossary?: Record<string, string> | undefined;
14
+ readonly timeoutMs?: number | undefined;
14
15
  }
15
16
  export declare function translateCatalog(options: TranslateOptions): Promise<{
16
17
  catalog: CatalogData;
17
18
  translated: number;
19
+ warnings: string[];
18
20
  }>;
19
21
  //# sourceMappingURL=translate.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"translate.d.ts","sourceRoot":"","sources":["../src/translate.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,WAAW,CAAA;AAI5C,MAAM,MAAM,UAAU,GAAG,QAAQ,GAAG,OAAO,CAAA;AAE3C,wBAAgB,WAAW,CACzB,YAAY,EAAE,MAAM,EACpB,YAAY,EAAE,MAAM,EACpB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAChC,OAAO,CAAC,EAAE,MAAM,GACf,MAAM,CAeR;AA2BD,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAgBhE;AAED,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CASnF;AAED,wBAAgB,YAAY,CAC1B,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC/B,SAAS,EAAE,MAAM,GAChB,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAa/B;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,UAAU,CAAA;IACpB,YAAY,EAAE,MAAM,CAAA;IACpB,YAAY,EAAE,MAAM,CAAA;IACpB,OAAO,EAAE,WAAW,CAAA;IACpB,SAAS,EAAE,MAAM,CAAA;IACjB,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB;AAED,wBAAsB,gBAAgB,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC;IACzE,OAAO,EAAE,WAAW,CAAA;IACpB,UAAU,EAAE,MAAM,CAAA;CACnB,CAAC,CA0CD"}
1
+ {"version":3,"file":"translate.d.ts","sourceRoot":"","sources":["../src/translate.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,WAAW,CAAA;AAE5C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAA;AAI/C,YAAY,EAAE,UAAU,EAAE,MAAM,eAAe,CAAA;AAE/C,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CASnF;AAED,wBAAgB,YAAY,CAC1B,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC/B,SAAS,EAAE,MAAM,GAChB,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAa/B;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,QAAQ,EAAE,UAAU,CAAA;IAC7B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAA;IAC7B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAA;IAC7B,QAAQ,CAAC,OAAO,EAAE,WAAW,CAAA;IAC7B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IACrC,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,CAAA;IACtD,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;CACxC;AAED,wBAAsB,gBAAgB,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC;IACzE,OAAO,EAAE,WAAW,CAAA;IACpB,UAAU,EAAE,MAAM,CAAA;IAClB,QAAQ,EAAE,MAAM,EAAE,CAAA;CACnB,CAAC,CA0DD"}