@form-engine-ts/core 4.5.0 → 4.6.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.
- package/README.md +7 -0
- package/dist/index.cjs +168 -13
- package/dist/index.d.cts +23 -1
- package/dist/index.d.ts +23 -1
- package/dist/index.js +165 -13
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -62,6 +62,13 @@ operators include equality, containment, emptiness, and numeric comparisons; the
|
|
|
62
62
|
and missing, translated, stale, or manual states for authoring tools. `populateSchemaTranslations` can populate stale
|
|
63
63
|
and missing entries while preserving manual translations and reports skipped reasons.
|
|
64
64
|
|
|
65
|
+
Legacy translation metadata can be recognized with `isManualTranslationMetadata` and migrated with
|
|
66
|
+
`migrateSchemaTranslationMetadata`; pass a custom migrator when legacy fields need application-specific conversion.
|
|
67
|
+
`PopulateTranslationsOptions` is a compatibility alias for `PopulateTranslationOptions`, which also accepts custom
|
|
68
|
+
manual-translation detection and metadata normalization callbacks. `removeLocaleFromSchema(schema, locale)` removes
|
|
69
|
+
the locale from registrations and all form, page, field, option translation values and metadata; the default locale
|
|
70
|
+
cannot be removed.
|
|
71
|
+
|
|
65
72
|
The React builder uses canonical keys with legacy aliases when resolving UI translations:
|
|
66
73
|
|
|
67
74
|
| Canonical key | Legacy alias |
|
package/dist/index.cjs
CHANGED
|
@@ -50,15 +50,18 @@ __export(index_exports, {
|
|
|
50
50
|
getTranslationStatus: () => getTranslationStatus,
|
|
51
51
|
isDisplayConditionGroupSatisfied: () => isDisplayConditionGroupSatisfied,
|
|
52
52
|
isDisplayConditionSatisfied: () => isDisplayConditionSatisfied,
|
|
53
|
+
isManualTranslationMetadata: () => isManualTranslationMetadata,
|
|
53
54
|
isQuestionVisible: () => isQuestionVisible,
|
|
54
55
|
iterateSubmissionPages: () => iterateSubmissionPages,
|
|
55
56
|
jsonValuesEqual: () => jsonValuesEqual,
|
|
56
57
|
matchesSubmissionFilter: () => matchesSubmissionFilter,
|
|
57
58
|
matchesSubmissionPageFilters: () => matchesSubmissionPageFilters,
|
|
59
|
+
migrateSchemaTranslationMetadata: () => migrateSchemaTranslationMetadata,
|
|
58
60
|
normalizeSubmissionPageSize: () => normalizeSubmissionPageSize,
|
|
59
61
|
pipeResponsesToCsvStream: () => pipeResponsesToCsvStream,
|
|
60
62
|
populateSchemaTranslations: () => populateSchemaTranslations,
|
|
61
63
|
publishDraft: () => publishDraft,
|
|
64
|
+
removeLocaleFromSchema: () => removeLocaleFromSchema,
|
|
62
65
|
resolveFormTranslation: () => resolveFormTranslation,
|
|
63
66
|
resolveLocalizedSchema: () => resolveLocalizedSchema,
|
|
64
67
|
sanitizeSchema: () => sanitizeSchema,
|
|
@@ -2216,6 +2219,12 @@ function createSubmission(schema, values, options) {
|
|
|
2216
2219
|
}
|
|
2217
2220
|
|
|
2218
2221
|
// src/translation.ts
|
|
2222
|
+
var isManualTranslationMetadata = (metadata) => {
|
|
2223
|
+
if (metadata === void 0) return false;
|
|
2224
|
+
if ("isManuallyEdited" in metadata && metadata.isManuallyEdited === true || "isManual" in metadata && metadata.isManual === true)
|
|
2225
|
+
return true;
|
|
2226
|
+
return typeof metadata.translationSource === "string" && metadata.translationSource.toLowerCase() === "manual";
|
|
2227
|
+
};
|
|
2219
2228
|
var computeSourceTextHash = (text) => {
|
|
2220
2229
|
const normalized = text.normalize("NFKC").trim().replace(/\s+/gu, " ");
|
|
2221
2230
|
let hash = 2166136261;
|
|
@@ -2226,11 +2235,14 @@ var computeSourceTextHash = (text) => {
|
|
|
2226
2235
|
return (hash >>> 0).toString(16).padStart(8, "0");
|
|
2227
2236
|
};
|
|
2228
2237
|
function getTranslationStatus(sourceText, translatedText, metadata) {
|
|
2238
|
+
return getTranslationStatusWithManualOverride(sourceText, translatedText, metadata, void 0);
|
|
2239
|
+
}
|
|
2240
|
+
function getTranslationStatusWithManualOverride(sourceText, translatedText, metadata, manualOverride) {
|
|
2229
2241
|
if (translatedText === void 0 || translatedText.trim() === "") return "missing";
|
|
2230
2242
|
if (metadata === void 0) return "translated";
|
|
2231
2243
|
const currentHash = computeSourceTextHash(sourceText);
|
|
2232
2244
|
const sourceHash = typeof metadata.sourceTextHash === "string" ? metadata.sourceTextHash : void 0;
|
|
2233
|
-
const isManual =
|
|
2245
|
+
const isManual = manualOverride ?? isManualTranslationMetadata(metadata);
|
|
2234
2246
|
if (isManual) return sourceHash === void 0 || sourceHash === currentHash ? "manual" : "manual-stale";
|
|
2235
2247
|
return sourceHash === void 0 || sourceHash === currentHash ? "translated" : "stale";
|
|
2236
2248
|
}
|
|
@@ -2256,8 +2268,11 @@ function withTranslationMetadata(node, locale, property, metadata) {
|
|
|
2256
2268
|
}
|
|
2257
2269
|
};
|
|
2258
2270
|
}
|
|
2259
|
-
function createSlot(kind, nodeId, property, locale, sourceText, existingText, nodeMetadata, existingTranslationMetadata) {
|
|
2260
|
-
const
|
|
2271
|
+
function createSlot(kind, nodeId, property, locale, sourceText, existingText, nodeMetadata, existingTranslationMetadata, options = {}) {
|
|
2272
|
+
const path = `${kind}.${nodeId}.${property}`;
|
|
2273
|
+
const manual = options.isManualTranslation?.(existingTranslationMetadata, { path, locale }) ?? isManualTranslationMetadata(existingTranslationMetadata);
|
|
2274
|
+
const normalizedMetadata = existingTranslationMetadata === void 0 ? void 0 : options.normalizeMetadata === void 0 ? existingTranslationMetadata : { ...options.normalizeMetadata(existingTranslationMetadata, sourceText) };
|
|
2275
|
+
const status = getTranslationStatusWithManualOverride(sourceText, existingText, normalizedMetadata, manual);
|
|
2261
2276
|
return {
|
|
2262
2277
|
kind,
|
|
2263
2278
|
nodeId,
|
|
@@ -2265,15 +2280,15 @@ function createSlot(kind, nodeId, property, locale, sourceText, existingText, no
|
|
|
2265
2280
|
locale,
|
|
2266
2281
|
sourceText,
|
|
2267
2282
|
target: { kind, ...nodeId.length === 0 ? {} : { id: nodeId }, property },
|
|
2268
|
-
path
|
|
2283
|
+
path,
|
|
2269
2284
|
sourceTextHash: computeSourceTextHash(sourceText),
|
|
2270
2285
|
status,
|
|
2271
2286
|
...existingText === void 0 ? {} : { existingText },
|
|
2272
2287
|
...nodeMetadata === void 0 ? {} : { nodeMetadata, metadata: nodeMetadata },
|
|
2273
|
-
...
|
|
2288
|
+
...normalizedMetadata === void 0 ? {} : { existingTranslationMetadata: normalizedMetadata }
|
|
2274
2289
|
};
|
|
2275
2290
|
}
|
|
2276
|
-
function translationSlots(schema, locale) {
|
|
2291
|
+
function translationSlots(schema, locale, options = {}) {
|
|
2277
2292
|
const descriptors = [];
|
|
2278
2293
|
const addFormSlot = (property, sourceText) => {
|
|
2279
2294
|
const slot = createSlot(
|
|
@@ -2284,10 +2299,15 @@ function translationSlots(schema, locale) {
|
|
|
2284
2299
|
sourceText,
|
|
2285
2300
|
schema.translations?.[locale]?.[property],
|
|
2286
2301
|
schema.metadata,
|
|
2287
|
-
schema.translationMetadata?.[locale]?.[property]
|
|
2302
|
+
schema.translationMetadata?.[locale]?.[property],
|
|
2303
|
+
options
|
|
2288
2304
|
);
|
|
2289
2305
|
descriptors.push({
|
|
2290
2306
|
slot,
|
|
2307
|
+
manual: options.isManualTranslation?.(schema.translationMetadata?.[locale]?.[property], {
|
|
2308
|
+
path: slot.path ?? "",
|
|
2309
|
+
locale
|
|
2310
|
+
}) ?? isManualTranslationMetadata(schema.translationMetadata?.[locale]?.[property]),
|
|
2291
2311
|
apply: (current, value, metadata) => withTranslationMetadata(
|
|
2292
2312
|
{ ...current, translations: mergeLocalizedText(current.translations, locale, property, value) },
|
|
2293
2313
|
locale,
|
|
@@ -2309,10 +2329,15 @@ function translationSlots(schema, locale) {
|
|
|
2309
2329
|
sourceText,
|
|
2310
2330
|
field.translations?.[locale]?.[property],
|
|
2311
2331
|
field.metadata,
|
|
2312
|
-
field.translationMetadata?.[locale]?.[property]
|
|
2332
|
+
field.translationMetadata?.[locale]?.[property],
|
|
2333
|
+
options
|
|
2313
2334
|
);
|
|
2314
2335
|
descriptors.push({
|
|
2315
2336
|
slot,
|
|
2337
|
+
manual: options.isManualTranslation?.(field.translationMetadata?.[locale]?.[property], {
|
|
2338
|
+
path: slot.path ?? "",
|
|
2339
|
+
locale
|
|
2340
|
+
}) ?? isManualTranslationMetadata(field.translationMetadata?.[locale]?.[property]),
|
|
2316
2341
|
apply: (current, value, metadata) => ({
|
|
2317
2342
|
...current,
|
|
2318
2343
|
fields: current.fields.map(
|
|
@@ -2341,10 +2366,15 @@ function translationSlots(schema, locale) {
|
|
|
2341
2366
|
option.label,
|
|
2342
2367
|
option.translations?.[locale],
|
|
2343
2368
|
option.metadata,
|
|
2344
|
-
option.translationMetadata?.[locale]?.label
|
|
2369
|
+
option.translationMetadata?.[locale]?.label,
|
|
2370
|
+
options
|
|
2345
2371
|
);
|
|
2346
2372
|
descriptors.push({
|
|
2347
2373
|
slot,
|
|
2374
|
+
manual: options.isManualTranslation?.(option.translationMetadata?.[locale]?.label, {
|
|
2375
|
+
path: slot.path ?? "",
|
|
2376
|
+
locale
|
|
2377
|
+
}) ?? isManualTranslationMetadata(option.translationMetadata?.[locale]?.label),
|
|
2348
2378
|
apply: (current, value, metadata) => ({
|
|
2349
2379
|
...current,
|
|
2350
2380
|
fields: current.fields.map((candidate, candidateIndex) => {
|
|
@@ -2379,10 +2409,15 @@ function translationSlots(schema, locale) {
|
|
|
2379
2409
|
sourceText,
|
|
2380
2410
|
page.translations?.[locale]?.[property],
|
|
2381
2411
|
page.metadata,
|
|
2382
|
-
page.translationMetadata?.[locale]?.[property]
|
|
2412
|
+
page.translationMetadata?.[locale]?.[property],
|
|
2413
|
+
options
|
|
2383
2414
|
);
|
|
2384
2415
|
descriptors.push({
|
|
2385
2416
|
slot,
|
|
2417
|
+
manual: options.isManualTranslation?.(page.translationMetadata?.[locale]?.[property], {
|
|
2418
|
+
path: slot.path ?? "",
|
|
2419
|
+
locale
|
|
2420
|
+
}) ?? isManualTranslationMetadata(page.translationMetadata?.[locale]?.[property]),
|
|
2386
2421
|
apply: (current, value, metadata) => ({
|
|
2387
2422
|
...current,
|
|
2388
2423
|
...current.pages === void 0 ? {} : {
|
|
@@ -2406,6 +2441,122 @@ function translationSlots(schema, locale) {
|
|
|
2406
2441
|
});
|
|
2407
2442
|
return descriptors;
|
|
2408
2443
|
}
|
|
2444
|
+
function removeLocaleRecord(record, locale) {
|
|
2445
|
+
if (record === void 0) return void 0;
|
|
2446
|
+
const remaining = Object.entries(record).filter(([candidate]) => candidate !== locale);
|
|
2447
|
+
return remaining.length === 0 ? void 0 : Object.fromEntries(remaining);
|
|
2448
|
+
}
|
|
2449
|
+
function removeLocalizedNodeLocale(node, locale) {
|
|
2450
|
+
const translations = removeLocaleRecord(node.translations, locale);
|
|
2451
|
+
const translationMetadata = removeLocaleRecord(node.translationMetadata, locale);
|
|
2452
|
+
const { translations: _translations, translationMetadata: _translationMetadata, ...base } = node;
|
|
2453
|
+
return {
|
|
2454
|
+
...base,
|
|
2455
|
+
...translations === void 0 ? {} : { translations },
|
|
2456
|
+
...translationMetadata === void 0 ? {} : { translationMetadata }
|
|
2457
|
+
};
|
|
2458
|
+
}
|
|
2459
|
+
function migrateMetadata(metadata, sourceText, defaultLocale, customMigrator) {
|
|
2460
|
+
if (customMigrator !== void 0) return customMigrator(metadata, sourceText);
|
|
2461
|
+
const record = metadata !== null && typeof metadata === "object" ? metadata : void 0;
|
|
2462
|
+
const sourceLocale = typeof record?.sourceLocale === "string" ? record.sourceLocale : defaultLocale ?? "";
|
|
2463
|
+
const translationSource = isManualTranslationMetadata(record) ? "manual" : "automatic";
|
|
2464
|
+
return {
|
|
2465
|
+
sourceLocale,
|
|
2466
|
+
sourceTextHash: computeSourceTextHash(sourceText),
|
|
2467
|
+
translationSource,
|
|
2468
|
+
...typeof record?.translatedAt === "string" ? { translatedAt: record.translatedAt } : {},
|
|
2469
|
+
...typeof record?.editedAt === "string" ? { editedAt: record.editedAt } : {}
|
|
2470
|
+
};
|
|
2471
|
+
}
|
|
2472
|
+
function migrateNodeMetadata(node, sourceTexts, defaultLocale, customMigrator) {
|
|
2473
|
+
if (node.translationMetadata === void 0) return node;
|
|
2474
|
+
const translationMetadata = Object.fromEntries(
|
|
2475
|
+
Object.entries(node.translationMetadata).map(([locale, properties]) => [
|
|
2476
|
+
locale,
|
|
2477
|
+
Object.fromEntries(
|
|
2478
|
+
Object.entries(properties).map(([property, metadata]) => [
|
|
2479
|
+
property,
|
|
2480
|
+
migrateMetadata(metadata, sourceTexts[property] ?? "", defaultLocale, customMigrator)
|
|
2481
|
+
])
|
|
2482
|
+
)
|
|
2483
|
+
])
|
|
2484
|
+
);
|
|
2485
|
+
return { ...node, translationMetadata };
|
|
2486
|
+
}
|
|
2487
|
+
var migrateSchemaTranslationMetadata = (schema, customMigrator) => {
|
|
2488
|
+
const migratedSchema = migrateNodeMetadata(
|
|
2489
|
+
schema,
|
|
2490
|
+
{
|
|
2491
|
+
title: schema.title,
|
|
2492
|
+
...schema.description === void 0 ? {} : { description: schema.description },
|
|
2493
|
+
...schema.completionMessage === void 0 ? {} : { completionMessage: schema.completionMessage }
|
|
2494
|
+
},
|
|
2495
|
+
schema.defaultLocale,
|
|
2496
|
+
customMigrator
|
|
2497
|
+
);
|
|
2498
|
+
const fields = schema.fields.map((field) => {
|
|
2499
|
+
const migratedField = migrateNodeMetadata(
|
|
2500
|
+
field,
|
|
2501
|
+
{ title: field.title, ...field.description === void 0 ? {} : { description: field.description } },
|
|
2502
|
+
schema.defaultLocale,
|
|
2503
|
+
customMigrator
|
|
2504
|
+
);
|
|
2505
|
+
if (!("options" in migratedField)) return migratedField;
|
|
2506
|
+
return {
|
|
2507
|
+
...migratedField,
|
|
2508
|
+
options: migratedField.options.map(
|
|
2509
|
+
(option) => migrateNodeMetadata(option, { label: option.label }, schema.defaultLocale, customMigrator)
|
|
2510
|
+
)
|
|
2511
|
+
};
|
|
2512
|
+
});
|
|
2513
|
+
const pages = schema.pages?.map(
|
|
2514
|
+
(page) => migrateNodeMetadata(
|
|
2515
|
+
page,
|
|
2516
|
+
{
|
|
2517
|
+
...page.title === void 0 ? {} : { title: page.title },
|
|
2518
|
+
...page.description === void 0 ? {} : { description: page.description }
|
|
2519
|
+
},
|
|
2520
|
+
schema.defaultLocale,
|
|
2521
|
+
customMigrator
|
|
2522
|
+
)
|
|
2523
|
+
);
|
|
2524
|
+
return {
|
|
2525
|
+
...migratedSchema,
|
|
2526
|
+
fields,
|
|
2527
|
+
...pages === void 0 ? {} : { pages }
|
|
2528
|
+
};
|
|
2529
|
+
};
|
|
2530
|
+
var removeLocaleFromSchema = (schema, localeToRemove) => {
|
|
2531
|
+
if (localeToRemove === schema.defaultLocale) {
|
|
2532
|
+
throw new Error(`Cannot remove defaultLocale: ${localeToRemove}`);
|
|
2533
|
+
}
|
|
2534
|
+
const form = removeLocalizedNodeLocale(schema, localeToRemove);
|
|
2535
|
+
const fields = schema.fields.map((field) => {
|
|
2536
|
+
const localizedField = removeLocalizedNodeLocale(field, localeToRemove);
|
|
2537
|
+
if (!("options" in localizedField)) return localizedField;
|
|
2538
|
+
return {
|
|
2539
|
+
...localizedField,
|
|
2540
|
+
options: localizedField.options.map((option) => {
|
|
2541
|
+
const translations = removeLocaleRecord(option.translations, localeToRemove);
|
|
2542
|
+
const translationMetadata = removeLocaleRecord(option.translationMetadata, localeToRemove);
|
|
2543
|
+
const { translations: _translations, translationMetadata: _translationMetadata, ...base } = option;
|
|
2544
|
+
return {
|
|
2545
|
+
...base,
|
|
2546
|
+
...translations === void 0 ? {} : { translations },
|
|
2547
|
+
...translationMetadata === void 0 ? {} : { translationMetadata }
|
|
2548
|
+
};
|
|
2549
|
+
})
|
|
2550
|
+
};
|
|
2551
|
+
});
|
|
2552
|
+
const pages = schema.pages?.map((page) => removeLocalizedNodeLocale(page, localeToRemove));
|
|
2553
|
+
return {
|
|
2554
|
+
...form,
|
|
2555
|
+
supportedLocales: (schema.supportedLocales ?? []).filter((locale) => locale !== localeToRemove),
|
|
2556
|
+
fields,
|
|
2557
|
+
...pages === void 0 ? {} : { pages }
|
|
2558
|
+
};
|
|
2559
|
+
};
|
|
2409
2560
|
function collectTranslationSlots(schema, locale) {
|
|
2410
2561
|
return translationSlots(schema, locale).map((descriptor) => descriptor.slot);
|
|
2411
2562
|
}
|
|
@@ -2469,7 +2620,7 @@ async function populateSchemaTranslations(schema, targetLocales, adapter, option
|
|
|
2469
2620
|
const skippedReasons = {};
|
|
2470
2621
|
let result = schema;
|
|
2471
2622
|
for (const locale of locales) {
|
|
2472
|
-
const descriptors = translationSlots(schema, locale);
|
|
2623
|
+
const descriptors = translationSlots(schema, locale, options);
|
|
2473
2624
|
if (options.markStaleTranslations ?? true) {
|
|
2474
2625
|
for (const descriptor of descriptors) {
|
|
2475
2626
|
if (descriptor.slot.status === "stale" || descriptor.slot.status === "manual-stale")
|
|
@@ -2479,8 +2630,9 @@ async function populateSchemaTranslations(schema, targetLocales, adapter, option
|
|
|
2479
2630
|
const selected = [];
|
|
2480
2631
|
for (const descriptor of descriptors) {
|
|
2481
2632
|
const status = descriptor.slot.status ?? "missing";
|
|
2482
|
-
const manual = status === "manual" || status === "manual-stale";
|
|
2483
|
-
const
|
|
2633
|
+
const manual = descriptor.manual || status === "manual" || status === "manual-stale";
|
|
2634
|
+
const requestedOverwrite = options.shouldOverwrite?.(descriptor.slot);
|
|
2635
|
+
const shouldTranslate = (options.preserveManualTranslations ?? true) && manual ? false : requestedOverwrite ?? (options.overwrite === "all" || (options.overwrite === "stale-and-missing" || options.overwrite === void 0 ? status === "missing" || status === "stale" || !(options.preserveManualTranslations ?? true) && status === "manual-stale" : status === "missing"));
|
|
2484
2636
|
if (shouldTranslate) selected.push(descriptor);
|
|
2485
2637
|
else {
|
|
2486
2638
|
skippedSlots.push(descriptor.slot);
|
|
@@ -2842,15 +2994,18 @@ function assertVersionMutable(status) {
|
|
|
2842
2994
|
getTranslationStatus,
|
|
2843
2995
|
isDisplayConditionGroupSatisfied,
|
|
2844
2996
|
isDisplayConditionSatisfied,
|
|
2997
|
+
isManualTranslationMetadata,
|
|
2845
2998
|
isQuestionVisible,
|
|
2846
2999
|
iterateSubmissionPages,
|
|
2847
3000
|
jsonValuesEqual,
|
|
2848
3001
|
matchesSubmissionFilter,
|
|
2849
3002
|
matchesSubmissionPageFilters,
|
|
3003
|
+
migrateSchemaTranslationMetadata,
|
|
2850
3004
|
normalizeSubmissionPageSize,
|
|
2851
3005
|
pipeResponsesToCsvStream,
|
|
2852
3006
|
populateSchemaTranslations,
|
|
2853
3007
|
publishDraft,
|
|
3008
|
+
removeLocaleFromSchema,
|
|
2854
3009
|
resolveFormTranslation,
|
|
2855
3010
|
resolveLocalizedSchema,
|
|
2856
3011
|
sanitizeSchema,
|
package/dist/index.d.cts
CHANGED
|
@@ -686,15 +686,34 @@ interface CanonicalTranslationMetadata {
|
|
|
686
686
|
readonly translatedAt?: string;
|
|
687
687
|
readonly editedAt?: string;
|
|
688
688
|
}
|
|
689
|
+
interface LegacyTranslationMetadata {
|
|
690
|
+
readonly isManuallyEdited?: boolean;
|
|
691
|
+
readonly translationSource?: "MANUAL" | "AUTOMATIC" | "manual" | "automatic" | string;
|
|
692
|
+
readonly sourceTextHash?: string;
|
|
693
|
+
readonly sourceText?: string;
|
|
694
|
+
readonly sourceLocale?: string;
|
|
695
|
+
readonly translatedAt?: string;
|
|
696
|
+
readonly editedAt?: string;
|
|
697
|
+
readonly isManual?: boolean;
|
|
698
|
+
readonly [key: string]: unknown;
|
|
699
|
+
}
|
|
700
|
+
declare const isManualTranslationMetadata: (metadata?: LegacyTranslationMetadata | CanonicalTranslationMetadata) => boolean;
|
|
689
701
|
interface PopulateTranslationOptions {
|
|
690
702
|
readonly overwrite?: "all" | "missing-only" | "stale-and-missing";
|
|
691
703
|
readonly preserveManualTranslations?: boolean;
|
|
692
704
|
readonly markStaleTranslations?: boolean;
|
|
693
705
|
readonly shouldOverwrite?: (slot: TranslationSlot) => boolean;
|
|
694
706
|
readonly createMetadata?: (slot: TranslationSlot, translatedText: string) => Readonly<Record<string, JsonValue>>;
|
|
707
|
+
readonly isManualTranslation?: (metadata: unknown, context: {
|
|
708
|
+
readonly path: string;
|
|
709
|
+
readonly locale: string;
|
|
710
|
+
}) => boolean;
|
|
711
|
+
readonly normalizeMetadata?: (metadata: unknown, sourceText: string) => CanonicalTranslationMetadata;
|
|
695
712
|
/** Applies locale admission and count limits before the adapter is called. */
|
|
696
713
|
readonly policy?: Pick<FormPolicy, "allowedLocales" | "maxLocales">;
|
|
697
714
|
}
|
|
715
|
+
/** Compatibility alias for clients that used the pluralized options name. */
|
|
716
|
+
type PopulateTranslationsOptions = PopulateTranslationOptions;
|
|
698
717
|
interface TranslationReport {
|
|
699
718
|
readonly updatedSlots: readonly TranslationSlot[];
|
|
700
719
|
readonly skippedSlots: readonly TranslationSlot[];
|
|
@@ -703,6 +722,9 @@ interface TranslationReport {
|
|
|
703
722
|
}
|
|
704
723
|
declare const computeSourceTextHash: (text: string) => string;
|
|
705
724
|
declare function getTranslationStatus(sourceText: string, translatedText: string | undefined, metadata: CanonicalTranslationMetadata | Readonly<Record<string, JsonValue>> | undefined): TranslationStatus;
|
|
725
|
+
declare const migrateSchemaTranslationMetadata: (schema: FormSchema, customMigrator?: (oldMeta: unknown, sourceText: string) => CanonicalTranslationMetadata) => FormSchema;
|
|
726
|
+
/** Removes a locale registration and every localized value and metadata entry for it. */
|
|
727
|
+
declare const removeLocaleFromSchema: (schema: FormSchema, localeToRemove: string) => FormSchema;
|
|
706
728
|
declare function collectTranslationSlots(schema: FormSchema, locale: string): readonly TranslationSlot[];
|
|
707
729
|
declare function resolveLocalizedSchema(schema: FormSchema, targetLocale?: string): FormSchema;
|
|
708
730
|
declare function populateSchemaTranslations(schema: FormSchema, targetLocales: readonly string[], adapter: AsyncTranslationAdapter, options?: PopulateTranslationOptions): Promise<{
|
|
@@ -725,4 +747,4 @@ declare function calculatePageVisibility(schema: FormSchema, currentAnswers: Rea
|
|
|
725
747
|
declare function calculateFieldVisibility(schema: FormSchema, currentAnswers: Readonly<Record<string, unknown>>): Readonly<Record<string, boolean>>;
|
|
726
748
|
declare function selectVisibleAnswers(schema: FormSchema, currentAnswers: FormValues): FormValues;
|
|
727
749
|
|
|
728
|
-
export { type AccumulatorReport, type AccumulatorResponse, type AccumulatorSkipReason, type AnswerValidationResult, type AsyncTranslationAdapter, type BaseField, type BaseFieldConstraintRule, type BuilderTranslationKey, type CanonicalTranslationMetadata, type CheckboxField, type CheckboxQuestionAggregate, type ChoiceDistributionEntry, type ChoiceFieldConstraintRule, type ChoiceOption, type ChoiceQuestionAggregate, type CloneVersionOptions, type CollectedLocales, type ConditionOperator, type ConditionValue, type CreateSubmissionOptions, type CrossTabulationResult, type CsvColumnContext, type CsvColumnDef, type CsvExportOptions, DEFAULT_FIELD_TYPE_DEFINITIONS, type DeleteDraftOptions, type DisplayCondition, type DisplayConditionGroup, type DisplayRule, type ExtensibleNode, type FieldConstraintRule, type FieldDisplayCondition, type FieldOption, type FieldType, type FieldTypeDefinition, type FormAnalytics, type FormEvent, type FormEventType, type FormField, type FormPage, type FormPolicy, type FormResponse, type FormSchema, type FormStorageAdapter, type FormSubmission, type FormSubmissionSettings, type FormValue, type FormValues, type FormVersionRecord, type FormVersionState, type FormVersionStatus, type JsonValue, type LocalizedText, type MultiSelectField, type NodeWritableStream, type NumberField, type NumberQuestionAggregate, type NumericSummary, type OptionAggregate, type PagedSubmissionStorageAdapter, type PaginationIteratorOptions, type PopulateTranslationOptions, type PublishDraftOptions, type PublishDraftResult, type Question, type QuestionAggregate, type QuestionType, type RatingField, type RatingFieldConstraintRule, type ResponseAccumulator, type ResponseAccumulatorOptions, type Result, type SanitizeSchemaOptions, type SchemaIssue, type SchemaStructureIssue, type SchemaStructureIssueType, type SchemaTranslations, type SchemaValidationResult, type SelectField, type StorageAdapter, type StorageCommitError, type StreamCsvOptions, type SubmissionCursorValue, type SubmissionFilter, type SubmissionPage, type SubmissionPageQueryOptions, type SubmissionQueryOptions, type TextAnswerCursorValue, type TextAnswerItem, type TextAnswerPage, type TextAnswerPageQueryOptions, type TextField, type TextFieldConstraintRule, type TextQuestionAggregate, type TranslationAdapter, type TranslationReport, type TranslationSlot, type TranslationStatus, type ValidateFormSchemaOptions, type ValidationCode, type ValidationError, type ValidationIssue, type VersionTransitionError, type VersionTransitionEvent, type VersionTransitionPlan, type VersionedFormStorageAdapter, type WebhookConfig, type WebhookDispatchResult, aggregateResponses, assertValidFormSchema, assertVersionMutable, calculateChoiceDistribution, calculateCrossTabulation, calculateFieldVisibility, calculateNumericSummary, calculatePageVisibility, cloneVersionToDraft, collectSchemaLocales, collectTranslationSlots, computeSourceTextHash, createCloneTransitionPlan, createDeleteDraftTransitionPlan, createPublishTransitionPlan, createResponseAccumulator, createSubmission, decodeSubmissionCursor, decodeTextAnswerCursor, deleteDraft, dispatchWebhook, encodeSubmissionCursor, encodeTextAnswerCursor, escapeCsvCell, exportResponsesToCsv, exportResponsesToCsvStream, getTranslationStatus, isDisplayConditionGroupSatisfied, isDisplayConditionSatisfied, isQuestionVisible, iterateSubmissionPages, jsonValuesEqual, matchesSubmissionFilter, matchesSubmissionPageFilters, normalizeSubmissionPageSize, pipeResponsesToCsvStream, populateSchemaTranslations, publishDraft, resolveFormTranslation, resolveLocalizedSchema, sanitizeSchema, selectVisibleAnswers, transformFieldType, validateAnswers, validateFormSchema, validatePageAnswers, validateSchemaStructure };
|
|
750
|
+
export { type AccumulatorReport, type AccumulatorResponse, type AccumulatorSkipReason, type AnswerValidationResult, type AsyncTranslationAdapter, type BaseField, type BaseFieldConstraintRule, type BuilderTranslationKey, type CanonicalTranslationMetadata, type CheckboxField, type CheckboxQuestionAggregate, type ChoiceDistributionEntry, type ChoiceFieldConstraintRule, type ChoiceOption, type ChoiceQuestionAggregate, type CloneVersionOptions, type CollectedLocales, type ConditionOperator, type ConditionValue, type CreateSubmissionOptions, type CrossTabulationResult, type CsvColumnContext, type CsvColumnDef, type CsvExportOptions, DEFAULT_FIELD_TYPE_DEFINITIONS, type DeleteDraftOptions, type DisplayCondition, type DisplayConditionGroup, type DisplayRule, type ExtensibleNode, type FieldConstraintRule, type FieldDisplayCondition, type FieldOption, type FieldType, type FieldTypeDefinition, type FormAnalytics, type FormEvent, type FormEventType, type FormField, type FormPage, type FormPolicy, type FormResponse, type FormSchema, type FormStorageAdapter, type FormSubmission, type FormSubmissionSettings, type FormValue, type FormValues, type FormVersionRecord, type FormVersionState, type FormVersionStatus, type JsonValue, type LegacyTranslationMetadata, type LocalizedText, type MultiSelectField, type NodeWritableStream, type NumberField, type NumberQuestionAggregate, type NumericSummary, type OptionAggregate, type PagedSubmissionStorageAdapter, type PaginationIteratorOptions, type PopulateTranslationOptions, type PopulateTranslationsOptions, type PublishDraftOptions, type PublishDraftResult, type Question, type QuestionAggregate, type QuestionType, type RatingField, type RatingFieldConstraintRule, type ResponseAccumulator, type ResponseAccumulatorOptions, type Result, type SanitizeSchemaOptions, type SchemaIssue, type SchemaStructureIssue, type SchemaStructureIssueType, type SchemaTranslations, type SchemaValidationResult, type SelectField, type StorageAdapter, type StorageCommitError, type StreamCsvOptions, type SubmissionCursorValue, type SubmissionFilter, type SubmissionPage, type SubmissionPageQueryOptions, type SubmissionQueryOptions, type TextAnswerCursorValue, type TextAnswerItem, type TextAnswerPage, type TextAnswerPageQueryOptions, type TextField, type TextFieldConstraintRule, type TextQuestionAggregate, type TranslationAdapter, type TranslationReport, type TranslationSlot, type TranslationStatus, type ValidateFormSchemaOptions, type ValidationCode, type ValidationError, type ValidationIssue, type VersionTransitionError, type VersionTransitionEvent, type VersionTransitionPlan, type VersionedFormStorageAdapter, type WebhookConfig, type WebhookDispatchResult, aggregateResponses, assertValidFormSchema, assertVersionMutable, calculateChoiceDistribution, calculateCrossTabulation, calculateFieldVisibility, calculateNumericSummary, calculatePageVisibility, cloneVersionToDraft, collectSchemaLocales, collectTranslationSlots, computeSourceTextHash, createCloneTransitionPlan, createDeleteDraftTransitionPlan, createPublishTransitionPlan, createResponseAccumulator, createSubmission, decodeSubmissionCursor, decodeTextAnswerCursor, deleteDraft, dispatchWebhook, encodeSubmissionCursor, encodeTextAnswerCursor, escapeCsvCell, exportResponsesToCsv, exportResponsesToCsvStream, getTranslationStatus, isDisplayConditionGroupSatisfied, isDisplayConditionSatisfied, isManualTranslationMetadata, isQuestionVisible, iterateSubmissionPages, jsonValuesEqual, matchesSubmissionFilter, matchesSubmissionPageFilters, migrateSchemaTranslationMetadata, normalizeSubmissionPageSize, pipeResponsesToCsvStream, populateSchemaTranslations, publishDraft, removeLocaleFromSchema, resolveFormTranslation, resolveLocalizedSchema, sanitizeSchema, selectVisibleAnswers, transformFieldType, validateAnswers, validateFormSchema, validatePageAnswers, validateSchemaStructure };
|
package/dist/index.d.ts
CHANGED
|
@@ -686,15 +686,34 @@ interface CanonicalTranslationMetadata {
|
|
|
686
686
|
readonly translatedAt?: string;
|
|
687
687
|
readonly editedAt?: string;
|
|
688
688
|
}
|
|
689
|
+
interface LegacyTranslationMetadata {
|
|
690
|
+
readonly isManuallyEdited?: boolean;
|
|
691
|
+
readonly translationSource?: "MANUAL" | "AUTOMATIC" | "manual" | "automatic" | string;
|
|
692
|
+
readonly sourceTextHash?: string;
|
|
693
|
+
readonly sourceText?: string;
|
|
694
|
+
readonly sourceLocale?: string;
|
|
695
|
+
readonly translatedAt?: string;
|
|
696
|
+
readonly editedAt?: string;
|
|
697
|
+
readonly isManual?: boolean;
|
|
698
|
+
readonly [key: string]: unknown;
|
|
699
|
+
}
|
|
700
|
+
declare const isManualTranslationMetadata: (metadata?: LegacyTranslationMetadata | CanonicalTranslationMetadata) => boolean;
|
|
689
701
|
interface PopulateTranslationOptions {
|
|
690
702
|
readonly overwrite?: "all" | "missing-only" | "stale-and-missing";
|
|
691
703
|
readonly preserveManualTranslations?: boolean;
|
|
692
704
|
readonly markStaleTranslations?: boolean;
|
|
693
705
|
readonly shouldOverwrite?: (slot: TranslationSlot) => boolean;
|
|
694
706
|
readonly createMetadata?: (slot: TranslationSlot, translatedText: string) => Readonly<Record<string, JsonValue>>;
|
|
707
|
+
readonly isManualTranslation?: (metadata: unknown, context: {
|
|
708
|
+
readonly path: string;
|
|
709
|
+
readonly locale: string;
|
|
710
|
+
}) => boolean;
|
|
711
|
+
readonly normalizeMetadata?: (metadata: unknown, sourceText: string) => CanonicalTranslationMetadata;
|
|
695
712
|
/** Applies locale admission and count limits before the adapter is called. */
|
|
696
713
|
readonly policy?: Pick<FormPolicy, "allowedLocales" | "maxLocales">;
|
|
697
714
|
}
|
|
715
|
+
/** Compatibility alias for clients that used the pluralized options name. */
|
|
716
|
+
type PopulateTranslationsOptions = PopulateTranslationOptions;
|
|
698
717
|
interface TranslationReport {
|
|
699
718
|
readonly updatedSlots: readonly TranslationSlot[];
|
|
700
719
|
readonly skippedSlots: readonly TranslationSlot[];
|
|
@@ -703,6 +722,9 @@ interface TranslationReport {
|
|
|
703
722
|
}
|
|
704
723
|
declare const computeSourceTextHash: (text: string) => string;
|
|
705
724
|
declare function getTranslationStatus(sourceText: string, translatedText: string | undefined, metadata: CanonicalTranslationMetadata | Readonly<Record<string, JsonValue>> | undefined): TranslationStatus;
|
|
725
|
+
declare const migrateSchemaTranslationMetadata: (schema: FormSchema, customMigrator?: (oldMeta: unknown, sourceText: string) => CanonicalTranslationMetadata) => FormSchema;
|
|
726
|
+
/** Removes a locale registration and every localized value and metadata entry for it. */
|
|
727
|
+
declare const removeLocaleFromSchema: (schema: FormSchema, localeToRemove: string) => FormSchema;
|
|
706
728
|
declare function collectTranslationSlots(schema: FormSchema, locale: string): readonly TranslationSlot[];
|
|
707
729
|
declare function resolveLocalizedSchema(schema: FormSchema, targetLocale?: string): FormSchema;
|
|
708
730
|
declare function populateSchemaTranslations(schema: FormSchema, targetLocales: readonly string[], adapter: AsyncTranslationAdapter, options?: PopulateTranslationOptions): Promise<{
|
|
@@ -725,4 +747,4 @@ declare function calculatePageVisibility(schema: FormSchema, currentAnswers: Rea
|
|
|
725
747
|
declare function calculateFieldVisibility(schema: FormSchema, currentAnswers: Readonly<Record<string, unknown>>): Readonly<Record<string, boolean>>;
|
|
726
748
|
declare function selectVisibleAnswers(schema: FormSchema, currentAnswers: FormValues): FormValues;
|
|
727
749
|
|
|
728
|
-
export { type AccumulatorReport, type AccumulatorResponse, type AccumulatorSkipReason, type AnswerValidationResult, type AsyncTranslationAdapter, type BaseField, type BaseFieldConstraintRule, type BuilderTranslationKey, type CanonicalTranslationMetadata, type CheckboxField, type CheckboxQuestionAggregate, type ChoiceDistributionEntry, type ChoiceFieldConstraintRule, type ChoiceOption, type ChoiceQuestionAggregate, type CloneVersionOptions, type CollectedLocales, type ConditionOperator, type ConditionValue, type CreateSubmissionOptions, type CrossTabulationResult, type CsvColumnContext, type CsvColumnDef, type CsvExportOptions, DEFAULT_FIELD_TYPE_DEFINITIONS, type DeleteDraftOptions, type DisplayCondition, type DisplayConditionGroup, type DisplayRule, type ExtensibleNode, type FieldConstraintRule, type FieldDisplayCondition, type FieldOption, type FieldType, type FieldTypeDefinition, type FormAnalytics, type FormEvent, type FormEventType, type FormField, type FormPage, type FormPolicy, type FormResponse, type FormSchema, type FormStorageAdapter, type FormSubmission, type FormSubmissionSettings, type FormValue, type FormValues, type FormVersionRecord, type FormVersionState, type FormVersionStatus, type JsonValue, type LocalizedText, type MultiSelectField, type NodeWritableStream, type NumberField, type NumberQuestionAggregate, type NumericSummary, type OptionAggregate, type PagedSubmissionStorageAdapter, type PaginationIteratorOptions, type PopulateTranslationOptions, type PublishDraftOptions, type PublishDraftResult, type Question, type QuestionAggregate, type QuestionType, type RatingField, type RatingFieldConstraintRule, type ResponseAccumulator, type ResponseAccumulatorOptions, type Result, type SanitizeSchemaOptions, type SchemaIssue, type SchemaStructureIssue, type SchemaStructureIssueType, type SchemaTranslations, type SchemaValidationResult, type SelectField, type StorageAdapter, type StorageCommitError, type StreamCsvOptions, type SubmissionCursorValue, type SubmissionFilter, type SubmissionPage, type SubmissionPageQueryOptions, type SubmissionQueryOptions, type TextAnswerCursorValue, type TextAnswerItem, type TextAnswerPage, type TextAnswerPageQueryOptions, type TextField, type TextFieldConstraintRule, type TextQuestionAggregate, type TranslationAdapter, type TranslationReport, type TranslationSlot, type TranslationStatus, type ValidateFormSchemaOptions, type ValidationCode, type ValidationError, type ValidationIssue, type VersionTransitionError, type VersionTransitionEvent, type VersionTransitionPlan, type VersionedFormStorageAdapter, type WebhookConfig, type WebhookDispatchResult, aggregateResponses, assertValidFormSchema, assertVersionMutable, calculateChoiceDistribution, calculateCrossTabulation, calculateFieldVisibility, calculateNumericSummary, calculatePageVisibility, cloneVersionToDraft, collectSchemaLocales, collectTranslationSlots, computeSourceTextHash, createCloneTransitionPlan, createDeleteDraftTransitionPlan, createPublishTransitionPlan, createResponseAccumulator, createSubmission, decodeSubmissionCursor, decodeTextAnswerCursor, deleteDraft, dispatchWebhook, encodeSubmissionCursor, encodeTextAnswerCursor, escapeCsvCell, exportResponsesToCsv, exportResponsesToCsvStream, getTranslationStatus, isDisplayConditionGroupSatisfied, isDisplayConditionSatisfied, isQuestionVisible, iterateSubmissionPages, jsonValuesEqual, matchesSubmissionFilter, matchesSubmissionPageFilters, normalizeSubmissionPageSize, pipeResponsesToCsvStream, populateSchemaTranslations, publishDraft, resolveFormTranslation, resolveLocalizedSchema, sanitizeSchema, selectVisibleAnswers, transformFieldType, validateAnswers, validateFormSchema, validatePageAnswers, validateSchemaStructure };
|
|
750
|
+
export { type AccumulatorReport, type AccumulatorResponse, type AccumulatorSkipReason, type AnswerValidationResult, type AsyncTranslationAdapter, type BaseField, type BaseFieldConstraintRule, type BuilderTranslationKey, type CanonicalTranslationMetadata, type CheckboxField, type CheckboxQuestionAggregate, type ChoiceDistributionEntry, type ChoiceFieldConstraintRule, type ChoiceOption, type ChoiceQuestionAggregate, type CloneVersionOptions, type CollectedLocales, type ConditionOperator, type ConditionValue, type CreateSubmissionOptions, type CrossTabulationResult, type CsvColumnContext, type CsvColumnDef, type CsvExportOptions, DEFAULT_FIELD_TYPE_DEFINITIONS, type DeleteDraftOptions, type DisplayCondition, type DisplayConditionGroup, type DisplayRule, type ExtensibleNode, type FieldConstraintRule, type FieldDisplayCondition, type FieldOption, type FieldType, type FieldTypeDefinition, type FormAnalytics, type FormEvent, type FormEventType, type FormField, type FormPage, type FormPolicy, type FormResponse, type FormSchema, type FormStorageAdapter, type FormSubmission, type FormSubmissionSettings, type FormValue, type FormValues, type FormVersionRecord, type FormVersionState, type FormVersionStatus, type JsonValue, type LegacyTranslationMetadata, type LocalizedText, type MultiSelectField, type NodeWritableStream, type NumberField, type NumberQuestionAggregate, type NumericSummary, type OptionAggregate, type PagedSubmissionStorageAdapter, type PaginationIteratorOptions, type PopulateTranslationOptions, type PopulateTranslationsOptions, type PublishDraftOptions, type PublishDraftResult, type Question, type QuestionAggregate, type QuestionType, type RatingField, type RatingFieldConstraintRule, type ResponseAccumulator, type ResponseAccumulatorOptions, type Result, type SanitizeSchemaOptions, type SchemaIssue, type SchemaStructureIssue, type SchemaStructureIssueType, type SchemaTranslations, type SchemaValidationResult, type SelectField, type StorageAdapter, type StorageCommitError, type StreamCsvOptions, type SubmissionCursorValue, type SubmissionFilter, type SubmissionPage, type SubmissionPageQueryOptions, type SubmissionQueryOptions, type TextAnswerCursorValue, type TextAnswerItem, type TextAnswerPage, type TextAnswerPageQueryOptions, type TextField, type TextFieldConstraintRule, type TextQuestionAggregate, type TranslationAdapter, type TranslationReport, type TranslationSlot, type TranslationStatus, type ValidateFormSchemaOptions, type ValidationCode, type ValidationError, type ValidationIssue, type VersionTransitionError, type VersionTransitionEvent, type VersionTransitionPlan, type VersionedFormStorageAdapter, type WebhookConfig, type WebhookDispatchResult, aggregateResponses, assertValidFormSchema, assertVersionMutable, calculateChoiceDistribution, calculateCrossTabulation, calculateFieldVisibility, calculateNumericSummary, calculatePageVisibility, cloneVersionToDraft, collectSchemaLocales, collectTranslationSlots, computeSourceTextHash, createCloneTransitionPlan, createDeleteDraftTransitionPlan, createPublishTransitionPlan, createResponseAccumulator, createSubmission, decodeSubmissionCursor, decodeTextAnswerCursor, deleteDraft, dispatchWebhook, encodeSubmissionCursor, encodeTextAnswerCursor, escapeCsvCell, exportResponsesToCsv, exportResponsesToCsvStream, getTranslationStatus, isDisplayConditionGroupSatisfied, isDisplayConditionSatisfied, isManualTranslationMetadata, isQuestionVisible, iterateSubmissionPages, jsonValuesEqual, matchesSubmissionFilter, matchesSubmissionPageFilters, migrateSchemaTranslationMetadata, normalizeSubmissionPageSize, pipeResponsesToCsvStream, populateSchemaTranslations, publishDraft, removeLocaleFromSchema, resolveFormTranslation, resolveLocalizedSchema, sanitizeSchema, selectVisibleAnswers, transformFieldType, validateAnswers, validateFormSchema, validatePageAnswers, validateSchemaStructure };
|
package/dist/index.js
CHANGED
|
@@ -2143,6 +2143,12 @@ function createSubmission(schema, values, options) {
|
|
|
2143
2143
|
}
|
|
2144
2144
|
|
|
2145
2145
|
// src/translation.ts
|
|
2146
|
+
var isManualTranslationMetadata = (metadata) => {
|
|
2147
|
+
if (metadata === void 0) return false;
|
|
2148
|
+
if ("isManuallyEdited" in metadata && metadata.isManuallyEdited === true || "isManual" in metadata && metadata.isManual === true)
|
|
2149
|
+
return true;
|
|
2150
|
+
return typeof metadata.translationSource === "string" && metadata.translationSource.toLowerCase() === "manual";
|
|
2151
|
+
};
|
|
2146
2152
|
var computeSourceTextHash = (text) => {
|
|
2147
2153
|
const normalized = text.normalize("NFKC").trim().replace(/\s+/gu, " ");
|
|
2148
2154
|
let hash = 2166136261;
|
|
@@ -2153,11 +2159,14 @@ var computeSourceTextHash = (text) => {
|
|
|
2153
2159
|
return (hash >>> 0).toString(16).padStart(8, "0");
|
|
2154
2160
|
};
|
|
2155
2161
|
function getTranslationStatus(sourceText, translatedText, metadata) {
|
|
2162
|
+
return getTranslationStatusWithManualOverride(sourceText, translatedText, metadata, void 0);
|
|
2163
|
+
}
|
|
2164
|
+
function getTranslationStatusWithManualOverride(sourceText, translatedText, metadata, manualOverride) {
|
|
2156
2165
|
if (translatedText === void 0 || translatedText.trim() === "") return "missing";
|
|
2157
2166
|
if (metadata === void 0) return "translated";
|
|
2158
2167
|
const currentHash = computeSourceTextHash(sourceText);
|
|
2159
2168
|
const sourceHash = typeof metadata.sourceTextHash === "string" ? metadata.sourceTextHash : void 0;
|
|
2160
|
-
const isManual =
|
|
2169
|
+
const isManual = manualOverride ?? isManualTranslationMetadata(metadata);
|
|
2161
2170
|
if (isManual) return sourceHash === void 0 || sourceHash === currentHash ? "manual" : "manual-stale";
|
|
2162
2171
|
return sourceHash === void 0 || sourceHash === currentHash ? "translated" : "stale";
|
|
2163
2172
|
}
|
|
@@ -2183,8 +2192,11 @@ function withTranslationMetadata(node, locale, property, metadata) {
|
|
|
2183
2192
|
}
|
|
2184
2193
|
};
|
|
2185
2194
|
}
|
|
2186
|
-
function createSlot(kind, nodeId, property, locale, sourceText, existingText, nodeMetadata, existingTranslationMetadata) {
|
|
2187
|
-
const
|
|
2195
|
+
function createSlot(kind, nodeId, property, locale, sourceText, existingText, nodeMetadata, existingTranslationMetadata, options = {}) {
|
|
2196
|
+
const path = `${kind}.${nodeId}.${property}`;
|
|
2197
|
+
const manual = options.isManualTranslation?.(existingTranslationMetadata, { path, locale }) ?? isManualTranslationMetadata(existingTranslationMetadata);
|
|
2198
|
+
const normalizedMetadata = existingTranslationMetadata === void 0 ? void 0 : options.normalizeMetadata === void 0 ? existingTranslationMetadata : { ...options.normalizeMetadata(existingTranslationMetadata, sourceText) };
|
|
2199
|
+
const status = getTranslationStatusWithManualOverride(sourceText, existingText, normalizedMetadata, manual);
|
|
2188
2200
|
return {
|
|
2189
2201
|
kind,
|
|
2190
2202
|
nodeId,
|
|
@@ -2192,15 +2204,15 @@ function createSlot(kind, nodeId, property, locale, sourceText, existingText, no
|
|
|
2192
2204
|
locale,
|
|
2193
2205
|
sourceText,
|
|
2194
2206
|
target: { kind, ...nodeId.length === 0 ? {} : { id: nodeId }, property },
|
|
2195
|
-
path
|
|
2207
|
+
path,
|
|
2196
2208
|
sourceTextHash: computeSourceTextHash(sourceText),
|
|
2197
2209
|
status,
|
|
2198
2210
|
...existingText === void 0 ? {} : { existingText },
|
|
2199
2211
|
...nodeMetadata === void 0 ? {} : { nodeMetadata, metadata: nodeMetadata },
|
|
2200
|
-
...
|
|
2212
|
+
...normalizedMetadata === void 0 ? {} : { existingTranslationMetadata: normalizedMetadata }
|
|
2201
2213
|
};
|
|
2202
2214
|
}
|
|
2203
|
-
function translationSlots(schema, locale) {
|
|
2215
|
+
function translationSlots(schema, locale, options = {}) {
|
|
2204
2216
|
const descriptors = [];
|
|
2205
2217
|
const addFormSlot = (property, sourceText) => {
|
|
2206
2218
|
const slot = createSlot(
|
|
@@ -2211,10 +2223,15 @@ function translationSlots(schema, locale) {
|
|
|
2211
2223
|
sourceText,
|
|
2212
2224
|
schema.translations?.[locale]?.[property],
|
|
2213
2225
|
schema.metadata,
|
|
2214
|
-
schema.translationMetadata?.[locale]?.[property]
|
|
2226
|
+
schema.translationMetadata?.[locale]?.[property],
|
|
2227
|
+
options
|
|
2215
2228
|
);
|
|
2216
2229
|
descriptors.push({
|
|
2217
2230
|
slot,
|
|
2231
|
+
manual: options.isManualTranslation?.(schema.translationMetadata?.[locale]?.[property], {
|
|
2232
|
+
path: slot.path ?? "",
|
|
2233
|
+
locale
|
|
2234
|
+
}) ?? isManualTranslationMetadata(schema.translationMetadata?.[locale]?.[property]),
|
|
2218
2235
|
apply: (current, value, metadata) => withTranslationMetadata(
|
|
2219
2236
|
{ ...current, translations: mergeLocalizedText(current.translations, locale, property, value) },
|
|
2220
2237
|
locale,
|
|
@@ -2236,10 +2253,15 @@ function translationSlots(schema, locale) {
|
|
|
2236
2253
|
sourceText,
|
|
2237
2254
|
field.translations?.[locale]?.[property],
|
|
2238
2255
|
field.metadata,
|
|
2239
|
-
field.translationMetadata?.[locale]?.[property]
|
|
2256
|
+
field.translationMetadata?.[locale]?.[property],
|
|
2257
|
+
options
|
|
2240
2258
|
);
|
|
2241
2259
|
descriptors.push({
|
|
2242
2260
|
slot,
|
|
2261
|
+
manual: options.isManualTranslation?.(field.translationMetadata?.[locale]?.[property], {
|
|
2262
|
+
path: slot.path ?? "",
|
|
2263
|
+
locale
|
|
2264
|
+
}) ?? isManualTranslationMetadata(field.translationMetadata?.[locale]?.[property]),
|
|
2243
2265
|
apply: (current, value, metadata) => ({
|
|
2244
2266
|
...current,
|
|
2245
2267
|
fields: current.fields.map(
|
|
@@ -2268,10 +2290,15 @@ function translationSlots(schema, locale) {
|
|
|
2268
2290
|
option.label,
|
|
2269
2291
|
option.translations?.[locale],
|
|
2270
2292
|
option.metadata,
|
|
2271
|
-
option.translationMetadata?.[locale]?.label
|
|
2293
|
+
option.translationMetadata?.[locale]?.label,
|
|
2294
|
+
options
|
|
2272
2295
|
);
|
|
2273
2296
|
descriptors.push({
|
|
2274
2297
|
slot,
|
|
2298
|
+
manual: options.isManualTranslation?.(option.translationMetadata?.[locale]?.label, {
|
|
2299
|
+
path: slot.path ?? "",
|
|
2300
|
+
locale
|
|
2301
|
+
}) ?? isManualTranslationMetadata(option.translationMetadata?.[locale]?.label),
|
|
2275
2302
|
apply: (current, value, metadata) => ({
|
|
2276
2303
|
...current,
|
|
2277
2304
|
fields: current.fields.map((candidate, candidateIndex) => {
|
|
@@ -2306,10 +2333,15 @@ function translationSlots(schema, locale) {
|
|
|
2306
2333
|
sourceText,
|
|
2307
2334
|
page.translations?.[locale]?.[property],
|
|
2308
2335
|
page.metadata,
|
|
2309
|
-
page.translationMetadata?.[locale]?.[property]
|
|
2336
|
+
page.translationMetadata?.[locale]?.[property],
|
|
2337
|
+
options
|
|
2310
2338
|
);
|
|
2311
2339
|
descriptors.push({
|
|
2312
2340
|
slot,
|
|
2341
|
+
manual: options.isManualTranslation?.(page.translationMetadata?.[locale]?.[property], {
|
|
2342
|
+
path: slot.path ?? "",
|
|
2343
|
+
locale
|
|
2344
|
+
}) ?? isManualTranslationMetadata(page.translationMetadata?.[locale]?.[property]),
|
|
2313
2345
|
apply: (current, value, metadata) => ({
|
|
2314
2346
|
...current,
|
|
2315
2347
|
...current.pages === void 0 ? {} : {
|
|
@@ -2333,6 +2365,122 @@ function translationSlots(schema, locale) {
|
|
|
2333
2365
|
});
|
|
2334
2366
|
return descriptors;
|
|
2335
2367
|
}
|
|
2368
|
+
function removeLocaleRecord(record, locale) {
|
|
2369
|
+
if (record === void 0) return void 0;
|
|
2370
|
+
const remaining = Object.entries(record).filter(([candidate]) => candidate !== locale);
|
|
2371
|
+
return remaining.length === 0 ? void 0 : Object.fromEntries(remaining);
|
|
2372
|
+
}
|
|
2373
|
+
function removeLocalizedNodeLocale(node, locale) {
|
|
2374
|
+
const translations = removeLocaleRecord(node.translations, locale);
|
|
2375
|
+
const translationMetadata = removeLocaleRecord(node.translationMetadata, locale);
|
|
2376
|
+
const { translations: _translations, translationMetadata: _translationMetadata, ...base } = node;
|
|
2377
|
+
return {
|
|
2378
|
+
...base,
|
|
2379
|
+
...translations === void 0 ? {} : { translations },
|
|
2380
|
+
...translationMetadata === void 0 ? {} : { translationMetadata }
|
|
2381
|
+
};
|
|
2382
|
+
}
|
|
2383
|
+
function migrateMetadata(metadata, sourceText, defaultLocale, customMigrator) {
|
|
2384
|
+
if (customMigrator !== void 0) return customMigrator(metadata, sourceText);
|
|
2385
|
+
const record = metadata !== null && typeof metadata === "object" ? metadata : void 0;
|
|
2386
|
+
const sourceLocale = typeof record?.sourceLocale === "string" ? record.sourceLocale : defaultLocale ?? "";
|
|
2387
|
+
const translationSource = isManualTranslationMetadata(record) ? "manual" : "automatic";
|
|
2388
|
+
return {
|
|
2389
|
+
sourceLocale,
|
|
2390
|
+
sourceTextHash: computeSourceTextHash(sourceText),
|
|
2391
|
+
translationSource,
|
|
2392
|
+
...typeof record?.translatedAt === "string" ? { translatedAt: record.translatedAt } : {},
|
|
2393
|
+
...typeof record?.editedAt === "string" ? { editedAt: record.editedAt } : {}
|
|
2394
|
+
};
|
|
2395
|
+
}
|
|
2396
|
+
function migrateNodeMetadata(node, sourceTexts, defaultLocale, customMigrator) {
|
|
2397
|
+
if (node.translationMetadata === void 0) return node;
|
|
2398
|
+
const translationMetadata = Object.fromEntries(
|
|
2399
|
+
Object.entries(node.translationMetadata).map(([locale, properties]) => [
|
|
2400
|
+
locale,
|
|
2401
|
+
Object.fromEntries(
|
|
2402
|
+
Object.entries(properties).map(([property, metadata]) => [
|
|
2403
|
+
property,
|
|
2404
|
+
migrateMetadata(metadata, sourceTexts[property] ?? "", defaultLocale, customMigrator)
|
|
2405
|
+
])
|
|
2406
|
+
)
|
|
2407
|
+
])
|
|
2408
|
+
);
|
|
2409
|
+
return { ...node, translationMetadata };
|
|
2410
|
+
}
|
|
2411
|
+
var migrateSchemaTranslationMetadata = (schema, customMigrator) => {
|
|
2412
|
+
const migratedSchema = migrateNodeMetadata(
|
|
2413
|
+
schema,
|
|
2414
|
+
{
|
|
2415
|
+
title: schema.title,
|
|
2416
|
+
...schema.description === void 0 ? {} : { description: schema.description },
|
|
2417
|
+
...schema.completionMessage === void 0 ? {} : { completionMessage: schema.completionMessage }
|
|
2418
|
+
},
|
|
2419
|
+
schema.defaultLocale,
|
|
2420
|
+
customMigrator
|
|
2421
|
+
);
|
|
2422
|
+
const fields = schema.fields.map((field) => {
|
|
2423
|
+
const migratedField = migrateNodeMetadata(
|
|
2424
|
+
field,
|
|
2425
|
+
{ title: field.title, ...field.description === void 0 ? {} : { description: field.description } },
|
|
2426
|
+
schema.defaultLocale,
|
|
2427
|
+
customMigrator
|
|
2428
|
+
);
|
|
2429
|
+
if (!("options" in migratedField)) return migratedField;
|
|
2430
|
+
return {
|
|
2431
|
+
...migratedField,
|
|
2432
|
+
options: migratedField.options.map(
|
|
2433
|
+
(option) => migrateNodeMetadata(option, { label: option.label }, schema.defaultLocale, customMigrator)
|
|
2434
|
+
)
|
|
2435
|
+
};
|
|
2436
|
+
});
|
|
2437
|
+
const pages = schema.pages?.map(
|
|
2438
|
+
(page) => migrateNodeMetadata(
|
|
2439
|
+
page,
|
|
2440
|
+
{
|
|
2441
|
+
...page.title === void 0 ? {} : { title: page.title },
|
|
2442
|
+
...page.description === void 0 ? {} : { description: page.description }
|
|
2443
|
+
},
|
|
2444
|
+
schema.defaultLocale,
|
|
2445
|
+
customMigrator
|
|
2446
|
+
)
|
|
2447
|
+
);
|
|
2448
|
+
return {
|
|
2449
|
+
...migratedSchema,
|
|
2450
|
+
fields,
|
|
2451
|
+
...pages === void 0 ? {} : { pages }
|
|
2452
|
+
};
|
|
2453
|
+
};
|
|
2454
|
+
var removeLocaleFromSchema = (schema, localeToRemove) => {
|
|
2455
|
+
if (localeToRemove === schema.defaultLocale) {
|
|
2456
|
+
throw new Error(`Cannot remove defaultLocale: ${localeToRemove}`);
|
|
2457
|
+
}
|
|
2458
|
+
const form = removeLocalizedNodeLocale(schema, localeToRemove);
|
|
2459
|
+
const fields = schema.fields.map((field) => {
|
|
2460
|
+
const localizedField = removeLocalizedNodeLocale(field, localeToRemove);
|
|
2461
|
+
if (!("options" in localizedField)) return localizedField;
|
|
2462
|
+
return {
|
|
2463
|
+
...localizedField,
|
|
2464
|
+
options: localizedField.options.map((option) => {
|
|
2465
|
+
const translations = removeLocaleRecord(option.translations, localeToRemove);
|
|
2466
|
+
const translationMetadata = removeLocaleRecord(option.translationMetadata, localeToRemove);
|
|
2467
|
+
const { translations: _translations, translationMetadata: _translationMetadata, ...base } = option;
|
|
2468
|
+
return {
|
|
2469
|
+
...base,
|
|
2470
|
+
...translations === void 0 ? {} : { translations },
|
|
2471
|
+
...translationMetadata === void 0 ? {} : { translationMetadata }
|
|
2472
|
+
};
|
|
2473
|
+
})
|
|
2474
|
+
};
|
|
2475
|
+
});
|
|
2476
|
+
const pages = schema.pages?.map((page) => removeLocalizedNodeLocale(page, localeToRemove));
|
|
2477
|
+
return {
|
|
2478
|
+
...form,
|
|
2479
|
+
supportedLocales: (schema.supportedLocales ?? []).filter((locale) => locale !== localeToRemove),
|
|
2480
|
+
fields,
|
|
2481
|
+
...pages === void 0 ? {} : { pages }
|
|
2482
|
+
};
|
|
2483
|
+
};
|
|
2336
2484
|
function collectTranslationSlots(schema, locale) {
|
|
2337
2485
|
return translationSlots(schema, locale).map((descriptor) => descriptor.slot);
|
|
2338
2486
|
}
|
|
@@ -2396,7 +2544,7 @@ async function populateSchemaTranslations(schema, targetLocales, adapter, option
|
|
|
2396
2544
|
const skippedReasons = {};
|
|
2397
2545
|
let result = schema;
|
|
2398
2546
|
for (const locale of locales) {
|
|
2399
|
-
const descriptors = translationSlots(schema, locale);
|
|
2547
|
+
const descriptors = translationSlots(schema, locale, options);
|
|
2400
2548
|
if (options.markStaleTranslations ?? true) {
|
|
2401
2549
|
for (const descriptor of descriptors) {
|
|
2402
2550
|
if (descriptor.slot.status === "stale" || descriptor.slot.status === "manual-stale")
|
|
@@ -2406,8 +2554,9 @@ async function populateSchemaTranslations(schema, targetLocales, adapter, option
|
|
|
2406
2554
|
const selected = [];
|
|
2407
2555
|
for (const descriptor of descriptors) {
|
|
2408
2556
|
const status = descriptor.slot.status ?? "missing";
|
|
2409
|
-
const manual = status === "manual" || status === "manual-stale";
|
|
2410
|
-
const
|
|
2557
|
+
const manual = descriptor.manual || status === "manual" || status === "manual-stale";
|
|
2558
|
+
const requestedOverwrite = options.shouldOverwrite?.(descriptor.slot);
|
|
2559
|
+
const shouldTranslate = (options.preserveManualTranslations ?? true) && manual ? false : requestedOverwrite ?? (options.overwrite === "all" || (options.overwrite === "stale-and-missing" || options.overwrite === void 0 ? status === "missing" || status === "stale" || !(options.preserveManualTranslations ?? true) && status === "manual-stale" : status === "missing"));
|
|
2411
2560
|
if (shouldTranslate) selected.push(descriptor);
|
|
2412
2561
|
else {
|
|
2413
2562
|
skippedSlots.push(descriptor.slot);
|
|
@@ -2768,15 +2917,18 @@ export {
|
|
|
2768
2917
|
getTranslationStatus,
|
|
2769
2918
|
isDisplayConditionGroupSatisfied,
|
|
2770
2919
|
isDisplayConditionSatisfied,
|
|
2920
|
+
isManualTranslationMetadata,
|
|
2771
2921
|
isQuestionVisible,
|
|
2772
2922
|
iterateSubmissionPages,
|
|
2773
2923
|
jsonValuesEqual,
|
|
2774
2924
|
matchesSubmissionFilter,
|
|
2775
2925
|
matchesSubmissionPageFilters,
|
|
2926
|
+
migrateSchemaTranslationMetadata,
|
|
2776
2927
|
normalizeSubmissionPageSize,
|
|
2777
2928
|
pipeResponsesToCsvStream,
|
|
2778
2929
|
populateSchemaTranslations,
|
|
2779
2930
|
publishDraft,
|
|
2931
|
+
removeLocaleFromSchema,
|
|
2780
2932
|
resolveFormTranslation,
|
|
2781
2933
|
resolveLocalizedSchema,
|
|
2782
2934
|
sanitizeSchema,
|