glotfile 0.4.1 → 0.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/bin/glotfile.js CHANGED
File without changes
@@ -1590,6 +1590,7 @@ function buildSystemPrompt(hasPluralItems) {
1590
1590
  function buildBatchPrompt(reqs) {
1591
1591
  const targetLocale = reqs[0]?.targetLocale ?? "";
1592
1592
  const hasPluralItems = reqs.some((r) => r.plural !== void 0);
1593
+ const hasGlossaryItems = reqs.some((r) => r.glossary !== void 0 && r.glossary.length > 0);
1593
1594
  const items = reqs.map((r) => {
1594
1595
  const base = {
1595
1596
  id: r.id,
@@ -1599,7 +1600,7 @@ function buildBatchPrompt(reqs) {
1599
1600
  // Wrap in braces so the model sees "{site}" not "site" — makes the visual
1600
1601
  // connection to the source string obvious and reduces rename errors.
1601
1602
  placeholders: r.placeholders.map((p) => `{${p}}`),
1602
- glossary: r.glossary ?? [],
1603
+ ...r.glossary?.length ? { glossary: r.glossary } : {},
1603
1604
  hasScreenshot: r.image !== void 0
1604
1605
  };
1605
1606
  if (r.plural) {
@@ -1609,7 +1610,7 @@ function buildBatchPrompt(reqs) {
1609
1610
  });
1610
1611
  const returnFormat = hasPluralItems ? 'For a scalar item (has `source`) return {"id","translation"}; for a plural item (has `plural`) return {"id","forms"} with one string per required category.' : 'Return {"id","translation"} for each item.';
1611
1612
  return `Translate every item below into the target locale: ${targetLocale}. All items share this one target language.
1612
- Glossary entries are constraints you MUST apply. Items with hasScreenshot:true have a screenshot supplied as a separate image block above; use it for context. ${returnFormat} Return JSON {"items":[\u2026]}.
1613
+ ` + (hasGlossaryItems ? "Glossary entries are constraints you MUST apply. " : "") + `Items with hasScreenshot:true have a screenshot supplied as a separate image block above; use it for context. ${returnFormat} Return JSON {"items":[\u2026]}.
1613
1614
  ` + JSON.stringify(items, null, 2);
1614
1615
  }
1615
1616
  function buildTranslateGemmaSystemPrompt(sourceLocale, targetLocale) {
@@ -4470,7 +4471,7 @@ function createApi(deps) {
4470
4471
  await stream.writeSSE({ event: "error", data: JSON.stringify({ error: e.message }) });
4471
4472
  return;
4472
4473
  }
4473
- const { skipped } = attachScreenshotsForProvider(reqs, s, projectRoot, provider.supportsVision());
4474
+ const { skipped } = attachScreenshotsForProvider(reqs, s, dirname2(resolve9(deps.statePath)), provider.supportsVision());
4474
4475
  if (skipped) console.warn(`Model "${aiCfg.model}" has no vision support; ${skipped} screenshot(s) ignored.`);
4475
4476
  console.log(`[translate] ${reqs.length} string(s) \u2192 ${aiCfg.model}`);
4476
4477
  let totalWritten = 0;
@@ -4548,7 +4549,7 @@ function createApi(deps) {
4548
4549
  } catch (e) {
4549
4550
  return c.json({ error: e.message }, 400);
4550
4551
  }
4551
- const { skipped } = attachScreenshotsForProvider(toTranslate, s, projectRoot, provider.supportsVision());
4552
+ const { skipped } = attachScreenshotsForProvider(toTranslate, s, dirname2(resolve9(deps.statePath)), provider.supportsVision());
4552
4553
  if (skipped) console.warn(`Model "${aiCfg.model}" has no vision support; ${skipped} screenshot(s) ignored.`);
4553
4554
  const results = await runLocaleParallel(toTranslate, provider, {}, aiCfg.concurrency);
4554
4555
  const latest = load();
@@ -4777,12 +4778,12 @@ async function readFileResponse(absPath) {
4777
4778
  }
4778
4779
  function buildApp(opts) {
4779
4780
  const app = new Hono2();
4780
- app.route("/api", createApi({ statePath: opts.statePath, autoExport: true }));
4781
- const projectRoot = dirname3(resolve10(opts.statePath));
4781
+ const apiDeps = { statePath: opts.statePath, autoExport: true };
4782
+ app.route("/api", createApi(apiDeps));
4782
4783
  app.get("/:dir/*", async (c, next) => {
4783
4784
  const dirSeg = c.req.param("dir");
4784
4785
  if (!dirSeg.endsWith("-screenshots")) return next();
4785
- const shotsRoot = resolve10(projectRoot, dirSeg);
4786
+ const shotsRoot = resolve10(dirname3(resolve10(apiDeps.statePath)), dirSeg);
4786
4787
  const pathname = decodeURIComponent(new URL(c.req.url).pathname);
4787
4788
  const rest = pathname.slice(`/${dirSeg}`.length);
4788
4789
  const target = resolve10(shotsRoot, "." + rest);
@@ -2376,6 +2376,7 @@ function buildSystemPrompt(hasPluralItems) {
2376
2376
  function buildBatchPrompt(reqs) {
2377
2377
  const targetLocale = reqs[0]?.targetLocale ?? "";
2378
2378
  const hasPluralItems = reqs.some((r) => r.plural !== void 0);
2379
+ const hasGlossaryItems = reqs.some((r) => r.glossary !== void 0 && r.glossary.length > 0);
2379
2380
  const items = reqs.map((r) => {
2380
2381
  const base = {
2381
2382
  id: r.id,
@@ -2385,7 +2386,7 @@ function buildBatchPrompt(reqs) {
2385
2386
  // Wrap in braces so the model sees "{site}" not "site" — makes the visual
2386
2387
  // connection to the source string obvious and reduces rename errors.
2387
2388
  placeholders: r.placeholders.map((p) => `{${p}}`),
2388
- glossary: r.glossary ?? [],
2389
+ ...r.glossary?.length ? { glossary: r.glossary } : {},
2389
2390
  hasScreenshot: r.image !== void 0
2390
2391
  };
2391
2392
  if (r.plural) {
@@ -2395,7 +2396,7 @@ function buildBatchPrompt(reqs) {
2395
2396
  });
2396
2397
  const returnFormat = hasPluralItems ? 'For a scalar item (has `source`) return {"id","translation"}; for a plural item (has `plural`) return {"id","forms"} with one string per required category.' : 'Return {"id","translation"} for each item.';
2397
2398
  return `Translate every item below into the target locale: ${targetLocale}. All items share this one target language.
2398
- Glossary entries are constraints you MUST apply. Items with hasScreenshot:true have a screenshot supplied as a separate image block above; use it for context. ${returnFormat} Return JSON {"items":[\u2026]}.
2399
+ ` + (hasGlossaryItems ? "Glossary entries are constraints you MUST apply. " : "") + `Items with hasScreenshot:true have a screenshot supplied as a separate image block above; use it for context. ${returnFormat} Return JSON {"items":[\u2026]}.
2399
2400
  ` + JSON.stringify(items, null, 2);
2400
2401
  }
2401
2402
  function buildTranslateGemmaSystemPrompt(sourceLocale, targetLocale) {
@@ -4100,7 +4101,7 @@ function createApi(deps) {
4100
4101
  await stream.writeSSE({ event: "error", data: JSON.stringify({ error: e.message }) });
4101
4102
  return;
4102
4103
  }
4103
- const { skipped } = attachScreenshotsForProvider(reqs, s, projectRoot, provider.supportsVision());
4104
+ const { skipped } = attachScreenshotsForProvider(reqs, s, dirname2(resolve8(deps.statePath)), provider.supportsVision());
4104
4105
  if (skipped) console.warn(`Model "${aiCfg.model}" has no vision support; ${skipped} screenshot(s) ignored.`);
4105
4106
  console.log(`[translate] ${reqs.length} string(s) \u2192 ${aiCfg.model}`);
4106
4107
  let totalWritten = 0;
@@ -4178,7 +4179,7 @@ function createApi(deps) {
4178
4179
  } catch (e) {
4179
4180
  return c.json({ error: e.message }, 400);
4180
4181
  }
4181
- const { skipped } = attachScreenshotsForProvider(toTranslate, s, projectRoot, provider.supportsVision());
4182
+ const { skipped } = attachScreenshotsForProvider(toTranslate, s, dirname2(resolve8(deps.statePath)), provider.supportsVision());
4182
4183
  if (skipped) console.warn(`Model "${aiCfg.model}" has no vision support; ${skipped} screenshot(s) ignored.`);
4183
4184
  const results = await runLocaleParallel(toTranslate, provider, {}, aiCfg.concurrency);
4184
4185
  const latest = load();
@@ -4386,12 +4387,12 @@ async function readFileResponse(absPath) {
4386
4387
  }
4387
4388
  function buildApp(opts) {
4388
4389
  const app = new Hono2();
4389
- app.route("/api", createApi({ statePath: opts.statePath, autoExport: true }));
4390
- const projectRoot = dirname3(resolve9(opts.statePath));
4390
+ const apiDeps = { statePath: opts.statePath, autoExport: true };
4391
+ app.route("/api", createApi(apiDeps));
4391
4392
  app.get("/:dir/*", async (c, next) => {
4392
4393
  const dirSeg = c.req.param("dir");
4393
4394
  if (!dirSeg.endsWith("-screenshots")) return next();
4394
- const shotsRoot = resolve9(projectRoot, dirSeg);
4395
+ const shotsRoot = resolve9(dirname3(resolve9(apiDeps.statePath)), dirSeg);
4395
4396
  const pathname = decodeURIComponent(new URL(c.req.url).pathname);
4396
4397
  const rest = pathname.slice(`/${dirSeg}`.length);
4397
4398
  const target = resolve9(shotsRoot, "." + rest);