scribe-cms 0.0.6 → 0.0.7
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/dist/cli/index.cjs +71 -29
- package/dist/cli/index.cjs.map +1 -1
- package/dist/cli/index.js +70 -28
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/translate-progress.d.ts.map +1 -1
- package/dist/index.cjs +45 -16
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +45 -16
- package/dist/index.js.map +1 -1
- package/dist/src/core/localized-slug.d.ts +8 -0
- package/dist/src/core/localized-slug.d.ts.map +1 -0
- package/dist/src/translate/page-translator.d.ts +5 -0
- package/dist/src/translate/page-translator.d.ts.map +1 -1
- package/dist/src/translate/prompts/translation-prompt.d.ts.map +1 -1
- package/dist/src/translate/resolve-translate-config.d.ts.map +1 -1
- package/dist/src/validate/validate-slug-suffix.d.ts.map +1 -1
- package/package.json +2 -1
package/dist/cli/index.cjs
CHANGED
|
@@ -12,6 +12,7 @@ var genai = require('@google/genai');
|
|
|
12
12
|
var dotenv = require('dotenv');
|
|
13
13
|
var nodeServer = require('@hono/node-server');
|
|
14
14
|
var hono = require('hono');
|
|
15
|
+
var core = require('@inquirer/core');
|
|
15
16
|
var prompts = require('@inquirer/prompts');
|
|
16
17
|
var url = require('url');
|
|
17
18
|
|
|
@@ -25,7 +26,6 @@ var dotenv__default = /*#__PURE__*/_interopDefault(dotenv);
|
|
|
25
26
|
|
|
26
27
|
var __defProp = Object.defineProperty;
|
|
27
28
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
28
|
-
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
29
29
|
var __esm = (fn, res) => function __init() {
|
|
30
30
|
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
31
31
|
};
|
|
@@ -33,7 +33,6 @@ var __export = (target, all) => {
|
|
|
33
33
|
for (var name in all)
|
|
34
34
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
35
35
|
};
|
|
36
|
-
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
37
36
|
|
|
38
37
|
// ../../node_modules/tsup/assets/cjs_shims.js
|
|
39
38
|
var getImportMetaUrl, importMetaUrl;
|
|
@@ -1642,22 +1641,45 @@ function validateDocumentAssets(config, input) {
|
|
|
1642
1641
|
|
|
1643
1642
|
// src/validate/validate-slug-suffix.ts
|
|
1644
1643
|
init_cjs_shims();
|
|
1644
|
+
|
|
1645
|
+
// src/core/localized-slug.ts
|
|
1646
|
+
init_cjs_shims();
|
|
1647
|
+
function findLocaleSuffixInSlug(slug, localeCodes) {
|
|
1648
|
+
const sorted = [...localeCodes].sort((a, b) => b.length - a.length);
|
|
1649
|
+
for (const code of sorted) {
|
|
1650
|
+
if (slug.endsWith(`-${code}`)) {
|
|
1651
|
+
return code;
|
|
1652
|
+
}
|
|
1653
|
+
}
|
|
1654
|
+
return void 0;
|
|
1655
|
+
}
|
|
1656
|
+
function stripLocaleSuffixFromSlug(slug, localeCodes) {
|
|
1657
|
+
const matchedCode = findLocaleSuffixInSlug(slug, localeCodes);
|
|
1658
|
+
if (!matchedCode) {
|
|
1659
|
+
return { slug, stripped: false };
|
|
1660
|
+
}
|
|
1661
|
+
return {
|
|
1662
|
+
slug: slug.slice(0, -(matchedCode.length + 1)),
|
|
1663
|
+
stripped: true,
|
|
1664
|
+
matchedCode
|
|
1665
|
+
};
|
|
1666
|
+
}
|
|
1667
|
+
|
|
1668
|
+
// src/validate/validate-slug-suffix.ts
|
|
1645
1669
|
function validateTranslationSlugSuffixes(config, db) {
|
|
1646
1670
|
const issues = [];
|
|
1647
1671
|
const localeCodes = config.locales.filter((l) => l !== config.defaultLocale);
|
|
1648
1672
|
for (const row of bulkLoadTranslations(db)) {
|
|
1649
1673
|
if (row.locale === config.defaultLocale) continue;
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
break;
|
|
1660
|
-
}
|
|
1674
|
+
const matchedCode = findLocaleSuffixInSlug(row.slug, localeCodes);
|
|
1675
|
+
if (matchedCode) {
|
|
1676
|
+
issues.push({
|
|
1677
|
+
contentTypeId: row.content_type,
|
|
1678
|
+
enSlug: row.en_slug,
|
|
1679
|
+
locale: row.locale,
|
|
1680
|
+
slug: row.slug,
|
|
1681
|
+
message: `Translation slug "${row.slug}" ends with locale code "-${matchedCode}"`
|
|
1682
|
+
});
|
|
1661
1683
|
}
|
|
1662
1684
|
}
|
|
1663
1685
|
return issues;
|
|
@@ -1805,7 +1827,7 @@ function validateProject(config) {
|
|
|
1805
1827
|
try {
|
|
1806
1828
|
for (const issue of validateTranslationSlugSuffixes(config, dbForSuffix)) {
|
|
1807
1829
|
issues.push({
|
|
1808
|
-
level: "
|
|
1830
|
+
level: "warning",
|
|
1809
1831
|
contentType: issue.contentTypeId,
|
|
1810
1832
|
enSlug: issue.enSlug,
|
|
1811
1833
|
locale: issue.locale,
|
|
@@ -2056,6 +2078,9 @@ function buildPageTranslationPrompt(input) {
|
|
|
2056
2078
|
...input.contextLabel ? [`Document: ${input.contextLabel}`, ""] : [],
|
|
2057
2079
|
"## Rules",
|
|
2058
2080
|
...input.resolved.rules.map((rule) => `- ${rule}`),
|
|
2081
|
+
...input.slugStrategy === "localized" ? [
|
|
2082
|
+
`- The slug MUST be written in ${localeName}, derived from the ${localeName} title and its meaning \u2014 never the English slug. Transliterate non-Latin ${localeName} into ASCII Latin.`
|
|
2083
|
+
] : [],
|
|
2059
2084
|
"",
|
|
2060
2085
|
"## Output format",
|
|
2061
2086
|
"Return ONLY valid JSON with keys:",
|
|
@@ -2143,9 +2168,11 @@ init_cjs_shims();
|
|
|
2143
2168
|
function slugStrategyRules(slugStrategy, preserveTerms) {
|
|
2144
2169
|
if (slugStrategy === "localized") {
|
|
2145
2170
|
const rules = [
|
|
2146
|
-
"Provide a
|
|
2171
|
+
"Provide a URL slug in JSON field `slug` that is TRANSLATED into the target language.",
|
|
2172
|
+
"Base the slug on the meaning of the translated title \u2014 do NOT reuse the English slug words.",
|
|
2147
2173
|
"Slug MUST be ASCII only: a-z, 0-9, hyphens. No uppercase, accents, underscores, or spaces.",
|
|
2148
|
-
"For non-Latin
|
|
2174
|
+
"For non-Latin languages, write the words in the target language and transliterate them into Latin script (e.g. Russian -> romanized Russian, not English).",
|
|
2175
|
+
"Do NOT append locale codes to the slug (e.g. -fr, -he, -zh-cn). Locale routing is handled by the URL prefix, not the slug."
|
|
2149
2176
|
];
|
|
2150
2177
|
if (preserveTerms?.length) {
|
|
2151
2178
|
rules.push(
|
|
@@ -2304,7 +2331,10 @@ async function translatePage(config, item, options = {}) {
|
|
|
2304
2331
|
model,
|
|
2305
2332
|
responseSchema: responseSchema ?? void 0
|
|
2306
2333
|
});
|
|
2307
|
-
const
|
|
2334
|
+
const rawSlug = type.slugStrategy === "localized" ? result.parsed.slug ?? existing?.slug ?? item.enSlug : item.enSlug;
|
|
2335
|
+
const localeCodes = config.locales.filter((l) => l !== config.defaultLocale);
|
|
2336
|
+
const { slug, stripped, matchedCode } = stripLocaleSuffixFromSlug(rawSlug, localeCodes);
|
|
2337
|
+
const slugAdjusted = stripped && matchedCode ? { from: rawSlug, to: slug, matchedCode } : void 0;
|
|
2308
2338
|
const validated = validateTranslatedFrontmatter(enDoc, result.parsed.frontmatter, type.schema);
|
|
2309
2339
|
if (!validated.ok) {
|
|
2310
2340
|
throw new Error(`Translation validation failed: ${validated.error}`);
|
|
@@ -2345,7 +2375,8 @@ async function translatePage(config, item, options = {}) {
|
|
|
2345
2375
|
model: result.model,
|
|
2346
2376
|
usage: result.usage,
|
|
2347
2377
|
estimatedCostUsd,
|
|
2348
|
-
durationMs: Date.now() - startedAt
|
|
2378
|
+
durationMs: Date.now() - startedAt,
|
|
2379
|
+
slugAdjusted
|
|
2349
2380
|
};
|
|
2350
2381
|
} catch (error) {
|
|
2351
2382
|
return {
|
|
@@ -2971,16 +3002,6 @@ async function startStudio(project, options = {}) {
|
|
|
2971
3002
|
|
|
2972
3003
|
// cli/prompt-translate.ts
|
|
2973
3004
|
init_cjs_shims();
|
|
2974
|
-
|
|
2975
|
-
// ../../node_modules/@inquirer/core/dist/lib/errors.js
|
|
2976
|
-
init_cjs_shims();
|
|
2977
|
-
var CancelPromptError = class extends Error {
|
|
2978
|
-
constructor() {
|
|
2979
|
-
super(...arguments);
|
|
2980
|
-
__publicField(this, "name", "CancelPromptError");
|
|
2981
|
-
__publicField(this, "message", "Prompt was canceled");
|
|
2982
|
-
}
|
|
2983
|
-
};
|
|
2984
3005
|
function isInteractive() {
|
|
2985
3006
|
return process.stdin.isTTY === true && process.stdout.isTTY === true;
|
|
2986
3007
|
}
|
|
@@ -2991,7 +3012,7 @@ async function runPrompt(prompt) {
|
|
|
2991
3012
|
try {
|
|
2992
3013
|
return await prompt;
|
|
2993
3014
|
} catch (error) {
|
|
2994
|
-
if (error instanceof CancelPromptError) process.exit(0);
|
|
3015
|
+
if (error instanceof core.CancelPromptError) process.exit(0);
|
|
2995
3016
|
throw error;
|
|
2996
3017
|
}
|
|
2997
3018
|
}
|
|
@@ -3092,8 +3113,17 @@ function statusForResult(result, dryRun) {
|
|
|
3092
3113
|
if (dryRun) return yellow("would translate");
|
|
3093
3114
|
return green("translated");
|
|
3094
3115
|
}
|
|
3116
|
+
function slugAdjustedMessage(result) {
|
|
3117
|
+
if (!result.slugAdjusted) return void 0;
|
|
3118
|
+
const { from, to, matchedCode } = result.slugAdjusted;
|
|
3119
|
+
return yellow(
|
|
3120
|
+
`slug adjusted: "${from}" \u2192 "${to}" (stripped -${matchedCode})`
|
|
3121
|
+
);
|
|
3122
|
+
}
|
|
3095
3123
|
function detailForResult(result) {
|
|
3096
3124
|
const parts = [];
|
|
3125
|
+
const slugMsg = slugAdjustedMessage(result);
|
|
3126
|
+
if (slugMsg) parts.push(slugMsg);
|
|
3097
3127
|
if (result.durationMs !== void 0) parts.push(`${(result.durationMs / 1e3).toFixed(1)}s`);
|
|
3098
3128
|
if (result.usage) {
|
|
3099
3129
|
parts.push(`${formatTokenCount(result.usage.inputTokens)} in`);
|
|
@@ -3127,6 +3157,10 @@ function createTranslateProgressReporter(options = {}) {
|
|
|
3127
3157
|
const status = statusForResult(event.result, dryRun);
|
|
3128
3158
|
const detail = detailForResult(event.result);
|
|
3129
3159
|
console.log(`${label}: ${status}${detail ? ` (${detail.replace(/\x1b\[[0-9;]*m/g, "")})` : ""}`);
|
|
3160
|
+
const slugMsg = slugAdjustedMessage(event.result);
|
|
3161
|
+
if (slugMsg) {
|
|
3162
|
+
console.log(`[warning] ${labelForResult(event.result)} ${slugMsg.replace(/\x1b\[[0-9;]*m/g, "")}`);
|
|
3163
|
+
}
|
|
3130
3164
|
if (event.result.failed && event.result.error) {
|
|
3131
3165
|
console.error(event.result.error);
|
|
3132
3166
|
}
|
|
@@ -3230,6 +3264,14 @@ function createTranslateProgressReporter(options = {}) {
|
|
|
3230
3264
|
for (const result of event.results.filter((entry) => entry.failed)) {
|
|
3231
3265
|
process.stdout.write("\x1B[2K" + red(`${labelForResult(result)}: ${result.error ?? "failed"}`) + "\n");
|
|
3232
3266
|
}
|
|
3267
|
+
for (const result of event.results.filter((entry) => entry.slugAdjusted)) {
|
|
3268
|
+
const slugMsg = slugAdjustedMessage(result);
|
|
3269
|
+
if (slugMsg) {
|
|
3270
|
+
process.stdout.write(
|
|
3271
|
+
"\x1B[2K" + yellow(`[warning] ${labelForResult(result)} ${slugMsg.replace(/\x1b\[[0-9;]*m/g, "")}`) + "\n"
|
|
3272
|
+
);
|
|
3273
|
+
}
|
|
3274
|
+
}
|
|
3233
3275
|
break;
|
|
3234
3276
|
}
|
|
3235
3277
|
},
|