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/index.js
CHANGED
|
@@ -1869,23 +1869,43 @@ function validateDocumentAssets(config, input) {
|
|
|
1869
1869
|
return issues;
|
|
1870
1870
|
}
|
|
1871
1871
|
|
|
1872
|
+
// src/core/localized-slug.ts
|
|
1873
|
+
function findLocaleSuffixInSlug(slug, localeCodes) {
|
|
1874
|
+
const sorted = [...localeCodes].sort((a, b) => b.length - a.length);
|
|
1875
|
+
for (const code of sorted) {
|
|
1876
|
+
if (slug.endsWith(`-${code}`)) {
|
|
1877
|
+
return code;
|
|
1878
|
+
}
|
|
1879
|
+
}
|
|
1880
|
+
return void 0;
|
|
1881
|
+
}
|
|
1882
|
+
function stripLocaleSuffixFromSlug(slug, localeCodes) {
|
|
1883
|
+
const matchedCode = findLocaleSuffixInSlug(slug, localeCodes);
|
|
1884
|
+
if (!matchedCode) {
|
|
1885
|
+
return { slug, stripped: false };
|
|
1886
|
+
}
|
|
1887
|
+
return {
|
|
1888
|
+
slug: slug.slice(0, -(matchedCode.length + 1)),
|
|
1889
|
+
stripped: true,
|
|
1890
|
+
matchedCode
|
|
1891
|
+
};
|
|
1892
|
+
}
|
|
1893
|
+
|
|
1872
1894
|
// src/validate/validate-slug-suffix.ts
|
|
1873
1895
|
function validateTranslationSlugSuffixes(config, db) {
|
|
1874
1896
|
const issues = [];
|
|
1875
1897
|
const localeCodes = config.locales.filter((l) => l !== config.defaultLocale);
|
|
1876
1898
|
for (const row of bulkLoadTranslations(db)) {
|
|
1877
1899
|
if (row.locale === config.defaultLocale) continue;
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
break;
|
|
1888
|
-
}
|
|
1900
|
+
const matchedCode = findLocaleSuffixInSlug(row.slug, localeCodes);
|
|
1901
|
+
if (matchedCode) {
|
|
1902
|
+
issues.push({
|
|
1903
|
+
contentTypeId: row.content_type,
|
|
1904
|
+
enSlug: row.en_slug,
|
|
1905
|
+
locale: row.locale,
|
|
1906
|
+
slug: row.slug,
|
|
1907
|
+
message: `Translation slug "${row.slug}" ends with locale code "-${matchedCode}"`
|
|
1908
|
+
});
|
|
1889
1909
|
}
|
|
1890
1910
|
}
|
|
1891
1911
|
return issues;
|
|
@@ -2033,7 +2053,7 @@ function validateProject(config) {
|
|
|
2033
2053
|
try {
|
|
2034
2054
|
for (const issue of validateTranslationSlugSuffixes(config, dbForSuffix)) {
|
|
2035
2055
|
issues.push({
|
|
2036
|
-
level: "
|
|
2056
|
+
level: "warning",
|
|
2037
2057
|
contentType: issue.contentTypeId,
|
|
2038
2058
|
enSlug: issue.enSlug,
|
|
2039
2059
|
locale: issue.locale,
|
|
@@ -2252,6 +2272,9 @@ function buildPageTranslationPrompt(input) {
|
|
|
2252
2272
|
...input.contextLabel ? [`Document: ${input.contextLabel}`, ""] : [],
|
|
2253
2273
|
"## Rules",
|
|
2254
2274
|
...input.resolved.rules.map((rule) => `- ${rule}`),
|
|
2275
|
+
...input.slugStrategy === "localized" ? [
|
|
2276
|
+
`- 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.`
|
|
2277
|
+
] : [],
|
|
2255
2278
|
"",
|
|
2256
2279
|
"## Output format",
|
|
2257
2280
|
"Return ONLY valid JSON with keys:",
|
|
@@ -2335,9 +2358,11 @@ function buildGeminiResponseSchema(schema, slugStrategy) {
|
|
|
2335
2358
|
function slugStrategyRules(slugStrategy, preserveTerms) {
|
|
2336
2359
|
if (slugStrategy === "localized") {
|
|
2337
2360
|
const rules = [
|
|
2338
|
-
"Provide a
|
|
2361
|
+
"Provide a URL slug in JSON field `slug` that is TRANSLATED into the target language.",
|
|
2362
|
+
"Base the slug on the meaning of the translated title \u2014 do NOT reuse the English slug words.",
|
|
2339
2363
|
"Slug MUST be ASCII only: a-z, 0-9, hyphens. No uppercase, accents, underscores, or spaces.",
|
|
2340
|
-
"For non-Latin
|
|
2364
|
+
"For non-Latin languages, write the words in the target language and transliterate them into Latin script (e.g. Russian -> romanized Russian, not English).",
|
|
2365
|
+
"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."
|
|
2341
2366
|
];
|
|
2342
2367
|
if (preserveTerms?.length) {
|
|
2343
2368
|
rules.push(
|
|
@@ -2495,7 +2520,10 @@ async function translatePage(config, item, options = {}) {
|
|
|
2495
2520
|
model,
|
|
2496
2521
|
responseSchema: responseSchema ?? void 0
|
|
2497
2522
|
});
|
|
2498
|
-
const
|
|
2523
|
+
const rawSlug = type.slugStrategy === "localized" ? result.parsed.slug ?? existing?.slug ?? item.enSlug : item.enSlug;
|
|
2524
|
+
const localeCodes = config.locales.filter((l) => l !== config.defaultLocale);
|
|
2525
|
+
const { slug, stripped, matchedCode } = stripLocaleSuffixFromSlug(rawSlug, localeCodes);
|
|
2526
|
+
const slugAdjusted = stripped && matchedCode ? { from: rawSlug, to: slug, matchedCode } : void 0;
|
|
2499
2527
|
const validated = validateTranslatedFrontmatter(enDoc, result.parsed.frontmatter, type.schema);
|
|
2500
2528
|
if (!validated.ok) {
|
|
2501
2529
|
throw new Error(`Translation validation failed: ${validated.error}`);
|
|
@@ -2536,7 +2564,8 @@ async function translatePage(config, item, options = {}) {
|
|
|
2536
2564
|
model: result.model,
|
|
2537
2565
|
usage: result.usage,
|
|
2538
2566
|
estimatedCostUsd,
|
|
2539
|
-
durationMs: Date.now() - startedAt
|
|
2567
|
+
durationMs: Date.now() - startedAt,
|
|
2568
|
+
slugAdjusted
|
|
2540
2569
|
};
|
|
2541
2570
|
} catch (error) {
|
|
2542
2571
|
return {
|