@form-engine-ts/core 4.6.0 → 4.8.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 +6 -1
- package/dist/index.cjs +214 -81
- package/dist/index.d.cts +31 -2
- package/dist/index.d.ts +31 -2
- package/dist/index.js +213 -81
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,8 +1,24 @@
|
|
|
1
|
+
// src/locale.ts
|
|
2
|
+
var normalizeLocale = (rawLocale) => {
|
|
3
|
+
if (!rawLocale || typeof rawLocale !== "string") return null;
|
|
4
|
+
const trimmed = rawLocale.trim().replace(/_/gu, "-");
|
|
5
|
+
if (trimmed.length === 0) return null;
|
|
6
|
+
try {
|
|
7
|
+
return Intl.getCanonicalLocales(trimmed)[0] ?? null;
|
|
8
|
+
} catch {
|
|
9
|
+
return null;
|
|
10
|
+
}
|
|
11
|
+
};
|
|
12
|
+
function canonicalLocaleOrRaw(rawLocale) {
|
|
13
|
+
return normalizeLocale(rawLocale) ?? rawLocale;
|
|
14
|
+
}
|
|
15
|
+
|
|
1
16
|
// src/policy.ts
|
|
2
17
|
function collectRecordKeys(value, path, pathsByLocale) {
|
|
3
|
-
for (const
|
|
18
|
+
for (const rawLocale of Object.keys(value ?? {})) {
|
|
19
|
+
const locale = canonicalLocaleOrRaw(rawLocale);
|
|
4
20
|
const paths = pathsByLocale.get(locale) ?? [];
|
|
5
|
-
paths.push(`${path}.${
|
|
21
|
+
paths.push(`${path}.${rawLocale}`);
|
|
6
22
|
pathsByLocale.set(locale, paths);
|
|
7
23
|
}
|
|
8
24
|
}
|
|
@@ -33,13 +49,15 @@ function collectSchemaLocales(schema) {
|
|
|
33
49
|
});
|
|
34
50
|
const translationLocales = new Set(pathsByLocale.keys());
|
|
35
51
|
const allUniqueLocales = /* @__PURE__ */ new Set([
|
|
36
|
-
...schema.defaultLocale === void 0 ? [] : [schema.defaultLocale],
|
|
37
|
-
...schema.supportedLocales ?? [],
|
|
52
|
+
...schema.defaultLocale === void 0 ? [] : [canonicalLocaleOrRaw(schema.defaultLocale)],
|
|
53
|
+
...(schema.supportedLocales ?? []).map(canonicalLocaleOrRaw),
|
|
38
54
|
...translationLocales
|
|
39
55
|
]);
|
|
56
|
+
const defaultLocale = schema.defaultLocale === void 0 ? void 0 : canonicalLocaleOrRaw(schema.defaultLocale);
|
|
57
|
+
const supportedLocales = (schema.supportedLocales ?? []).map(canonicalLocaleOrRaw);
|
|
40
58
|
return {
|
|
41
|
-
...
|
|
42
|
-
supportedLocales
|
|
59
|
+
...defaultLocale === void 0 ? {} : { defaultLocale },
|
|
60
|
+
supportedLocales,
|
|
43
61
|
translationLocales,
|
|
44
62
|
allUniqueLocales,
|
|
45
63
|
translationLocalePaths: pathsByLocale
|
|
@@ -62,7 +80,12 @@ function displayRuleSourceIds(field) {
|
|
|
62
80
|
}
|
|
63
81
|
function registeredEntries(value, registeredLocales) {
|
|
64
82
|
if (value === void 0) return void 0;
|
|
65
|
-
const entries =
|
|
83
|
+
const entries = [];
|
|
84
|
+
for (const [rawLocale, entry] of Object.entries(value)) {
|
|
85
|
+
const locale = normalizeLocale(rawLocale);
|
|
86
|
+
if (locale === null || !registeredLocales.has(locale)) continue;
|
|
87
|
+
entries.push([locale, entry]);
|
|
88
|
+
}
|
|
66
89
|
return entries.length === 0 ? void 0 : Object.fromEntries(entries);
|
|
67
90
|
}
|
|
68
91
|
function sanitizeNodeLocales(node, registeredLocales) {
|
|
@@ -100,6 +123,16 @@ function sanitizePageLocales(page, registeredLocales) {
|
|
|
100
123
|
const translations = registeredEntries(page.translations, registeredLocales);
|
|
101
124
|
return { ...base, ...translations === void 0 ? {} : { translations } };
|
|
102
125
|
}
|
|
126
|
+
function normalizedLocaleList(locales) {
|
|
127
|
+
return [
|
|
128
|
+
...new Set(
|
|
129
|
+
locales.flatMap((locale) => {
|
|
130
|
+
const normalized = normalizeLocale(locale);
|
|
131
|
+
return normalized === null ? [] : [normalized];
|
|
132
|
+
})
|
|
133
|
+
)
|
|
134
|
+
];
|
|
135
|
+
}
|
|
103
136
|
function sanitizeFieldConstraints(field, policy) {
|
|
104
137
|
const constraint = policy?.fieldConstraints?.[field.type];
|
|
105
138
|
if (constraint === void 0) return field;
|
|
@@ -214,10 +247,9 @@ function validateSchemaStructure(schema) {
|
|
|
214
247
|
}
|
|
215
248
|
function sanitizeSchema(schema, options = {}) {
|
|
216
249
|
const existingQuestionIds = new Set(schema.fields.map((field) => field.id));
|
|
217
|
-
const
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
]);
|
|
250
|
+
const defaultLocale = schema.defaultLocale === void 0 ? null : normalizeLocale(schema.defaultLocale);
|
|
251
|
+
const supportedLocales = schema.supportedLocales === void 0 ? void 0 : normalizedLocaleList(schema.supportedLocales);
|
|
252
|
+
const registeredLocales = /* @__PURE__ */ new Set([...defaultLocale === null ? [] : [defaultLocale], ...supportedLocales ?? []]);
|
|
221
253
|
const cyclic = cyclicQuestionIds(schema.fields);
|
|
222
254
|
const sanitizedFields = schema.fields.map((sourceField) => {
|
|
223
255
|
const field = sanitizeFieldConstraints(sanitizeFieldLocales(sourceField, registeredLocales), options.policy);
|
|
@@ -235,10 +267,17 @@ function sanitizeSchema(schema, options = {}) {
|
|
|
235
267
|
return sanitized;
|
|
236
268
|
});
|
|
237
269
|
const localizedSchema = sanitizeNodeLocales(schema, registeredLocales);
|
|
238
|
-
const {
|
|
270
|
+
const {
|
|
271
|
+
defaultLocale: _defaultLocale,
|
|
272
|
+
supportedLocales: _supportedLocales,
|
|
273
|
+
translations: _translations,
|
|
274
|
+
...schemaWithoutLocaleContent
|
|
275
|
+
} = localizedSchema;
|
|
239
276
|
const translations = registeredEntries(schema.translations, registeredLocales);
|
|
240
277
|
const base = {
|
|
241
278
|
...schemaWithoutLocaleContent,
|
|
279
|
+
...defaultLocale === null ? {} : { defaultLocale },
|
|
280
|
+
...supportedLocales === void 0 ? {} : { supportedLocales },
|
|
242
281
|
...translations === void 0 ? {} : { translations },
|
|
243
282
|
fields: sanitizedFields
|
|
244
283
|
};
|
|
@@ -291,6 +330,12 @@ function isRecord(value) {
|
|
|
291
330
|
function isNonEmptyString(value) {
|
|
292
331
|
return typeof value === "string" && value.trim().length > 0;
|
|
293
332
|
}
|
|
333
|
+
function localeRecordEntry(record, locale) {
|
|
334
|
+
for (const [candidate, value] of Object.entries(record ?? {})) {
|
|
335
|
+
if (canonicalLocaleOrRaw(candidate) === locale) return value;
|
|
336
|
+
}
|
|
337
|
+
return void 0;
|
|
338
|
+
}
|
|
294
339
|
function issue(issues, path, code, message) {
|
|
295
340
|
issues.push({ path, code, message });
|
|
296
341
|
}
|
|
@@ -653,51 +698,55 @@ function collectSchemaText(schema) {
|
|
|
653
698
|
return entries;
|
|
654
699
|
}
|
|
655
700
|
function addRequiredTranslationIssues(schema, locale, issues) {
|
|
656
|
-
if (!(schema.supportedLocales ?? []).
|
|
701
|
+
if (!(schema.supportedLocales ?? []).some((candidate) => canonicalLocaleOrRaw(candidate) === locale)) {
|
|
657
702
|
issue(issues, "supportedLocales", "required_locale_missing", `Required locale ${locale} is missing.`);
|
|
658
703
|
}
|
|
659
|
-
if (
|
|
704
|
+
if (schema.defaultLocale !== void 0 && canonicalLocaleOrRaw(schema.defaultLocale) === locale) return;
|
|
705
|
+
const formTranslation = localeRecordEntry(schema.translations, locale);
|
|
660
706
|
const required = [
|
|
661
|
-
{ path: `translations.${locale}.title`, value:
|
|
707
|
+
{ path: `translations.${locale}.title`, value: formTranslation?.title }
|
|
662
708
|
];
|
|
663
709
|
if (schema.description !== void 0)
|
|
664
|
-
required.push({ path: `translations.${locale}.description`, value:
|
|
710
|
+
required.push({ path: `translations.${locale}.description`, value: formTranslation?.description });
|
|
665
711
|
if (schema.completionMessage !== void 0) {
|
|
666
712
|
required.push({
|
|
667
713
|
path: `translations.${locale}.completionMessage`,
|
|
668
|
-
value:
|
|
714
|
+
value: formTranslation?.completionMessage
|
|
669
715
|
});
|
|
670
716
|
}
|
|
671
717
|
schema.fields.forEach((field, fieldIndex) => {
|
|
718
|
+
const fieldTranslation = localeRecordEntry(field.translations, locale);
|
|
672
719
|
required.push({
|
|
673
720
|
path: `fields[${fieldIndex}].translations.${locale}.title`,
|
|
674
|
-
value:
|
|
721
|
+
value: fieldTranslation?.title
|
|
675
722
|
});
|
|
676
723
|
if (field.description !== void 0) {
|
|
677
724
|
required.push({
|
|
678
725
|
path: `fields[${fieldIndex}].translations.${locale}.description`,
|
|
679
|
-
value:
|
|
726
|
+
value: fieldTranslation?.description
|
|
680
727
|
});
|
|
681
728
|
}
|
|
682
729
|
if (!("options" in field)) return;
|
|
683
730
|
field.options.forEach((option, optionIndex) => {
|
|
731
|
+
const optionTranslation = localeRecordEntry(option.translations, locale);
|
|
684
732
|
required.push({
|
|
685
733
|
path: `fields[${fieldIndex}].options[${optionIndex}].translations.${locale}`,
|
|
686
|
-
value:
|
|
734
|
+
value: optionTranslation
|
|
687
735
|
});
|
|
688
736
|
});
|
|
689
737
|
});
|
|
690
738
|
schema.pages?.forEach((page, pageIndex) => {
|
|
739
|
+
const pageTranslation = localeRecordEntry(page.translations, locale);
|
|
691
740
|
if (page.title !== void 0) {
|
|
692
741
|
required.push({
|
|
693
742
|
path: `pages[${pageIndex}].translations.${locale}.title`,
|
|
694
|
-
value:
|
|
743
|
+
value: pageTranslation?.title
|
|
695
744
|
});
|
|
696
745
|
}
|
|
697
746
|
if (page.description !== void 0) {
|
|
698
747
|
required.push({
|
|
699
748
|
path: `pages[${pageIndex}].translations.${locale}.description`,
|
|
700
|
-
value:
|
|
749
|
+
value: pageTranslation?.description
|
|
701
750
|
});
|
|
702
751
|
}
|
|
703
752
|
});
|
|
@@ -830,8 +879,8 @@ function validatePolicy(schema, policy, issues) {
|
|
|
830
879
|
}
|
|
831
880
|
const collectedLocales = collectSchemaLocales(schema);
|
|
832
881
|
const registeredLocales = /* @__PURE__ */ new Set([
|
|
833
|
-
...
|
|
834
|
-
...
|
|
882
|
+
...collectedLocales.defaultLocale === void 0 ? [] : [collectedLocales.defaultLocale],
|
|
883
|
+
...collectedLocales.supportedLocales
|
|
835
884
|
]);
|
|
836
885
|
for (const locale of collectedLocales.translationLocales) {
|
|
837
886
|
if (registeredLocales.has(locale)) continue;
|
|
@@ -845,23 +894,27 @@ function validatePolicy(schema, policy, issues) {
|
|
|
845
894
|
}
|
|
846
895
|
}
|
|
847
896
|
if (policy.allowedLocales !== void 0) {
|
|
897
|
+
const allowedLocales = new Set(policy.allowedLocales.map(canonicalLocaleOrRaw));
|
|
848
898
|
const pathsByLocale = /* @__PURE__ */ new Map();
|
|
849
|
-
if (
|
|
899
|
+
if (collectedLocales.defaultLocale !== void 0)
|
|
900
|
+
pathsByLocale.set(collectedLocales.defaultLocale, ["defaultLocale"]);
|
|
850
901
|
schema.supportedLocales?.forEach((locale, index) => {
|
|
851
|
-
|
|
902
|
+
const canonical = canonicalLocaleOrRaw(locale);
|
|
903
|
+
pathsByLocale.set(canonical, [...pathsByLocale.get(canonical) ?? [], `supportedLocales[${index}]`]);
|
|
852
904
|
});
|
|
853
905
|
for (const [locale, paths] of collectedLocales.translationLocalePaths) {
|
|
854
906
|
pathsByLocale.set(locale, [...pathsByLocale.get(locale) ?? [], ...paths]);
|
|
855
907
|
}
|
|
856
908
|
for (const [locale, paths] of pathsByLocale) {
|
|
857
|
-
if (!
|
|
909
|
+
if (!allowedLocales.has(locale)) {
|
|
858
910
|
for (const path of paths) {
|
|
859
911
|
issue(issues, path, "disallowed_locale", `Locale ${locale} is not allowed by the form policy.`);
|
|
860
912
|
}
|
|
861
913
|
}
|
|
862
914
|
}
|
|
863
|
-
for (const
|
|
864
|
-
|
|
915
|
+
for (const rawLocale of policy.requiredLocales ?? []) {
|
|
916
|
+
const locale = canonicalLocaleOrRaw(rawLocale);
|
|
917
|
+
if (!allowedLocales.has(locale)) {
|
|
865
918
|
issue(
|
|
866
919
|
issues,
|
|
867
920
|
"policy.requiredLocales",
|
|
@@ -874,7 +927,8 @@ function validatePolicy(schema, policy, issues) {
|
|
|
874
927
|
if (policy.maxLocales !== void 0 && collectedLocales.allUniqueLocales.size > policy.maxLocales) {
|
|
875
928
|
issue(issues, "supportedLocales", "max_locales_exceeded", `At most ${policy.maxLocales} locales are allowed.`);
|
|
876
929
|
}
|
|
877
|
-
for (const locale of policy.requiredLocales ?? [])
|
|
930
|
+
for (const locale of policy.requiredLocales ?? [])
|
|
931
|
+
addRequiredTranslationIssues(schema, canonicalLocaleOrRaw(locale), issues);
|
|
878
932
|
if (policy.maxSchemaBytes !== void 0) {
|
|
879
933
|
try {
|
|
880
934
|
const byteLength = new TextEncoder().encode(JSON.stringify(schema)).byteLength;
|
|
@@ -909,8 +963,12 @@ function validateFormSchema(input, options = {}) {
|
|
|
909
963
|
);
|
|
910
964
|
}
|
|
911
965
|
}
|
|
912
|
-
if (input.defaultLocale !== void 0
|
|
913
|
-
|
|
966
|
+
if (input.defaultLocale !== void 0) {
|
|
967
|
+
if (!isNonEmptyString(input.defaultLocale)) {
|
|
968
|
+
issue(issues, "defaultLocale", "invalid_locale", "Expected a non-empty default locale.");
|
|
969
|
+
} else if (normalizeLocale(input.defaultLocale) === null) {
|
|
970
|
+
issue(issues, "defaultLocale", "invalid_locale", "Expected a valid BCP 47 locale.");
|
|
971
|
+
}
|
|
914
972
|
}
|
|
915
973
|
if (input.supportedLocales !== void 0) {
|
|
916
974
|
if (!Array.isArray(input.supportedLocales) || input.supportedLocales.length === 0) {
|
|
@@ -920,10 +978,15 @@ function validateFormSchema(input, options = {}) {
|
|
|
920
978
|
input.supportedLocales.forEach((locale, index) => {
|
|
921
979
|
if (!isNonEmptyString(locale)) {
|
|
922
980
|
issue(issues, `supportedLocales[${index}]`, "invalid_locale", "Expected a non-empty locale.");
|
|
923
|
-
} else if (locales.has(locale)) {
|
|
924
|
-
issue(issues, `supportedLocales[${index}]`, "duplicate_locale", "Locales must be unique.");
|
|
925
981
|
} else {
|
|
926
|
-
|
|
982
|
+
const normalized = normalizeLocale(locale);
|
|
983
|
+
if (normalized === null) {
|
|
984
|
+
issue(issues, `supportedLocales[${index}]`, "invalid_locale", "Expected a valid BCP 47 locale.");
|
|
985
|
+
} else if (locales.has(normalized)) {
|
|
986
|
+
issue(issues, `supportedLocales[${index}]`, "duplicate_locale", "Locales must be unique.");
|
|
987
|
+
} else {
|
|
988
|
+
locales.add(normalized);
|
|
989
|
+
}
|
|
927
990
|
}
|
|
928
991
|
});
|
|
929
992
|
}
|
|
@@ -2192,8 +2255,15 @@ function withTranslationMetadata(node, locale, property, metadata) {
|
|
|
2192
2255
|
}
|
|
2193
2256
|
};
|
|
2194
2257
|
}
|
|
2195
|
-
function
|
|
2196
|
-
const
|
|
2258
|
+
function localeRecordEntry2(record, locale) {
|
|
2259
|
+
const normalizedLocale = normalizeLocale(locale) ?? locale;
|
|
2260
|
+
for (const [candidate, value] of Object.entries(record ?? {})) {
|
|
2261
|
+
if ((normalizeLocale(candidate) ?? candidate) === normalizedLocale) return value;
|
|
2262
|
+
}
|
|
2263
|
+
return void 0;
|
|
2264
|
+
}
|
|
2265
|
+
function createSlot(kind, nodeId, property, locale, sourceText, existingText, nodeMetadata, existingTranslationMetadata, options = {}, parentId) {
|
|
2266
|
+
const path = kind === "form" ? `form.${property}` : kind === "option" ? `fields.${parentId ?? ""}.options.${nodeId}.${property}` : `${kind}s.${nodeId}.${property}`;
|
|
2197
2267
|
const manual = options.isManualTranslation?.(existingTranslationMetadata, { path, locale }) ?? isManualTranslationMetadata(existingTranslationMetadata);
|
|
2198
2268
|
const normalizedMetadata = existingTranslationMetadata === void 0 ? void 0 : options.normalizeMetadata === void 0 ? existingTranslationMetadata : { ...options.normalizeMetadata(existingTranslationMetadata, sourceText) };
|
|
2199
2269
|
const status = getTranslationStatusWithManualOverride(sourceText, existingText, normalizedMetadata, manual);
|
|
@@ -2213,7 +2283,10 @@ function createSlot(kind, nodeId, property, locale, sourceText, existingText, no
|
|
|
2213
2283
|
};
|
|
2214
2284
|
}
|
|
2215
2285
|
function translationSlots(schema, locale, options = {}) {
|
|
2286
|
+
locale = normalizeLocale(locale) ?? locale;
|
|
2216
2287
|
const descriptors = [];
|
|
2288
|
+
const schemaTranslation = localeRecordEntry2(schema.translations, locale);
|
|
2289
|
+
const schemaTranslationMetadata = localeRecordEntry2(schema.translationMetadata, locale);
|
|
2217
2290
|
const addFormSlot = (property, sourceText) => {
|
|
2218
2291
|
const slot = createSlot(
|
|
2219
2292
|
"form",
|
|
@@ -2221,17 +2294,17 @@ function translationSlots(schema, locale, options = {}) {
|
|
|
2221
2294
|
property,
|
|
2222
2295
|
locale,
|
|
2223
2296
|
sourceText,
|
|
2224
|
-
|
|
2297
|
+
schemaTranslation?.[property],
|
|
2225
2298
|
schema.metadata,
|
|
2226
|
-
|
|
2299
|
+
schemaTranslationMetadata?.[property],
|
|
2227
2300
|
options
|
|
2228
2301
|
);
|
|
2229
2302
|
descriptors.push({
|
|
2230
2303
|
slot,
|
|
2231
|
-
manual: options.isManualTranslation?.(
|
|
2304
|
+
manual: options.isManualTranslation?.(schemaTranslationMetadata?.[property], {
|
|
2232
2305
|
path: slot.path ?? "",
|
|
2233
2306
|
locale
|
|
2234
|
-
}) ?? isManualTranslationMetadata(
|
|
2307
|
+
}) ?? isManualTranslationMetadata(schemaTranslationMetadata?.[property]),
|
|
2235
2308
|
apply: (current, value, metadata) => withTranslationMetadata(
|
|
2236
2309
|
{ ...current, translations: mergeLocalizedText(current.translations, locale, property, value) },
|
|
2237
2310
|
locale,
|
|
@@ -2244,6 +2317,8 @@ function translationSlots(schema, locale, options = {}) {
|
|
|
2244
2317
|
if (schema.description !== void 0) addFormSlot("description", schema.description);
|
|
2245
2318
|
if (schema.completionMessage !== void 0) addFormSlot("completionMessage", schema.completionMessage);
|
|
2246
2319
|
schema.fields.forEach((field, fieldIndex) => {
|
|
2320
|
+
const fieldTranslation = localeRecordEntry2(field.translations, locale);
|
|
2321
|
+
const fieldTranslationMetadata = localeRecordEntry2(field.translationMetadata, locale);
|
|
2247
2322
|
const addFieldSlot = (property, sourceText) => {
|
|
2248
2323
|
const slot = createSlot(
|
|
2249
2324
|
"field",
|
|
@@ -2251,17 +2326,17 @@ function translationSlots(schema, locale, options = {}) {
|
|
|
2251
2326
|
property,
|
|
2252
2327
|
locale,
|
|
2253
2328
|
sourceText,
|
|
2254
|
-
|
|
2329
|
+
fieldTranslation?.[property],
|
|
2255
2330
|
field.metadata,
|
|
2256
|
-
|
|
2331
|
+
fieldTranslationMetadata?.[property],
|
|
2257
2332
|
options
|
|
2258
2333
|
);
|
|
2259
2334
|
descriptors.push({
|
|
2260
2335
|
slot,
|
|
2261
|
-
manual: options.isManualTranslation?.(
|
|
2336
|
+
manual: options.isManualTranslation?.(fieldTranslationMetadata?.[property], {
|
|
2262
2337
|
path: slot.path ?? "",
|
|
2263
2338
|
locale
|
|
2264
|
-
}) ?? isManualTranslationMetadata(
|
|
2339
|
+
}) ?? isManualTranslationMetadata(fieldTranslationMetadata?.[property]),
|
|
2265
2340
|
apply: (current, value, metadata) => ({
|
|
2266
2341
|
...current,
|
|
2267
2342
|
fields: current.fields.map(
|
|
@@ -2282,23 +2357,26 @@ function translationSlots(schema, locale, options = {}) {
|
|
|
2282
2357
|
if (field.description !== void 0) addFieldSlot("description", field.description);
|
|
2283
2358
|
if ("options" in field) {
|
|
2284
2359
|
field.options.forEach((option, optionIndex) => {
|
|
2360
|
+
const optionTranslation = localeRecordEntry2(option.translations, locale);
|
|
2361
|
+
const optionTranslationMetadata = localeRecordEntry2(option.translationMetadata, locale);
|
|
2285
2362
|
const slot = createSlot(
|
|
2286
2363
|
"option",
|
|
2287
2364
|
option.id,
|
|
2288
2365
|
"label",
|
|
2289
2366
|
locale,
|
|
2290
2367
|
option.label,
|
|
2291
|
-
|
|
2368
|
+
optionTranslation,
|
|
2292
2369
|
option.metadata,
|
|
2293
|
-
|
|
2294
|
-
options
|
|
2370
|
+
optionTranslationMetadata?.label,
|
|
2371
|
+
options,
|
|
2372
|
+
field.id
|
|
2295
2373
|
);
|
|
2296
2374
|
descriptors.push({
|
|
2297
2375
|
slot,
|
|
2298
|
-
manual: options.isManualTranslation?.(
|
|
2376
|
+
manual: options.isManualTranslation?.(optionTranslationMetadata?.label, {
|
|
2299
2377
|
path: slot.path ?? "",
|
|
2300
2378
|
locale
|
|
2301
|
-
}) ?? isManualTranslationMetadata(
|
|
2379
|
+
}) ?? isManualTranslationMetadata(optionTranslationMetadata?.label),
|
|
2302
2380
|
apply: (current, value, metadata) => ({
|
|
2303
2381
|
...current,
|
|
2304
2382
|
fields: current.fields.map((candidate, candidateIndex) => {
|
|
@@ -2324,6 +2402,8 @@ function translationSlots(schema, locale, options = {}) {
|
|
|
2324
2402
|
}
|
|
2325
2403
|
});
|
|
2326
2404
|
schema.pages?.forEach((page, pageIndex) => {
|
|
2405
|
+
const pageTranslation = localeRecordEntry2(page.translations, locale);
|
|
2406
|
+
const pageTranslationMetadata = localeRecordEntry2(page.translationMetadata, locale);
|
|
2327
2407
|
const addPageSlot = (property, sourceText) => {
|
|
2328
2408
|
const slot = createSlot(
|
|
2329
2409
|
"page",
|
|
@@ -2331,17 +2411,17 @@ function translationSlots(schema, locale, options = {}) {
|
|
|
2331
2411
|
property,
|
|
2332
2412
|
locale,
|
|
2333
2413
|
sourceText,
|
|
2334
|
-
|
|
2414
|
+
pageTranslation?.[property],
|
|
2335
2415
|
page.metadata,
|
|
2336
|
-
|
|
2416
|
+
pageTranslationMetadata?.[property],
|
|
2337
2417
|
options
|
|
2338
2418
|
);
|
|
2339
2419
|
descriptors.push({
|
|
2340
2420
|
slot,
|
|
2341
|
-
manual: options.isManualTranslation?.(
|
|
2421
|
+
manual: options.isManualTranslation?.(pageTranslationMetadata?.[property], {
|
|
2342
2422
|
path: slot.path ?? "",
|
|
2343
2423
|
locale
|
|
2344
|
-
}) ?? isManualTranslationMetadata(
|
|
2424
|
+
}) ?? isManualTranslationMetadata(pageTranslationMetadata?.[property]),
|
|
2345
2425
|
apply: (current, value, metadata) => ({
|
|
2346
2426
|
...current,
|
|
2347
2427
|
...current.pages === void 0 ? {} : {
|
|
@@ -2380,10 +2460,9 @@ function removeLocalizedNodeLocale(node, locale) {
|
|
|
2380
2460
|
...translationMetadata === void 0 ? {} : { translationMetadata }
|
|
2381
2461
|
};
|
|
2382
2462
|
}
|
|
2383
|
-
function
|
|
2384
|
-
if (customMigrator !== void 0) return customMigrator(metadata, sourceText);
|
|
2463
|
+
function defaultTranslationMetadataMigrator(metadata, sourceText, defaultLocale) {
|
|
2385
2464
|
const record = metadata !== null && typeof metadata === "object" ? metadata : void 0;
|
|
2386
|
-
const sourceLocale = typeof record?.sourceLocale === "string" ? record.sourceLocale : defaultLocale
|
|
2465
|
+
const sourceLocale = typeof record?.sourceLocale === "string" ? record.sourceLocale : defaultLocale;
|
|
2387
2466
|
const translationSource = isManualTranslationMetadata(record) ? "manual" : "automatic";
|
|
2388
2467
|
return {
|
|
2389
2468
|
sourceLocale,
|
|
@@ -2393,22 +2472,33 @@ function migrateMetadata(metadata, sourceText, defaultLocale, customMigrator) {
|
|
|
2393
2472
|
...typeof record?.editedAt === "string" ? { editedAt: record.editedAt } : {}
|
|
2394
2473
|
};
|
|
2395
2474
|
}
|
|
2396
|
-
function
|
|
2475
|
+
function migrateMetadata(metadata, sourceText, context, migrator) {
|
|
2476
|
+
return migrator(metadata, sourceText, context);
|
|
2477
|
+
}
|
|
2478
|
+
function isTranslationMetadataProperty(property) {
|
|
2479
|
+
return property === "title" || property === "description" || property === "label" || property === "completionMessage";
|
|
2480
|
+
}
|
|
2481
|
+
function migrateNodeMetadata(node, sourceTexts, contextFor, migrator) {
|
|
2397
2482
|
if (node.translationMetadata === void 0) return node;
|
|
2398
2483
|
const translationMetadata = Object.fromEntries(
|
|
2399
2484
|
Object.entries(node.translationMetadata).map(([locale, properties]) => [
|
|
2400
2485
|
locale,
|
|
2401
2486
|
Object.fromEntries(
|
|
2402
|
-
Object.entries(properties).map(([property, metadata]) =>
|
|
2403
|
-
property,
|
|
2404
|
-
|
|
2405
|
-
|
|
2487
|
+
Object.entries(properties).map(([property, metadata]) => {
|
|
2488
|
+
if (!isTranslationMetadataProperty(property)) return [property, metadata];
|
|
2489
|
+
return [
|
|
2490
|
+
property,
|
|
2491
|
+
migrateMetadata(metadata, sourceTexts[property] ?? "", contextFor(locale, property), migrator)
|
|
2492
|
+
];
|
|
2493
|
+
})
|
|
2406
2494
|
)
|
|
2407
2495
|
])
|
|
2408
2496
|
);
|
|
2409
2497
|
return { ...node, translationMetadata };
|
|
2410
2498
|
}
|
|
2411
|
-
var migrateSchemaTranslationMetadata = (schema,
|
|
2499
|
+
var migrateSchemaTranslationMetadata = (schema, migratorOrOptions) => {
|
|
2500
|
+
const defaultLocale = schema.defaultLocale ?? "";
|
|
2501
|
+
const migrator = typeof migratorOrOptions === "function" ? migratorOrOptions : migratorOrOptions?.migrator ?? ((metadata, sourceText, context) => defaultTranslationMetadataMigrator(metadata, sourceText, context.defaultLocale));
|
|
2412
2502
|
const migratedSchema = migrateNodeMetadata(
|
|
2413
2503
|
schema,
|
|
2414
2504
|
{
|
|
@@ -2416,21 +2506,47 @@ var migrateSchemaTranslationMetadata = (schema, customMigrator) => {
|
|
|
2416
2506
|
...schema.description === void 0 ? {} : { description: schema.description },
|
|
2417
2507
|
...schema.completionMessage === void 0 ? {} : { completionMessage: schema.completionMessage }
|
|
2418
2508
|
},
|
|
2419
|
-
|
|
2420
|
-
|
|
2509
|
+
(locale, property) => ({
|
|
2510
|
+
locale,
|
|
2511
|
+
defaultLocale,
|
|
2512
|
+
path: `form.${property}`,
|
|
2513
|
+
property,
|
|
2514
|
+
nodeKind: "form"
|
|
2515
|
+
}),
|
|
2516
|
+
migrator
|
|
2421
2517
|
);
|
|
2422
2518
|
const fields = schema.fields.map((field) => {
|
|
2423
2519
|
const migratedField = migrateNodeMetadata(
|
|
2424
2520
|
field,
|
|
2425
2521
|
{ title: field.title, ...field.description === void 0 ? {} : { description: field.description } },
|
|
2426
|
-
|
|
2427
|
-
|
|
2522
|
+
(locale, property) => ({
|
|
2523
|
+
locale,
|
|
2524
|
+
defaultLocale,
|
|
2525
|
+
path: `fields.${field.id}.${property}`,
|
|
2526
|
+
property,
|
|
2527
|
+
nodeKind: "field",
|
|
2528
|
+
nodeId: field.id
|
|
2529
|
+
}),
|
|
2530
|
+
migrator
|
|
2428
2531
|
);
|
|
2429
2532
|
if (!("options" in migratedField)) return migratedField;
|
|
2430
2533
|
return {
|
|
2431
2534
|
...migratedField,
|
|
2432
2535
|
options: migratedField.options.map(
|
|
2433
|
-
(option) => migrateNodeMetadata(
|
|
2536
|
+
(option) => migrateNodeMetadata(
|
|
2537
|
+
option,
|
|
2538
|
+
{ label: option.label },
|
|
2539
|
+
(locale, property) => ({
|
|
2540
|
+
locale,
|
|
2541
|
+
defaultLocale,
|
|
2542
|
+
path: `fields.${field.id}.options.${option.id}.${property}`,
|
|
2543
|
+
property,
|
|
2544
|
+
nodeKind: "option",
|
|
2545
|
+
nodeId: option.id,
|
|
2546
|
+
parentId: field.id
|
|
2547
|
+
}),
|
|
2548
|
+
migrator
|
|
2549
|
+
)
|
|
2434
2550
|
)
|
|
2435
2551
|
};
|
|
2436
2552
|
});
|
|
@@ -2441,8 +2557,15 @@ var migrateSchemaTranslationMetadata = (schema, customMigrator) => {
|
|
|
2441
2557
|
...page.title === void 0 ? {} : { title: page.title },
|
|
2442
2558
|
...page.description === void 0 ? {} : { description: page.description }
|
|
2443
2559
|
},
|
|
2444
|
-
|
|
2445
|
-
|
|
2560
|
+
(locale, property) => ({
|
|
2561
|
+
locale,
|
|
2562
|
+
defaultLocale,
|
|
2563
|
+
path: `pages.${page.id}.${property}`,
|
|
2564
|
+
property,
|
|
2565
|
+
nodeKind: "page",
|
|
2566
|
+
nodeId: page.id
|
|
2567
|
+
}),
|
|
2568
|
+
migrator
|
|
2446
2569
|
)
|
|
2447
2570
|
);
|
|
2448
2571
|
return {
|
|
@@ -2485,8 +2608,11 @@ function collectTranslationSlots(schema, locale) {
|
|
|
2485
2608
|
return translationSlots(schema, locale).map((descriptor) => descriptor.slot);
|
|
2486
2609
|
}
|
|
2487
2610
|
function resolveLocalizedSchema(schema, targetLocale) {
|
|
2488
|
-
if (targetLocale === void 0 || targetLocale.length === 0
|
|
2489
|
-
const
|
|
2611
|
+
if (targetLocale === void 0 || targetLocale.length === 0) return schema;
|
|
2612
|
+
const normalizedTargetLocale = normalizeLocale(targetLocale) ?? targetLocale;
|
|
2613
|
+
const defaultLocale = schema.defaultLocale === void 0 ? void 0 : normalizeLocale(schema.defaultLocale);
|
|
2614
|
+
if (normalizedTargetLocale === defaultLocale || targetLocale === schema.defaultLocale) return schema;
|
|
2615
|
+
const formTranslation = localeRecordEntry2(schema.translations, normalizedTargetLocale);
|
|
2490
2616
|
const completionMessage = formTranslation?.completionMessage ?? schema.completionMessage;
|
|
2491
2617
|
return {
|
|
2492
2618
|
...schema,
|
|
@@ -2494,7 +2620,7 @@ function resolveLocalizedSchema(schema, targetLocale) {
|
|
|
2494
2620
|
...(formTranslation?.description ?? schema.description) === void 0 ? {} : { description: formTranslation?.description ?? schema.description },
|
|
2495
2621
|
...completionMessage === void 0 ? {} : { completionMessage },
|
|
2496
2622
|
fields: schema.fields.map((field) => {
|
|
2497
|
-
const translation = field.translations
|
|
2623
|
+
const translation = localeRecordEntry2(field.translations, normalizedTargetLocale);
|
|
2498
2624
|
const localized = {
|
|
2499
2625
|
...field,
|
|
2500
2626
|
title: translation?.title ?? field.title,
|
|
@@ -2505,13 +2631,13 @@ function resolveLocalizedSchema(schema, targetLocale) {
|
|
|
2505
2631
|
...localized,
|
|
2506
2632
|
options: field.options.map((option) => ({
|
|
2507
2633
|
...option,
|
|
2508
|
-
label: option.translations
|
|
2634
|
+
label: localeRecordEntry2(option.translations, normalizedTargetLocale) ?? option.label
|
|
2509
2635
|
}))
|
|
2510
2636
|
};
|
|
2511
2637
|
}),
|
|
2512
2638
|
...schema.pages === void 0 ? {} : {
|
|
2513
2639
|
pages: schema.pages.map((page) => {
|
|
2514
|
-
const translation = page.translations
|
|
2640
|
+
const translation = localeRecordEntry2(page.translations, normalizedTargetLocale);
|
|
2515
2641
|
const title = translation?.title ?? page.title;
|
|
2516
2642
|
const description = translation?.description ?? page.description;
|
|
2517
2643
|
return {
|
|
@@ -2525,8 +2651,13 @@ function resolveLocalizedSchema(schema, targetLocale) {
|
|
|
2525
2651
|
}
|
|
2526
2652
|
async function populateSchemaTranslations(schema, targetLocales, adapter, options = {}) {
|
|
2527
2653
|
assertValidFormSchema(schema);
|
|
2528
|
-
const
|
|
2529
|
-
const
|
|
2654
|
+
const defaultLocale = schema.defaultLocale === void 0 ? void 0 : normalizeLocale(schema.defaultLocale) ?? schema.defaultLocale;
|
|
2655
|
+
const locales = [
|
|
2656
|
+
...new Set(
|
|
2657
|
+
targetLocales.map((locale) => normalizeLocale(locale) ?? locale.trim()).filter((locale) => locale.length > 0 && locale !== defaultLocale)
|
|
2658
|
+
)
|
|
2659
|
+
];
|
|
2660
|
+
const allowedLocales = options.policy?.allowedLocales?.map((locale) => normalizeLocale(locale) ?? locale);
|
|
2530
2661
|
const collectedLocales = collectSchemaLocales(schema);
|
|
2531
2662
|
const disallowedLocale = [...collectedLocales.allUniqueLocales, ...locales].find(
|
|
2532
2663
|
(locale) => allowedLocales !== void 0 && !allowedLocales.includes(locale)
|
|
@@ -2568,7 +2699,7 @@ async function populateSchemaTranslations(schema, targetLocales, adapter, option
|
|
|
2568
2699
|
adapter,
|
|
2569
2700
|
selected.map((descriptor) => descriptor.slot.sourceText),
|
|
2570
2701
|
locale,
|
|
2571
|
-
|
|
2702
|
+
defaultLocale
|
|
2572
2703
|
);
|
|
2573
2704
|
if (translated.length !== selected.length) {
|
|
2574
2705
|
throw new Error(`Translation adapter returned ${translated.length} texts for ${selected.length} inputs.`);
|
|
@@ -2577,7 +2708,7 @@ async function populateSchemaTranslations(schema, targetLocales, adapter, option
|
|
|
2577
2708
|
const translatedText = translated[index];
|
|
2578
2709
|
if (translatedText === void 0) throw new Error("Translation adapter returned an unexpected result.");
|
|
2579
2710
|
const metadata = options.createMetadata?.(descriptor.slot, translatedText) ?? {
|
|
2580
|
-
sourceLocale:
|
|
2711
|
+
sourceLocale: defaultLocale ?? "",
|
|
2581
2712
|
sourceTextHash: computeSourceTextHash(descriptor.slot.sourceText),
|
|
2582
2713
|
translationSource: "automatic",
|
|
2583
2714
|
translatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
@@ -2588,8 +2719,8 @@ async function populateSchemaTranslations(schema, targetLocales, adapter, option
|
|
|
2588
2719
|
}
|
|
2589
2720
|
const supportedLocales = [
|
|
2590
2721
|
.../* @__PURE__ */ new Set([
|
|
2591
|
-
...
|
|
2592
|
-
...schema.supportedLocales ?? [],
|
|
2722
|
+
...defaultLocale === void 0 ? [] : [defaultLocale],
|
|
2723
|
+
...(schema.supportedLocales ?? []).map((locale) => normalizeLocale(locale) ?? locale),
|
|
2593
2724
|
...locales
|
|
2594
2725
|
])
|
|
2595
2726
|
];
|
|
@@ -2924,6 +3055,7 @@ export {
|
|
|
2924
3055
|
matchesSubmissionFilter,
|
|
2925
3056
|
matchesSubmissionPageFilters,
|
|
2926
3057
|
migrateSchemaTranslationMetadata,
|
|
3058
|
+
normalizeLocale,
|
|
2927
3059
|
normalizeSubmissionPageSize,
|
|
2928
3060
|
pipeResponsesToCsvStream,
|
|
2929
3061
|
populateSchemaTranslations,
|