scribe-cms 0.0.10 → 0.0.12
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 +193 -111
- package/dist/cli/index.cjs.map +1 -1
- package/dist/cli/index.js +191 -111
- package/dist/cli/index.js.map +1 -1
- package/dist/index.cjs +188 -110
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +186 -110
- package/dist/index.js.map +1 -1
- package/dist/runtime.cjs +118 -1
- package/dist/runtime.cjs.map +1 -1
- package/dist/runtime.js +116 -1
- package/dist/runtime.js.map +1 -1
- package/dist/src/core/types.d.ts +0 -2
- package/dist/src/core/types.d.ts.map +1 -1
- package/dist/src/loader/create-loader.d.ts.map +1 -1
- package/dist/src/translate/gemini-client.d.ts +5 -0
- package/dist/src/translate/gemini-client.d.ts.map +1 -1
- package/dist/src/translate/normalize-mdx-body.d.ts +9 -0
- package/dist/src/translate/normalize-mdx-body.d.ts.map +1 -0
- package/dist/src/translate/resolve-translate-config.d.ts.map +1 -1
- package/dist/src/translate/validate-mdx-body.d.ts +16 -0
- package/dist/src/translate/validate-mdx-body.d.ts.map +1 -0
- package/dist/src/validate/validate-project.d.ts.map +1 -1
- package/dist/studio/server.cjs +6 -0
- package/dist/studio/server.cjs.map +1 -1
- package/dist/studio/server.js +4 -0
- package/dist/studio/server.js.map +1 -1
- package/package.json +5 -2
package/dist/cli/index.js
CHANGED
|
@@ -5,6 +5,9 @@ import fs2 from 'fs';
|
|
|
5
5
|
import Database from 'better-sqlite3';
|
|
6
6
|
import { z } from 'zod';
|
|
7
7
|
import matter from 'gray-matter';
|
|
8
|
+
import remarkMdx from 'remark-mdx';
|
|
9
|
+
import remarkParse from 'remark-parse';
|
|
10
|
+
import { unified } from 'unified';
|
|
8
11
|
import { createJiti } from 'jiti';
|
|
9
12
|
import { createHash } from 'crypto';
|
|
10
13
|
import { GoogleGenAI } from '@google/genai';
|
|
@@ -712,6 +715,140 @@ function bulkLoadTranslations(db) {
|
|
|
712
715
|
return db.prepare(`SELECT * FROM translations ORDER BY content_type, en_slug, locale`).all();
|
|
713
716
|
}
|
|
714
717
|
|
|
718
|
+
// src/translate/validate-mdx-body.ts
|
|
719
|
+
init_esm_shims();
|
|
720
|
+
|
|
721
|
+
// src/translate/normalize-mdx-body.ts
|
|
722
|
+
init_esm_shims();
|
|
723
|
+
function needsMdxEscapeNormalization(body) {
|
|
724
|
+
return /\\n[ \t/>]|<[\w.-][^>]*\\n/.test(body);
|
|
725
|
+
}
|
|
726
|
+
function normalizeTranslatedMdxBody(body) {
|
|
727
|
+
if (!needsMdxEscapeNormalization(body)) {
|
|
728
|
+
return { body, adjusted: false };
|
|
729
|
+
}
|
|
730
|
+
const normalized = body.replace(/\\r\\n/g, "\n").replace(/\\n/g, "\n").replace(/\\t/g, " ").replace(/\\"/g, '"').replace(/\\\\/g, "\\");
|
|
731
|
+
return { body: normalized, adjusted: normalized !== body };
|
|
732
|
+
}
|
|
733
|
+
|
|
734
|
+
// src/translate/sanitize-mdx-jsx.ts
|
|
735
|
+
init_esm_shims();
|
|
736
|
+
function sanitizeMdxJsxAttributeQuotes(body) {
|
|
737
|
+
let adjusted = false;
|
|
738
|
+
let out = "";
|
|
739
|
+
let i = 0;
|
|
740
|
+
while (i < body.length) {
|
|
741
|
+
if (body[i] !== "<" || !/[\w.]/.test(body[i + 1] ?? "")) {
|
|
742
|
+
out += body[i];
|
|
743
|
+
i += 1;
|
|
744
|
+
continue;
|
|
745
|
+
}
|
|
746
|
+
const tagStart = i;
|
|
747
|
+
i += 1;
|
|
748
|
+
while (i < body.length && /[\w.-]/.test(body[i] ?? "")) i += 1;
|
|
749
|
+
const tagName = body.slice(tagStart + 1, i);
|
|
750
|
+
let tagOut = `<${tagName}`;
|
|
751
|
+
let tagAdjusted = false;
|
|
752
|
+
while (i < body.length && body[i] !== ">" && body[i] !== "/") {
|
|
753
|
+
while (i < body.length && /\s/.test(body[i] ?? "")) {
|
|
754
|
+
tagOut += body[i];
|
|
755
|
+
i += 1;
|
|
756
|
+
}
|
|
757
|
+
if (i >= body.length || body[i] === ">" || body[i] === "/") break;
|
|
758
|
+
const attrStart = i;
|
|
759
|
+
while (i < body.length && /[\w:.-]/.test(body[i] ?? "")) i += 1;
|
|
760
|
+
body.slice(attrStart, i);
|
|
761
|
+
while (i < body.length && /\s/.test(body[i] ?? "")) i += 1;
|
|
762
|
+
if (body[i] !== "=") {
|
|
763
|
+
tagOut += body.slice(attrStart, i);
|
|
764
|
+
continue;
|
|
765
|
+
}
|
|
766
|
+
tagOut += body.slice(attrStart, i);
|
|
767
|
+
tagOut += "=";
|
|
768
|
+
i += 1;
|
|
769
|
+
while (i < body.length && /\s/.test(body[i] ?? "")) i += 1;
|
|
770
|
+
const quote = body[i];
|
|
771
|
+
if (quote !== '"' && quote !== "'") {
|
|
772
|
+
continue;
|
|
773
|
+
}
|
|
774
|
+
if (quote === "'") {
|
|
775
|
+
const valStart2 = i + 1;
|
|
776
|
+
i += 1;
|
|
777
|
+
while (i < body.length) {
|
|
778
|
+
if (body[i] === "\\") {
|
|
779
|
+
i += 2;
|
|
780
|
+
continue;
|
|
781
|
+
}
|
|
782
|
+
if (body[i] === "'") break;
|
|
783
|
+
i += 1;
|
|
784
|
+
}
|
|
785
|
+
tagOut += body.slice(valStart2 - 1, i + 1);
|
|
786
|
+
i += 1;
|
|
787
|
+
continue;
|
|
788
|
+
}
|
|
789
|
+
const valStart = i + 1;
|
|
790
|
+
i += 1;
|
|
791
|
+
let closeIdx = -1;
|
|
792
|
+
for (let scan = valStart; scan < body.length; scan += 1) {
|
|
793
|
+
if (body[scan] !== '"') continue;
|
|
794
|
+
let j = scan + 1;
|
|
795
|
+
while (j < body.length && /\s/.test(body[j] ?? "")) j += 1;
|
|
796
|
+
if (j < body.length && (body[j] === ">" || body[j] === "/" || /[a-zA-Z]/.test(body[j] ?? ""))) {
|
|
797
|
+
closeIdx = scan;
|
|
798
|
+
break;
|
|
799
|
+
}
|
|
800
|
+
}
|
|
801
|
+
if (closeIdx === -1) {
|
|
802
|
+
tagOut += body.slice(valStart - 1, i);
|
|
803
|
+
break;
|
|
804
|
+
}
|
|
805
|
+
const value = body.slice(valStart, closeIdx);
|
|
806
|
+
const hasInternalQuote = value.includes('"');
|
|
807
|
+
if (hasInternalQuote) {
|
|
808
|
+
const escaped = value.replace(/\\/g, "\\\\").replace(/'/g, "\\'");
|
|
809
|
+
tagOut += `'${escaped}'`;
|
|
810
|
+
tagAdjusted = true;
|
|
811
|
+
} else {
|
|
812
|
+
tagOut += `"${value}"`;
|
|
813
|
+
}
|
|
814
|
+
i = closeIdx + 1;
|
|
815
|
+
}
|
|
816
|
+
if (tagAdjusted) adjusted = true;
|
|
817
|
+
tagOut += body[i] ?? "";
|
|
818
|
+
out += tagOut;
|
|
819
|
+
i += 1;
|
|
820
|
+
}
|
|
821
|
+
return { body: out, adjusted };
|
|
822
|
+
}
|
|
823
|
+
|
|
824
|
+
// src/translate/validate-mdx-body.ts
|
|
825
|
+
var parser = unified().use(remarkParse).use(remarkMdx);
|
|
826
|
+
function prepareTranslatedMdxBody(body) {
|
|
827
|
+
const normalized = normalizeTranslatedMdxBody(body);
|
|
828
|
+
const sanitized = sanitizeMdxJsxAttributeQuotes(normalized.body);
|
|
829
|
+
return {
|
|
830
|
+
body: sanitized.body,
|
|
831
|
+
adjusted: normalized.adjusted || sanitized.adjusted
|
|
832
|
+
};
|
|
833
|
+
}
|
|
834
|
+
function validateMdxBody(body) {
|
|
835
|
+
try {
|
|
836
|
+
parser.parse(body);
|
|
837
|
+
return { ok: true };
|
|
838
|
+
} catch (error) {
|
|
839
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
840
|
+
return { ok: false, error: message };
|
|
841
|
+
}
|
|
842
|
+
}
|
|
843
|
+
function assertValidTranslatedMdxBody(body) {
|
|
844
|
+
const prepared = prepareTranslatedMdxBody(body);
|
|
845
|
+
const validated = validateMdxBody(prepared.body);
|
|
846
|
+
if (!validated.ok) {
|
|
847
|
+
throw new Error(`MDX validation failed: ${validated.error}`);
|
|
848
|
+
}
|
|
849
|
+
return prepared;
|
|
850
|
+
}
|
|
851
|
+
|
|
715
852
|
// src/loader/normalize-en.ts
|
|
716
853
|
init_esm_shims();
|
|
717
854
|
function normalizeEnFrontmatter(data) {
|
|
@@ -833,7 +970,7 @@ function buildDocumentFromTranslation(row, enDoc, type, config) {
|
|
|
833
970
|
noindex: seo.noindex,
|
|
834
971
|
canonicalPathOverride: seo.canonicalPathOverride,
|
|
835
972
|
frontmatter,
|
|
836
|
-
content: row.body
|
|
973
|
+
content: prepareTranslatedMdxBody(row.body).body
|
|
837
974
|
};
|
|
838
975
|
}
|
|
839
976
|
var DEV_REVALIDATE_MS = 1500;
|
|
@@ -1752,6 +1889,20 @@ function listEnSlugs3(rootDir, contentDir) {
|
|
|
1752
1889
|
if (!fs2.existsSync(dir)) return [];
|
|
1753
1890
|
return fs2.readdirSync(dir).filter(isPublishableContentFile).map((f) => f.replace(/\.(md|mdx)$/, ""));
|
|
1754
1891
|
}
|
|
1892
|
+
function validateDocumentMdxBody(issues, input) {
|
|
1893
|
+
const preparedBody = prepareTranslatedMdxBody(input.body).body;
|
|
1894
|
+
const mdxValidation = validateMdxBody(preparedBody);
|
|
1895
|
+
if (!mdxValidation.ok) {
|
|
1896
|
+
issues.push({
|
|
1897
|
+
level: "error",
|
|
1898
|
+
contentType: input.contentType,
|
|
1899
|
+
enSlug: input.enSlug,
|
|
1900
|
+
locale: input.locale,
|
|
1901
|
+
field: "body",
|
|
1902
|
+
message: `Invalid MDX: ${mdxValidation.error}`
|
|
1903
|
+
});
|
|
1904
|
+
}
|
|
1905
|
+
}
|
|
1755
1906
|
function validateProject(config) {
|
|
1756
1907
|
const issues = [];
|
|
1757
1908
|
const project = createProject(config);
|
|
@@ -1810,6 +1961,12 @@ function validateProject(config) {
|
|
|
1810
1961
|
})) {
|
|
1811
1962
|
issues.push(issue);
|
|
1812
1963
|
}
|
|
1964
|
+
validateDocumentMdxBody(issues, {
|
|
1965
|
+
contentType: type.id,
|
|
1966
|
+
enSlug,
|
|
1967
|
+
locale: config.defaultLocale,
|
|
1968
|
+
body: enDoc.content
|
|
1969
|
+
});
|
|
1813
1970
|
for (const locale of config.locales) {
|
|
1814
1971
|
if (locale === config.defaultLocale) continue;
|
|
1815
1972
|
const row = getTranslation(db, type.id, enSlug, locale);
|
|
@@ -1825,15 +1982,22 @@ function validateProject(config) {
|
|
|
1825
1982
|
message: issue.message
|
|
1826
1983
|
});
|
|
1827
1984
|
}
|
|
1985
|
+
const preparedBody = prepareTranslatedMdxBody(row.body).body;
|
|
1828
1986
|
for (const issue of validateDocumentAssets(config, {
|
|
1829
1987
|
contentType: type.id,
|
|
1830
1988
|
enSlug,
|
|
1831
1989
|
locale,
|
|
1832
1990
|
frontmatter: localeFm,
|
|
1833
|
-
body:
|
|
1991
|
+
body: preparedBody
|
|
1834
1992
|
})) {
|
|
1835
1993
|
issues.push(issue);
|
|
1836
1994
|
}
|
|
1995
|
+
validateDocumentMdxBody(issues, {
|
|
1996
|
+
contentType: type.id,
|
|
1997
|
+
enSlug,
|
|
1998
|
+
locale,
|
|
1999
|
+
body: row.body
|
|
2000
|
+
});
|
|
1837
2001
|
}
|
|
1838
2002
|
}
|
|
1839
2003
|
try {
|
|
@@ -2001,12 +2165,20 @@ function normalizeGeminiDisplayName(model) {
|
|
|
2001
2165
|
// src/translate/gemini-client.ts
|
|
2002
2166
|
var DEFAULT_MODEL = DEFAULT_GEMINI_MODEL;
|
|
2003
2167
|
function extractJson(text) {
|
|
2004
|
-
const
|
|
2168
|
+
const trimmed = text.trim();
|
|
2169
|
+
const fenced = trimmed.match(/^```(?:json)?\s*\n?([\s\S]*?)\n?```$/);
|
|
2005
2170
|
if (fenced?.[1]) return fenced[1].trim();
|
|
2006
|
-
const start =
|
|
2007
|
-
const end =
|
|
2008
|
-
if (start >= 0 && end > start) return
|
|
2009
|
-
return
|
|
2171
|
+
const start = trimmed.indexOf("{");
|
|
2172
|
+
const end = trimmed.lastIndexOf("}");
|
|
2173
|
+
if (start >= 0 && end > start) return trimmed.slice(start, end + 1);
|
|
2174
|
+
return trimmed;
|
|
2175
|
+
}
|
|
2176
|
+
function parseGeminiResponse(text) {
|
|
2177
|
+
try {
|
|
2178
|
+
return JSON.parse(text.trim());
|
|
2179
|
+
} catch {
|
|
2180
|
+
return JSON.parse(extractJson(text));
|
|
2181
|
+
}
|
|
2010
2182
|
}
|
|
2011
2183
|
async function translatePageWithGemini(input) {
|
|
2012
2184
|
const apiKey = input.apiKey ?? process.env.GEMINI_API_KEY;
|
|
@@ -2027,7 +2199,7 @@ async function translatePageWithGemini(input) {
|
|
|
2027
2199
|
}
|
|
2028
2200
|
});
|
|
2029
2201
|
const raw = response.text ?? "";
|
|
2030
|
-
const parsed =
|
|
2202
|
+
const parsed = parseGeminiResponse(raw);
|
|
2031
2203
|
if (!parsed.frontmatter || typeof parsed.body !== "string") {
|
|
2032
2204
|
throw new Error("Gemini response missing frontmatter/body");
|
|
2033
2205
|
}
|
|
@@ -2201,24 +2373,21 @@ function buildGeminiResponseSchema(schema, slugStrategy) {
|
|
|
2201
2373
|
|
|
2202
2374
|
// src/translate/resolve-translate-config.ts
|
|
2203
2375
|
init_esm_shims();
|
|
2204
|
-
|
|
2376
|
+
var BUILTIN_TRANSLATE_RULES = [
|
|
2377
|
+
"Do not translate brand or product names unless the brand has a well-known localized name in the target market (rare). Keep the original spelling and capitalization.",
|
|
2378
|
+
"Return the MDX body with real line breaks; do not use JSON escape sequences like \\n or \\t in the body string.",
|
|
2379
|
+
'In JSX attributes (e.g. FaqItem question="..."), use single quotes when the value contains double-quote characters (e.g. Hebrew \u05D3\u05D5\u05D0"\u05DC), or escape them as \\".'
|
|
2380
|
+
];
|
|
2381
|
+
function slugStrategyRules(slugStrategy) {
|
|
2205
2382
|
if (slugStrategy === "localized") {
|
|
2206
|
-
|
|
2383
|
+
return [
|
|
2207
2384
|
"Provide a URL slug in JSON field `slug` that is Localized into the target language.",
|
|
2208
2385
|
"Base the slug on the meaning of the translated title \u2014 do NOT reuse the English slug words.",
|
|
2209
2386
|
"Slug MUST be ASCII only: a-z, 0-9, hyphens. No uppercase, accents, underscores, or spaces.",
|
|
2210
2387
|
"For non-Latin languages, write the words in the target language and transliterate them into Latin script (e.g. Russian -> romanized Russian, not English).",
|
|
2211
2388
|
"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.",
|
|
2212
|
-
|
|
2389
|
+
"Preserve 4-digit years and proper nouns in slugs."
|
|
2213
2390
|
];
|
|
2214
|
-
if (preserveTerms?.length) {
|
|
2215
|
-
rules.push(
|
|
2216
|
-
`Preserve these terms verbatim in slugs (lowercase): ${preserveTerms.join(", ")}.`
|
|
2217
|
-
);
|
|
2218
|
-
} else {
|
|
2219
|
-
rules.push("Preserve 4-digit years and proper nouns in slugs.");
|
|
2220
|
-
}
|
|
2221
|
-
return rules;
|
|
2222
2391
|
}
|
|
2223
2392
|
return ["Do NOT output a slug \u2014 slugStrategy is fixed."];
|
|
2224
2393
|
}
|
|
@@ -2231,9 +2400,10 @@ function mergeTranslateConfig(project, type, slugStrategy) {
|
|
|
2231
2400
|
promptOverride: type?.prompt ?? project?.prompt,
|
|
2232
2401
|
context: mergeContext(project, type),
|
|
2233
2402
|
rules: [
|
|
2403
|
+
...BUILTIN_TRANSLATE_RULES,
|
|
2234
2404
|
...project?.rules ?? [],
|
|
2235
2405
|
...type?.rules ?? [],
|
|
2236
|
-
...slugStrategyRules(slugStrategy
|
|
2406
|
+
...slugStrategyRules(slugStrategy)
|
|
2237
2407
|
],
|
|
2238
2408
|
model: type?.model ?? project?.defaultModel
|
|
2239
2409
|
};
|
|
@@ -2242,96 +2412,6 @@ function resolveTranslateConfig(config, type) {
|
|
|
2242
2412
|
return mergeTranslateConfig(config.translate, type.translate, type.slugStrategy);
|
|
2243
2413
|
}
|
|
2244
2414
|
|
|
2245
|
-
// src/translate/sanitize-mdx-jsx.ts
|
|
2246
|
-
init_esm_shims();
|
|
2247
|
-
function sanitizeMdxJsxAttributeQuotes(body) {
|
|
2248
|
-
let adjusted = false;
|
|
2249
|
-
let out = "";
|
|
2250
|
-
let i = 0;
|
|
2251
|
-
while (i < body.length) {
|
|
2252
|
-
if (body[i] !== "<" || !/[\w.]/.test(body[i + 1] ?? "")) {
|
|
2253
|
-
out += body[i];
|
|
2254
|
-
i += 1;
|
|
2255
|
-
continue;
|
|
2256
|
-
}
|
|
2257
|
-
const tagStart = i;
|
|
2258
|
-
i += 1;
|
|
2259
|
-
while (i < body.length && /[\w.-]/.test(body[i] ?? "")) i += 1;
|
|
2260
|
-
const tagName = body.slice(tagStart + 1, i);
|
|
2261
|
-
let tagOut = `<${tagName}`;
|
|
2262
|
-
let tagAdjusted = false;
|
|
2263
|
-
while (i < body.length && body[i] !== ">" && body[i] !== "/") {
|
|
2264
|
-
while (i < body.length && /\s/.test(body[i] ?? "")) {
|
|
2265
|
-
tagOut += body[i];
|
|
2266
|
-
i += 1;
|
|
2267
|
-
}
|
|
2268
|
-
if (i >= body.length || body[i] === ">" || body[i] === "/") break;
|
|
2269
|
-
const attrStart = i;
|
|
2270
|
-
while (i < body.length && /[\w:.-]/.test(body[i] ?? "")) i += 1;
|
|
2271
|
-
body.slice(attrStart, i);
|
|
2272
|
-
while (i < body.length && /\s/.test(body[i] ?? "")) i += 1;
|
|
2273
|
-
if (body[i] !== "=") {
|
|
2274
|
-
tagOut += body.slice(attrStart, i);
|
|
2275
|
-
continue;
|
|
2276
|
-
}
|
|
2277
|
-
tagOut += body.slice(attrStart, i);
|
|
2278
|
-
tagOut += "=";
|
|
2279
|
-
i += 1;
|
|
2280
|
-
while (i < body.length && /\s/.test(body[i] ?? "")) i += 1;
|
|
2281
|
-
const quote = body[i];
|
|
2282
|
-
if (quote !== '"' && quote !== "'") {
|
|
2283
|
-
continue;
|
|
2284
|
-
}
|
|
2285
|
-
if (quote === "'") {
|
|
2286
|
-
const valStart2 = i + 1;
|
|
2287
|
-
i += 1;
|
|
2288
|
-
while (i < body.length) {
|
|
2289
|
-
if (body[i] === "\\") {
|
|
2290
|
-
i += 2;
|
|
2291
|
-
continue;
|
|
2292
|
-
}
|
|
2293
|
-
if (body[i] === "'") break;
|
|
2294
|
-
i += 1;
|
|
2295
|
-
}
|
|
2296
|
-
tagOut += body.slice(valStart2 - 1, i + 1);
|
|
2297
|
-
i += 1;
|
|
2298
|
-
continue;
|
|
2299
|
-
}
|
|
2300
|
-
const valStart = i + 1;
|
|
2301
|
-
i += 1;
|
|
2302
|
-
let closeIdx = -1;
|
|
2303
|
-
for (let scan = valStart; scan < body.length; scan += 1) {
|
|
2304
|
-
if (body[scan] !== '"') continue;
|
|
2305
|
-
let j = scan + 1;
|
|
2306
|
-
while (j < body.length && /\s/.test(body[j] ?? "")) j += 1;
|
|
2307
|
-
if (j < body.length && (body[j] === ">" || body[j] === "/" || /[a-zA-Z]/.test(body[j] ?? ""))) {
|
|
2308
|
-
closeIdx = scan;
|
|
2309
|
-
break;
|
|
2310
|
-
}
|
|
2311
|
-
}
|
|
2312
|
-
if (closeIdx === -1) {
|
|
2313
|
-
tagOut += body.slice(valStart - 1, i);
|
|
2314
|
-
break;
|
|
2315
|
-
}
|
|
2316
|
-
const value = body.slice(valStart, closeIdx);
|
|
2317
|
-
const hasInternalQuote = value.includes('"');
|
|
2318
|
-
if (hasInternalQuote) {
|
|
2319
|
-
const escaped = value.replace(/\\/g, "\\\\").replace(/'/g, "\\'");
|
|
2320
|
-
tagOut += `'${escaped}'`;
|
|
2321
|
-
tagAdjusted = true;
|
|
2322
|
-
} else {
|
|
2323
|
-
tagOut += `"${value}"`;
|
|
2324
|
-
}
|
|
2325
|
-
i = closeIdx + 1;
|
|
2326
|
-
}
|
|
2327
|
-
if (tagAdjusted) adjusted = true;
|
|
2328
|
-
tagOut += body[i] ?? "";
|
|
2329
|
-
out += tagOut;
|
|
2330
|
-
i += 1;
|
|
2331
|
-
}
|
|
2332
|
-
return { body: out, adjusted };
|
|
2333
|
-
}
|
|
2334
|
-
|
|
2335
2415
|
// src/translate/validate-translation.ts
|
|
2336
2416
|
init_esm_shims();
|
|
2337
2417
|
function formatZodIssues(error) {
|
|
@@ -2466,7 +2546,7 @@ async function translatePage(config, item, options = {}) {
|
|
|
2466
2546
|
if (!validated.ok) {
|
|
2467
2547
|
throw new Error(`Translation validation failed: ${validated.error}`);
|
|
2468
2548
|
}
|
|
2469
|
-
const { body: translatedBody, adjusted: mdxAdjusted } =
|
|
2549
|
+
const { body: translatedBody, adjusted: mdxAdjusted } = assertValidTranslatedMdxBody(
|
|
2470
2550
|
result.parsed.body
|
|
2471
2551
|
);
|
|
2472
2552
|
const writeDb = openStore(config, "readwrite");
|