@form-engine-ts/core 4.7.0 → 5.0.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/dist/index.cjs CHANGED
@@ -21,7 +21,10 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
21
21
  var index_exports = {};
22
22
  __export(index_exports, {
23
23
  DEFAULT_FIELD_TYPE_DEFINITIONS: () => DEFAULT_FIELD_TYPE_DEFINITIONS,
24
+ EN_MESSAGES: () => EN_MESSAGES,
25
+ JA_MESSAGES: () => JA_MESSAGES,
24
26
  aggregateResponses: () => aggregateResponses,
27
+ applyTransitionPlan: () => applyTransitionPlan,
25
28
  assertValidFormSchema: () => assertValidFormSchema,
26
29
  assertVersionMutable: () => assertVersionMutable,
27
30
  calculateChoiceDistribution: () => calculateChoiceDistribution,
@@ -32,16 +35,22 @@ __export(index_exports, {
32
35
  cloneVersionToDraft: () => cloneVersionToDraft,
33
36
  collectSchemaLocales: () => collectSchemaLocales,
34
37
  collectTranslationSlots: () => collectTranslationSlots,
38
+ commitVersionTransition: () => commitVersionTransition,
35
39
  computeSourceTextHash: () => computeSourceTextHash,
36
40
  createCloneTransitionPlan: () => createCloneTransitionPlan,
37
41
  createDeleteDraftTransitionPlan: () => createDeleteDraftTransitionPlan,
42
+ createFormEngineTranslator: () => createFormEngineTranslator,
38
43
  createPublishTransitionPlan: () => createPublishTransitionPlan,
39
44
  createResponseAccumulator: () => createResponseAccumulator,
40
45
  createSubmission: () => createSubmission,
46
+ decodeStorageSubmissionCursor: () => decodeStorageSubmissionCursor,
47
+ decodeStorageTextAnswerCursor: () => decodeStorageTextAnswerCursor,
41
48
  decodeSubmissionCursor: () => decodeSubmissionCursor,
42
49
  decodeTextAnswerCursor: () => decodeTextAnswerCursor,
43
50
  deleteDraft: () => deleteDraft,
44
51
  dispatchWebhook: () => dispatchWebhook,
52
+ encodeStorageSubmissionCursor: () => encodeStorageSubmissionCursor,
53
+ encodeStorageTextAnswerCursor: () => encodeStorageTextAnswerCursor,
45
54
  encodeSubmissionCursor: () => encodeSubmissionCursor,
46
55
  encodeTextAnswerCursor: () => encodeTextAnswerCursor,
47
56
  escapeCsvCell: () => escapeCsvCell,
@@ -57,7 +66,9 @@ __export(index_exports, {
57
66
  matchesSubmissionFilter: () => matchesSubmissionFilter,
58
67
  matchesSubmissionPageFilters: () => matchesSubmissionPageFilters,
59
68
  migrateSchemaTranslationMetadata: () => migrateSchemaTranslationMetadata,
69
+ normalizeLocale: () => normalizeLocale,
60
70
  normalizeSubmissionPageSize: () => normalizeSubmissionPageSize,
71
+ paginateWithFilter: () => paginateWithFilter,
61
72
  pipeResponsesToCsvStream: () => pipeResponsesToCsvStream,
62
73
  populateSchemaTranslations: () => populateSchemaTranslations,
63
74
  publishDraft: () => publishDraft,
@@ -70,15 +81,32 @@ __export(index_exports, {
70
81
  validateAnswers: () => validateAnswers,
71
82
  validateFormSchema: () => validateFormSchema,
72
83
  validatePageAnswers: () => validatePageAnswers,
73
- validateSchemaStructure: () => validateSchemaStructure
84
+ validateSchemaStructure: () => validateSchemaStructure,
85
+ validateSubmission: () => validateSubmission
74
86
  });
75
87
  module.exports = __toCommonJS(index_exports);
76
88
 
89
+ // src/locale.ts
90
+ var normalizeLocale = (rawLocale) => {
91
+ if (!rawLocale || typeof rawLocale !== "string") return null;
92
+ const trimmed = rawLocale.trim().replace(/_/gu, "-");
93
+ if (trimmed.length === 0) return null;
94
+ try {
95
+ return Intl.getCanonicalLocales(trimmed)[0] ?? null;
96
+ } catch {
97
+ return null;
98
+ }
99
+ };
100
+ function canonicalLocaleOrRaw(rawLocale) {
101
+ return normalizeLocale(rawLocale) ?? rawLocale;
102
+ }
103
+
77
104
  // src/policy.ts
78
105
  function collectRecordKeys(value, path, pathsByLocale) {
79
- for (const locale of Object.keys(value ?? {})) {
106
+ for (const rawLocale of Object.keys(value ?? {})) {
107
+ const locale = canonicalLocaleOrRaw(rawLocale);
80
108
  const paths = pathsByLocale.get(locale) ?? [];
81
- paths.push(`${path}.${locale}`);
109
+ paths.push(`${path}.${rawLocale}`);
82
110
  pathsByLocale.set(locale, paths);
83
111
  }
84
112
  }
@@ -109,13 +137,15 @@ function collectSchemaLocales(schema) {
109
137
  });
110
138
  const translationLocales = new Set(pathsByLocale.keys());
111
139
  const allUniqueLocales = /* @__PURE__ */ new Set([
112
- ...schema.defaultLocale === void 0 ? [] : [schema.defaultLocale],
113
- ...schema.supportedLocales ?? [],
140
+ ...schema.defaultLocale === void 0 ? [] : [canonicalLocaleOrRaw(schema.defaultLocale)],
141
+ ...(schema.supportedLocales ?? []).map(canonicalLocaleOrRaw),
114
142
  ...translationLocales
115
143
  ]);
144
+ const defaultLocale = schema.defaultLocale === void 0 ? void 0 : canonicalLocaleOrRaw(schema.defaultLocale);
145
+ const supportedLocales = (schema.supportedLocales ?? []).map(canonicalLocaleOrRaw);
116
146
  return {
117
- ...schema.defaultLocale === void 0 ? {} : { defaultLocale: schema.defaultLocale },
118
- supportedLocales: schema.supportedLocales ?? [],
147
+ ...defaultLocale === void 0 ? {} : { defaultLocale },
148
+ supportedLocales,
119
149
  translationLocales,
120
150
  allUniqueLocales,
121
151
  translationLocalePaths: pathsByLocale
@@ -138,7 +168,12 @@ function displayRuleSourceIds(field) {
138
168
  }
139
169
  function registeredEntries(value, registeredLocales) {
140
170
  if (value === void 0) return void 0;
141
- const entries = Object.entries(value).filter(([locale]) => registeredLocales.has(locale));
171
+ const entries = [];
172
+ for (const [rawLocale, entry] of Object.entries(value)) {
173
+ const locale = normalizeLocale(rawLocale);
174
+ if (locale === null || !registeredLocales.has(locale)) continue;
175
+ entries.push([locale, entry]);
176
+ }
142
177
  return entries.length === 0 ? void 0 : Object.fromEntries(entries);
143
178
  }
144
179
  function sanitizeNodeLocales(node, registeredLocales) {
@@ -176,6 +211,16 @@ function sanitizePageLocales(page, registeredLocales) {
176
211
  const translations = registeredEntries(page.translations, registeredLocales);
177
212
  return { ...base, ...translations === void 0 ? {} : { translations } };
178
213
  }
214
+ function normalizedLocaleList(locales) {
215
+ return [
216
+ ...new Set(
217
+ locales.flatMap((locale) => {
218
+ const normalized = normalizeLocale(locale);
219
+ return normalized === null ? [] : [normalized];
220
+ })
221
+ )
222
+ ];
223
+ }
179
224
  function sanitizeFieldConstraints(field, policy) {
180
225
  const constraint = policy?.fieldConstraints?.[field.type];
181
226
  if (constraint === void 0) return field;
@@ -290,10 +335,9 @@ function validateSchemaStructure(schema) {
290
335
  }
291
336
  function sanitizeSchema(schema, options = {}) {
292
337
  const existingQuestionIds = new Set(schema.fields.map((field) => field.id));
293
- const registeredLocales = /* @__PURE__ */ new Set([
294
- ...schema.defaultLocale === void 0 ? [] : [schema.defaultLocale],
295
- ...schema.supportedLocales ?? []
296
- ]);
338
+ const defaultLocale = schema.defaultLocale === void 0 ? null : normalizeLocale(schema.defaultLocale);
339
+ const supportedLocales = schema.supportedLocales === void 0 ? void 0 : normalizedLocaleList(schema.supportedLocales);
340
+ const registeredLocales = /* @__PURE__ */ new Set([...defaultLocale === null ? [] : [defaultLocale], ...supportedLocales ?? []]);
297
341
  const cyclic = cyclicQuestionIds(schema.fields);
298
342
  const sanitizedFields = schema.fields.map((sourceField) => {
299
343
  const field = sanitizeFieldConstraints(sanitizeFieldLocales(sourceField, registeredLocales), options.policy);
@@ -311,10 +355,17 @@ function sanitizeSchema(schema, options = {}) {
311
355
  return sanitized;
312
356
  });
313
357
  const localizedSchema = sanitizeNodeLocales(schema, registeredLocales);
314
- const { translations: _translations, ...schemaWithoutLocaleContent } = localizedSchema;
358
+ const {
359
+ defaultLocale: _defaultLocale,
360
+ supportedLocales: _supportedLocales,
361
+ translations: _translations,
362
+ ...schemaWithoutLocaleContent
363
+ } = localizedSchema;
315
364
  const translations = registeredEntries(schema.translations, registeredLocales);
316
365
  const base = {
317
366
  ...schemaWithoutLocaleContent,
367
+ ...defaultLocale === null ? {} : { defaultLocale },
368
+ ...supportedLocales === void 0 ? {} : { supportedLocales },
318
369
  ...translations === void 0 ? {} : { translations },
319
370
  fields: sanitizedFields
320
371
  };
@@ -367,6 +418,12 @@ function isRecord(value) {
367
418
  function isNonEmptyString(value) {
368
419
  return typeof value === "string" && value.trim().length > 0;
369
420
  }
421
+ function localeRecordEntry(record, locale) {
422
+ for (const [candidate, value] of Object.entries(record ?? {})) {
423
+ if (canonicalLocaleOrRaw(candidate) === locale) return value;
424
+ }
425
+ return void 0;
426
+ }
370
427
  function issue(issues, path, code, message) {
371
428
  issues.push({ path, code, message });
372
429
  }
@@ -729,51 +786,55 @@ function collectSchemaText(schema) {
729
786
  return entries;
730
787
  }
731
788
  function addRequiredTranslationIssues(schema, locale, issues) {
732
- if (!(schema.supportedLocales ?? []).includes(locale)) {
789
+ if (!(schema.supportedLocales ?? []).some((candidate) => canonicalLocaleOrRaw(candidate) === locale)) {
733
790
  issue(issues, "supportedLocales", "required_locale_missing", `Required locale ${locale} is missing.`);
734
791
  }
735
- if (locale === schema.defaultLocale) return;
792
+ if (schema.defaultLocale !== void 0 && canonicalLocaleOrRaw(schema.defaultLocale) === locale) return;
793
+ const formTranslation = localeRecordEntry(schema.translations, locale);
736
794
  const required = [
737
- { path: `translations.${locale}.title`, value: schema.translations?.[locale]?.title }
795
+ { path: `translations.${locale}.title`, value: formTranslation?.title }
738
796
  ];
739
797
  if (schema.description !== void 0)
740
- required.push({ path: `translations.${locale}.description`, value: schema.translations?.[locale]?.description });
798
+ required.push({ path: `translations.${locale}.description`, value: formTranslation?.description });
741
799
  if (schema.completionMessage !== void 0) {
742
800
  required.push({
743
801
  path: `translations.${locale}.completionMessage`,
744
- value: schema.translations?.[locale]?.completionMessage
802
+ value: formTranslation?.completionMessage
745
803
  });
746
804
  }
747
805
  schema.fields.forEach((field, fieldIndex) => {
806
+ const fieldTranslation = localeRecordEntry(field.translations, locale);
748
807
  required.push({
749
808
  path: `fields[${fieldIndex}].translations.${locale}.title`,
750
- value: field.translations?.[locale]?.title
809
+ value: fieldTranslation?.title
751
810
  });
752
811
  if (field.description !== void 0) {
753
812
  required.push({
754
813
  path: `fields[${fieldIndex}].translations.${locale}.description`,
755
- value: field.translations?.[locale]?.description
814
+ value: fieldTranslation?.description
756
815
  });
757
816
  }
758
817
  if (!("options" in field)) return;
759
818
  field.options.forEach((option, optionIndex) => {
819
+ const optionTranslation = localeRecordEntry(option.translations, locale);
760
820
  required.push({
761
821
  path: `fields[${fieldIndex}].options[${optionIndex}].translations.${locale}`,
762
- value: option.translations?.[locale]
822
+ value: optionTranslation
763
823
  });
764
824
  });
765
825
  });
766
826
  schema.pages?.forEach((page, pageIndex) => {
827
+ const pageTranslation = localeRecordEntry(page.translations, locale);
767
828
  if (page.title !== void 0) {
768
829
  required.push({
769
830
  path: `pages[${pageIndex}].translations.${locale}.title`,
770
- value: page.translations?.[locale]?.title
831
+ value: pageTranslation?.title
771
832
  });
772
833
  }
773
834
  if (page.description !== void 0) {
774
835
  required.push({
775
836
  path: `pages[${pageIndex}].translations.${locale}.description`,
776
- value: page.translations?.[locale]?.description
837
+ value: pageTranslation?.description
777
838
  });
778
839
  }
779
840
  });
@@ -906,8 +967,8 @@ function validatePolicy(schema, policy, issues) {
906
967
  }
907
968
  const collectedLocales = collectSchemaLocales(schema);
908
969
  const registeredLocales = /* @__PURE__ */ new Set([
909
- ...schema.defaultLocale === void 0 ? [] : [schema.defaultLocale],
910
- ...schema.supportedLocales ?? []
970
+ ...collectedLocales.defaultLocale === void 0 ? [] : [collectedLocales.defaultLocale],
971
+ ...collectedLocales.supportedLocales
911
972
  ]);
912
973
  for (const locale of collectedLocales.translationLocales) {
913
974
  if (registeredLocales.has(locale)) continue;
@@ -921,23 +982,27 @@ function validatePolicy(schema, policy, issues) {
921
982
  }
922
983
  }
923
984
  if (policy.allowedLocales !== void 0) {
985
+ const allowedLocales = new Set(policy.allowedLocales.map(canonicalLocaleOrRaw));
924
986
  const pathsByLocale = /* @__PURE__ */ new Map();
925
- if (schema.defaultLocale !== void 0) pathsByLocale.set(schema.defaultLocale, ["defaultLocale"]);
987
+ if (collectedLocales.defaultLocale !== void 0)
988
+ pathsByLocale.set(collectedLocales.defaultLocale, ["defaultLocale"]);
926
989
  schema.supportedLocales?.forEach((locale, index) => {
927
- pathsByLocale.set(locale, [...pathsByLocale.get(locale) ?? [], `supportedLocales[${index}]`]);
990
+ const canonical = canonicalLocaleOrRaw(locale);
991
+ pathsByLocale.set(canonical, [...pathsByLocale.get(canonical) ?? [], `supportedLocales[${index}]`]);
928
992
  });
929
993
  for (const [locale, paths] of collectedLocales.translationLocalePaths) {
930
994
  pathsByLocale.set(locale, [...pathsByLocale.get(locale) ?? [], ...paths]);
931
995
  }
932
996
  for (const [locale, paths] of pathsByLocale) {
933
- if (!policy.allowedLocales.includes(locale)) {
997
+ if (!allowedLocales.has(locale)) {
934
998
  for (const path of paths) {
935
999
  issue(issues, path, "disallowed_locale", `Locale ${locale} is not allowed by the form policy.`);
936
1000
  }
937
1001
  }
938
1002
  }
939
- for (const locale of policy.requiredLocales ?? []) {
940
- if (!policy.allowedLocales.includes(locale)) {
1003
+ for (const rawLocale of policy.requiredLocales ?? []) {
1004
+ const locale = canonicalLocaleOrRaw(rawLocale);
1005
+ if (!allowedLocales.has(locale)) {
941
1006
  issue(
942
1007
  issues,
943
1008
  "policy.requiredLocales",
@@ -950,7 +1015,8 @@ function validatePolicy(schema, policy, issues) {
950
1015
  if (policy.maxLocales !== void 0 && collectedLocales.allUniqueLocales.size > policy.maxLocales) {
951
1016
  issue(issues, "supportedLocales", "max_locales_exceeded", `At most ${policy.maxLocales} locales are allowed.`);
952
1017
  }
953
- for (const locale of policy.requiredLocales ?? []) addRequiredTranslationIssues(schema, locale, issues);
1018
+ for (const locale of policy.requiredLocales ?? [])
1019
+ addRequiredTranslationIssues(schema, canonicalLocaleOrRaw(locale), issues);
954
1020
  if (policy.maxSchemaBytes !== void 0) {
955
1021
  try {
956
1022
  const byteLength = new TextEncoder().encode(JSON.stringify(schema)).byteLength;
@@ -985,8 +1051,12 @@ function validateFormSchema(input, options = {}) {
985
1051
  );
986
1052
  }
987
1053
  }
988
- if (input.defaultLocale !== void 0 && !isNonEmptyString(input.defaultLocale)) {
989
- issue(issues, "defaultLocale", "invalid_locale", "Expected a non-empty default locale.");
1054
+ if (input.defaultLocale !== void 0) {
1055
+ if (!isNonEmptyString(input.defaultLocale)) {
1056
+ issue(issues, "defaultLocale", "invalid_locale", "Expected a non-empty default locale.");
1057
+ } else if (normalizeLocale(input.defaultLocale) === null) {
1058
+ issue(issues, "defaultLocale", "invalid_locale", "Expected a valid BCP 47 locale.");
1059
+ }
990
1060
  }
991
1061
  if (input.supportedLocales !== void 0) {
992
1062
  if (!Array.isArray(input.supportedLocales) || input.supportedLocales.length === 0) {
@@ -996,10 +1066,15 @@ function validateFormSchema(input, options = {}) {
996
1066
  input.supportedLocales.forEach((locale, index) => {
997
1067
  if (!isNonEmptyString(locale)) {
998
1068
  issue(issues, `supportedLocales[${index}]`, "invalid_locale", "Expected a non-empty locale.");
999
- } else if (locales.has(locale)) {
1000
- issue(issues, `supportedLocales[${index}]`, "duplicate_locale", "Locales must be unique.");
1001
1069
  } else {
1002
- locales.add(locale);
1070
+ const normalized = normalizeLocale(locale);
1071
+ if (normalized === null) {
1072
+ issue(issues, `supportedLocales[${index}]`, "invalid_locale", "Expected a valid BCP 47 locale.");
1073
+ } else if (locales.has(normalized)) {
1074
+ issue(issues, `supportedLocales[${index}]`, "duplicate_locale", "Locales must be unique.");
1075
+ } else {
1076
+ locales.add(normalized);
1077
+ }
1003
1078
  }
1004
1079
  });
1005
1080
  }
@@ -1869,7 +1944,408 @@ var DEFAULT_FIELD_TYPE_DEFINITIONS = [
1869
1944
  }
1870
1945
  ];
1871
1946
 
1947
+ // src/i18n/catalogs/en.ts
1948
+ var EN_MESSAGES = Object.freeze({
1949
+ "builder.formTitle": "Form title",
1950
+ "builder.formDescription": "Form description",
1951
+ "builder.completionMessage": "Completion message",
1952
+ "builder.addQuestion": "Add question",
1953
+ "builder.actions.addField": "Add question",
1954
+ "builder.actions.deleteField": "Delete",
1955
+ "builder.actions.moveUp": "Move up",
1956
+ "builder.actions.moveDown": "Move down",
1957
+ "builder.actions.add": "Add",
1958
+ "builder.actions.delete": "Delete",
1959
+ "builder.actions.edit": "Edit",
1960
+ "builder.actions.settings": "Settings",
1961
+ "builder.actions.translate": "Translate",
1962
+ "builder.actions.close": "Close",
1963
+ "builder.actions.dragHandle": "Reorder",
1964
+ "builder.fields.selectType": "Select field type",
1965
+ "builder.fields.typeText": "Text",
1966
+ "builder.fields.typeTextarea": "Textarea",
1967
+ "builder.fields.typeNumber": "Number",
1968
+ "builder.fields.typeRadio": "Radio",
1969
+ "builder.fields.typeCheckbox": "Checkbox",
1970
+ "builder.fields.typeSelect": "Select",
1971
+ "builder.fields.typeRating": "Rating",
1972
+ "builder.fields.typeMultiSelect": "Multi-select",
1973
+ "builder.fieldType.text": "Text",
1974
+ "builder.fieldType.textarea": "Textarea",
1975
+ "builder.fieldType.number": "Number",
1976
+ "builder.fieldType.radio": "Radio",
1977
+ "builder.fieldType.checkbox": "Checkbox",
1978
+ "builder.fieldType.select": "Select",
1979
+ "builder.fieldType.rating": "Rating",
1980
+ "builder.fieldType.multi-select": "Multi-select",
1981
+ "builder.fieldTypeDescription.text": "A single-line text answer",
1982
+ "builder.fieldTypeDescription.textarea": "A long-form text answer",
1983
+ "builder.fieldTypeDescription.number": "A numeric answer",
1984
+ "builder.fieldTypeDescription.radio": "A single-choice answer",
1985
+ "builder.fieldTypeDescription.checkbox": "A yes/no answer",
1986
+ "builder.fieldTypeDescription.select": "A dropdown choice",
1987
+ "builder.fieldTypeDescription.rating": "A rating scale answer",
1988
+ "builder.fieldTypeDescription.multi-select": "Multiple choices",
1989
+ "builder.fieldCategory.text": "Text",
1990
+ "builder.fieldCategory.choice": "Choice",
1991
+ "builder.fieldCategory.number": "Number",
1992
+ "builder.fieldCategory.advanced": "Advanced",
1993
+ "builder.required": "Required",
1994
+ "builder.options": "Options",
1995
+ "builder.localization.title": "Localization",
1996
+ "builder.localization": "Localization",
1997
+ "builder.localization.addLocale": "Add locale",
1998
+ "builder.localization.selectLocaleToAdd": "Select a locale to add",
1999
+ "builder.localization.defaultLocale": "Default locale",
2000
+ "builder.localization.translateAll": "Translate all text",
2001
+ "builder.localization.noLocalesConfigured": "Translations not configured",
2002
+ "builder.localization.localesConfiguredSummary": "{{count}} locales configured",
2003
+ "builder.localization.allLocalesAdded": "All available locales have been added",
2004
+ "builder.localization.maxLocalesReached": "The maximum number of locales ({{max}}) has been reached",
2005
+ "builder.submissionSettings.title": "Submission settings",
2006
+ "builder.submissionSettings.showConfirmation": "Show confirmation before submit",
2007
+ "builder.submissionSettings.renderMode": "Confirmation display mode",
2008
+ "builder.formBuilder": "Form builder",
2009
+ "builder.basicSettings": "Basic settings",
2010
+ "builder.description": "Description",
2011
+ "builder.moveUp": "Move {{title}} up",
2012
+ "builder.moveDown": "Move {{title}} down",
2013
+ "builder.delete": "Delete {{title}}",
2014
+ "builder.deleteAction": "Delete",
2015
+ "builder.questionTitle": "Question title",
2016
+ "builder.questionTitlePlaceholder": "Example: Tell us what we could improve",
2017
+ "builder.newQuestionTitle": "New question",
2018
+ "builder.type": "Type",
2019
+ "builder.minimum": "Minimum",
2020
+ "builder.maximum": "Maximum",
2021
+ "builder.minimumLength": "Minimum length",
2022
+ "builder.maximumLength": "Maximum length",
2023
+ "builder.pattern": "Pattern",
2024
+ "builder.step": "Step",
2025
+ "builder.optionLabel": "Option label {{index}}",
2026
+ "builder.optionLabelPlaceholder": "Example: Very satisfied",
2027
+ "builder.newOptionLabel": "Option {{index}}",
2028
+ "builder.remove": "Remove",
2029
+ "builder.addOption": "Add option",
2030
+ "builder.displayCondition": "Display condition",
2031
+ "builder.alwaysVisible": "Always visible",
2032
+ "builder.conditionOperator": "Condition operator",
2033
+ "builder.conditionValue": "Condition value",
2034
+ "builder.conditionTrue": "true",
2035
+ "builder.conditionFalse": "false",
2036
+ "builder.pages": "Page manager",
2037
+ "builder.enablePages": "Enable multi-step pages",
2038
+ "builder.addPage": "Add page",
2039
+ "builder.newPage": "New page",
2040
+ "builder.pageTitle": "Page title",
2041
+ "builder.pageDescription": "Page description",
2042
+ "builder.pageQuestion": "Question to move to the new page",
2043
+ "builder.questionPage": "Page",
2044
+ "builder.pageCondition": "Page display condition",
2045
+ "builder.unassigned": "Unassigned",
2046
+ "builder.defaultLocale": "Default locale",
2047
+ "builder.supportedLocales": "Supported locales",
2048
+ "builder.addLocale": "Add locale",
2049
+ "builder.editLocale": "Edit locale",
2050
+ "builder.autoTranslate": "Translate all text",
2051
+ "builder.translating": "Translating\u2026",
2052
+ "builder.translationLocale": "Translation locale",
2053
+ "builder.selectLocale": "Select a locale to edit translations.",
2054
+ "builder.selectLocaleToAdd": "Select a locale to add",
2055
+ "builder.translation": "{{locale}} translation",
2056
+ "builder.translatedFormTitle": "Translated form title",
2057
+ "builder.translatedFormDescription": "Translated form description",
2058
+ "builder.translatedCompletionMessage": "Translated completion message",
2059
+ "builder.translatedQuestionTitle": "Translated question title",
2060
+ "builder.translatedDescription": "Translated description",
2061
+ "builder.translationUnavailable": "Provide an async translation adapter to enable automatic translation.",
2062
+ "builder.operator.equals": "equals",
2063
+ "builder.operator.not_equals": "does not equal",
2064
+ "builder.operator.contains": "contains",
2065
+ "builder.operator.not_empty": "is not empty",
2066
+ "builder.showConfirmationBeforeSubmit": "Show confirmation before submit",
2067
+ "builder.confirmationRenderMode": "Confirmation display mode",
2068
+ "renderer.submitButton": "Submit",
2069
+ "renderer.submittingButton": "Submitting...",
2070
+ "renderer.retryButton": "Retry",
2071
+ "renderer.requiredField": "This field is required.",
2072
+ "renderer.alreadySubmittedTitle": "Already Submitted",
2073
+ "renderer.alreadySubmittedMessage": "Already submitted.",
2074
+ "renderer.serverErrorSummary": "Submission failed. Please check your answers and try again.",
2075
+ "renderer.confirmSensitiveDataTitle": "Sensitive data may be included",
2076
+ "renderer.confirmSensitiveDataMessage": "The following answers may contain personal information. Continue submitting?",
2077
+ "renderer.confirmButton": "Proceed",
2078
+ "renderer.cancelButton": "Cancel",
2079
+ "form.submit": "Submit",
2080
+ "form.submitting": "Submitting...",
2081
+ "form.back": "Back",
2082
+ "form.next": "Next",
2083
+ "form.step": "{{current}} / {{total}}",
2084
+ "form.draftRestored": "Draft restored",
2085
+ "form.submissionBlocked": "Submission blocked because personal information was detected.",
2086
+ "form.confirmSensitiveData": "Sensitive data may be included. Please review before submitting.",
2087
+ "form.confirmSubmission": "Proceed",
2088
+ "form.cancelSubmission": "Cancel",
2089
+ "form.yes": "Yes",
2090
+ "form.no": "No",
2091
+ "form.alreadySubmitted": "Already submitted.",
2092
+ "form.submitAnother": "Submit another response",
2093
+ "validation.required": "This field is required.",
2094
+ "validation.invalidOption": "Select a valid option.",
2095
+ "validation.invalidType": "Enter a valid value.",
2096
+ "validation.max": "Value is too large.",
2097
+ "validation.maxLength": "Value is too long.",
2098
+ "validation.maxSelections": "Select fewer options.",
2099
+ "validation.min": "Value is too small.",
2100
+ "validation.minLength": "Value is too short.",
2101
+ "validation.minSelections": "Select more options.",
2102
+ "validation.pattern": "Value has an invalid format.",
2103
+ "validation.sensitiveData": "Sensitive data may be included.",
2104
+ "validation.step": "Enter a value with the correct step.",
2105
+ "validation.unknownField": "This field is not recognized.",
2106
+ "workspace.title": "Translation workspace",
2107
+ "workspace.status.missing": "Missing",
2108
+ "workspace.status.translated": "Translated",
2109
+ "workspace.status.stale": "Source changed",
2110
+ "workspace.status.manual": "Manual",
2111
+ "workspace.status.manualStale": "Manual / source changed",
2112
+ "workspace.errors.localeNotAllowed": "Locale {{locale}} is not allowed.",
2113
+ "workspace.errors.maxLocalesExceeded": "The maximum number of locales ({{max}}) has been reached.",
2114
+ "workspace.errors.readOnly": "This workspace is read-only.",
2115
+ "workspace.errors.adapterNotConfigured": "A translation adapter is not configured.",
2116
+ "workspace.errors.translationFailed": "Translation failed."
2117
+ });
2118
+
2119
+ // src/i18n/catalogs/ja.ts
2120
+ var JA_MESSAGES = Object.freeze({
2121
+ "builder.formTitle": "\u30D5\u30A9\u30FC\u30E0\u306E\u30BF\u30A4\u30C8\u30EB",
2122
+ "builder.formDescription": "\u30D5\u30A9\u30FC\u30E0\u306E\u8AAC\u660E",
2123
+ "builder.completionMessage": "\u9001\u4FE1\u5B8C\u4E86\u30E1\u30C3\u30BB\u30FC\u30B8",
2124
+ "builder.addQuestion": "\u8CEA\u554F\u3092\u8FFD\u52A0",
2125
+ "builder.actions.addField": "\u8CEA\u554F\u3092\u8FFD\u52A0",
2126
+ "builder.actions.deleteField": "\u524A\u9664",
2127
+ "builder.actions.moveUp": "\u4E0A\u3078\u79FB\u52D5",
2128
+ "builder.actions.moveDown": "\u4E0B\u3078\u79FB\u52D5",
2129
+ "builder.actions.add": "\u8FFD\u52A0",
2130
+ "builder.actions.delete": "\u524A\u9664",
2131
+ "builder.actions.edit": "\u7DE8\u96C6",
2132
+ "builder.actions.settings": "\u8A2D\u5B9A",
2133
+ "builder.actions.translate": "\u7FFB\u8A33",
2134
+ "builder.actions.close": "\u9589\u3058\u308B",
2135
+ "builder.actions.dragHandle": "\u4E26\u3079\u66FF\u3048",
2136
+ "builder.fields.selectType": "\u8CEA\u554F\u5F62\u5F0F\u3092\u9078\u629E",
2137
+ "builder.fields.typeText": "\u4E00\u884C\u30C6\u30AD\u30B9\u30C8",
2138
+ "builder.fields.typeTextarea": "\u9577\u6587\u30C6\u30AD\u30B9\u30C8",
2139
+ "builder.fields.typeNumber": "\u6570\u5024",
2140
+ "builder.fields.typeRadio": "\u5358\u4E00\u9078\u629E (\u30E9\u30B8\u30AA\u30DC\u30BF\u30F3)",
2141
+ "builder.fields.typeCheckbox": "\u30C1\u30A7\u30C3\u30AF\u30DC\u30C3\u30AF\u30B9",
2142
+ "builder.fields.typeSelect": "\u30C9\u30ED\u30C3\u30D7\u30C0\u30A6\u30F3",
2143
+ "builder.fields.typeRating": "\u8A55\u4FA1\u30B9\u30B1\u30FC\u30EB",
2144
+ "builder.fields.typeMultiSelect": "\u8907\u6570\u9078\u629E",
2145
+ "builder.fieldType.text": "\u4E00\u884C\u30C6\u30AD\u30B9\u30C8",
2146
+ "builder.fieldType.textarea": "\u9577\u6587\u30C6\u30AD\u30B9\u30C8",
2147
+ "builder.fieldType.number": "\u6570\u5024",
2148
+ "builder.fieldType.radio": "\u5358\u4E00\u9078\u629E",
2149
+ "builder.fieldType.checkbox": "\u30C1\u30A7\u30C3\u30AF\u30DC\u30C3\u30AF\u30B9",
2150
+ "builder.fieldType.select": "\u30C9\u30ED\u30C3\u30D7\u30C0\u30A6\u30F3",
2151
+ "builder.fieldType.rating": "\u8A55\u4FA1\u30B9\u30B1\u30FC\u30EB",
2152
+ "builder.fieldType.multi-select": "\u8907\u6570\u9078\u629E",
2153
+ "builder.fieldTypeDescription.text": "\u4E00\u884C\u306E\u56DE\u7B54",
2154
+ "builder.fieldTypeDescription.textarea": "\u9577\u6587\u306E\u56DE\u7B54",
2155
+ "builder.fieldTypeDescription.number": "\u6570\u5024\u306E\u56DE\u7B54",
2156
+ "builder.fieldTypeDescription.radio": "\u5358\u4E00\u9078\u629E\u306E\u56DE\u7B54",
2157
+ "builder.fieldTypeDescription.checkbox": "\u306F\u3044 / \u3044\u3044\u3048\u306E\u56DE\u7B54",
2158
+ "builder.fieldTypeDescription.select": "\u30C9\u30ED\u30C3\u30D7\u30C0\u30A6\u30F3\u5F62\u5F0F\u306E\u56DE\u7B54",
2159
+ "builder.fieldTypeDescription.rating": "\u8A55\u4FA1\u30B9\u30B1\u30FC\u30EB\u306E\u56DE\u7B54",
2160
+ "builder.fieldTypeDescription.multi-select": "\u8907\u6570\u9078\u629E\u306E\u56DE\u7B54",
2161
+ "builder.fieldCategory.text": "\u30C6\u30AD\u30B9\u30C8",
2162
+ "builder.fieldCategory.choice": "\u9078\u629E\u5F0F",
2163
+ "builder.fieldCategory.number": "\u6570\u5024",
2164
+ "builder.fieldCategory.advanced": "\u8A73\u7D30\u8A2D\u5B9A",
2165
+ "builder.required": "\u5FC5\u9808\u9805\u76EE\u306B\u3059\u308B",
2166
+ "builder.options": "\u9078\u629E\u80A2\u4E00\u89A7",
2167
+ "builder.localization.title": "\u591A\u8A00\u8A9E\u8A2D\u5B9A",
2168
+ "builder.localization": "\u591A\u8A00\u8A9E\u8A2D\u5B9A",
2169
+ "builder.localization.addLocale": "\u8A00\u8A9E\u3092\u8FFD\u52A0",
2170
+ "builder.localization.selectLocaleToAdd": "\u8FFD\u52A0\u3059\u308B\u8A00\u8A9E\u3092\u9078\u629E",
2171
+ "builder.localization.defaultLocale": "\u30C7\u30D5\u30A9\u30EB\u30C8\u8A00\u8A9E (\u5143\u8A00\u8A9E)",
2172
+ "builder.localization.translateAll": "\u4E00\u62EC\u81EA\u52D5\u7FFB\u8A33",
2173
+ "builder.localization.noLocalesConfigured": "\u7FFB\u8A33\u8A00\u8A9E\u306F\u307E\u3060\u8A2D\u5B9A\u3055\u308C\u3066\u3044\u307E\u305B\u3093\u3002",
2174
+ "builder.localization.localesConfiguredSummary": "{{count}}\u8A00\u8A9E\u306E\u7FFB\u8A33\u304C\u8A2D\u5B9A\u3055\u308C\u3066\u3044\u307E\u3059\u3002",
2175
+ "builder.localization.allLocalesAdded": "\u3059\u3079\u3066\u306E\u5019\u88DC\u8A00\u8A9E\u304C\u8FFD\u52A0\u6E08\u307F\u3067\u3059",
2176
+ "builder.localization.maxLocalesReached": "\u767B\u9332\u53EF\u80FD\u306A\u6700\u5927\u8A00\u8A9E\u6570 ({{max}}) \u306B\u9054\u3057\u307E\u3057\u305F",
2177
+ "builder.submissionSettings.title": "\u9001\u4FE1\u8A2D\u5B9A",
2178
+ "builder.submissionSettings.showConfirmation": "\u9001\u4FE1\u524D\u306B\u56DE\u7B54\u78BA\u8A8D\u753B\u9762\u3092\u8868\u793A\u3059\u308B",
2179
+ "builder.submissionSettings.renderMode": "\u78BA\u8A8D\u753B\u9762\u306E\u8868\u793A\u5F62\u5F0F",
2180
+ "builder.formBuilder": "\u30D5\u30A9\u30FC\u30E0\u30D3\u30EB\u30C0\u30FC",
2181
+ "builder.basicSettings": "\u57FA\u672C\u8A2D\u5B9A",
2182
+ "builder.description": "\u8AAC\u660E",
2183
+ "builder.moveUp": "{{title}}\u3092\u4E0A\u3078\u79FB\u52D5",
2184
+ "builder.moveDown": "{{title}}\u3092\u4E0B\u3078\u79FB\u52D5",
2185
+ "builder.delete": "{{title}}\u3092\u524A\u9664",
2186
+ "builder.deleteAction": "\u524A\u9664",
2187
+ "builder.questionTitle": "\u8CEA\u554F\u6587",
2188
+ "builder.questionTitlePlaceholder": "\u4F8B: \u6539\u5584\u3067\u304D\u308B\u70B9\u3092\u6559\u3048\u3066\u304F\u3060\u3055\u3044",
2189
+ "builder.newQuestionTitle": "\u65B0\u3057\u3044\u8CEA\u554F",
2190
+ "builder.type": "\u5F62\u5F0F",
2191
+ "builder.minimum": "\u6700\u5C0F\u5024",
2192
+ "builder.maximum": "\u6700\u5927\u5024",
2193
+ "builder.minimumLength": "\u6700\u5C0F\u6587\u5B57\u6570",
2194
+ "builder.maximumLength": "\u6700\u5927\u6587\u5B57\u6570",
2195
+ "builder.pattern": "\u5F62\u5F0F\u30D1\u30BF\u30FC\u30F3",
2196
+ "builder.step": "\u523B\u307F\u5E45",
2197
+ "builder.optionLabel": "\u9078\u629E\u80A2 {{index}}",
2198
+ "builder.optionLabelPlaceholder": "\u4F8B: \u3068\u3066\u3082\u6E80\u8DB3",
2199
+ "builder.newOptionLabel": "\u9078\u629E\u80A2 {{index}}",
2200
+ "builder.remove": "\u524A\u9664",
2201
+ "builder.addOption": "\u9078\u629E\u80A2\u3092\u8FFD\u52A0",
2202
+ "builder.displayCondition": "\u8868\u793A\u6761\u4EF6",
2203
+ "builder.alwaysVisible": "\u5E38\u306B\u8868\u793A",
2204
+ "builder.conditionOperator": "\u6761\u4EF6\u6F14\u7B97\u5B50",
2205
+ "builder.conditionValue": "\u6761\u4EF6\u5024",
2206
+ "builder.conditionTrue": "\u306F\u3044",
2207
+ "builder.conditionFalse": "\u3044\u3044\u3048",
2208
+ "builder.pages": "\u30DA\u30FC\u30B8\u7BA1\u7406",
2209
+ "builder.enablePages": "\u8907\u6570\u30DA\u30FC\u30B8\u3092\u6709\u52B9\u306B\u3059\u308B",
2210
+ "builder.addPage": "\u30DA\u30FC\u30B8\u3092\u8FFD\u52A0",
2211
+ "builder.newPage": "\u65B0\u3057\u3044\u30DA\u30FC\u30B8",
2212
+ "builder.pageTitle": "\u30DA\u30FC\u30B8\u30BF\u30A4\u30C8\u30EB",
2213
+ "builder.pageDescription": "\u30DA\u30FC\u30B8\u306E\u8AAC\u660E",
2214
+ "builder.pageQuestion": "\u65B0\u3057\u3044\u30DA\u30FC\u30B8\u3078\u79FB\u52D5\u3059\u308B\u8CEA\u554F",
2215
+ "builder.questionPage": "\u30DA\u30FC\u30B8",
2216
+ "builder.pageCondition": "\u30DA\u30FC\u30B8\u306E\u8868\u793A\u6761\u4EF6",
2217
+ "builder.unassigned": "\u672A\u5272\u308A\u5F53\u3066",
2218
+ "builder.defaultLocale": "\u30C7\u30D5\u30A9\u30EB\u30C8\u8A00\u8A9E",
2219
+ "builder.supportedLocales": "\u5BFE\u5FDC\u8A00\u8A9E",
2220
+ "builder.addLocale": "\u8A00\u8A9E\u3092\u8FFD\u52A0",
2221
+ "builder.editLocale": "\u8A00\u8A9E\u3092\u7DE8\u96C6",
2222
+ "builder.autoTranslate": "\u3059\u3079\u3066\u7FFB\u8A33",
2223
+ "builder.translating": "\u7FFB\u8A33\u4E2D\u2026",
2224
+ "builder.translationLocale": "\u7FFB\u8A33\u8A00\u8A9E",
2225
+ "builder.selectLocale": "\u7FFB\u8A33\u3092\u7DE8\u96C6\u3059\u308B\u8A00\u8A9E\u3092\u9078\u629E\u3057\u3066\u304F\u3060\u3055\u3044\u3002",
2226
+ "builder.selectLocaleToAdd": "\u8FFD\u52A0\u3059\u308B\u8A00\u8A9E\u3092\u9078\u629E",
2227
+ "builder.translation": "{{locale}}\u7FFB\u8A33",
2228
+ "builder.translatedFormTitle": "\u7FFB\u8A33\u5F8C\u306E\u30D5\u30A9\u30FC\u30E0\u30BF\u30A4\u30C8\u30EB",
2229
+ "builder.translatedFormDescription": "\u7FFB\u8A33\u5F8C\u306E\u30D5\u30A9\u30FC\u30E0\u8AAC\u660E",
2230
+ "builder.translatedCompletionMessage": "\u7FFB\u8A33\u5F8C\u306E\u9001\u4FE1\u5B8C\u4E86\u30E1\u30C3\u30BB\u30FC\u30B8",
2231
+ "builder.translatedQuestionTitle": "\u7FFB\u8A33\u5F8C\u306E\u8CEA\u554F\u6587",
2232
+ "builder.translatedDescription": "\u7FFB\u8A33\u5F8C\u306E\u8AAC\u660E",
2233
+ "builder.translationUnavailable": "\u81EA\u52D5\u7FFB\u8A33\u306B\u306F\u975E\u540C\u671F\u7FFB\u8A33\u30A2\u30C0\u30D7\u30BF\u30FC\u3092\u8A2D\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044\u3002",
2234
+ "builder.operator.equals": "\u7B49\u3057\u3044",
2235
+ "builder.operator.not_equals": "\u7B49\u3057\u304F\u306A\u3044",
2236
+ "builder.operator.contains": "\u542B\u3080",
2237
+ "builder.operator.not_empty": "\u7A7A\u3067\u306F\u306A\u3044",
2238
+ "builder.showConfirmationBeforeSubmit": "\u9001\u4FE1\u524D\u306B\u78BA\u8A8D\u753B\u9762\u3092\u8868\u793A\u3059\u308B",
2239
+ "builder.confirmationRenderMode": "\u78BA\u8A8D\u753B\u9762\u306E\u8868\u793A\u5F62\u5F0F",
2240
+ "renderer.submitButton": "\u9001\u4FE1\u3059\u308B",
2241
+ "renderer.submittingButton": "\u9001\u4FE1\u4E2D...",
2242
+ "renderer.retryButton": "\u518D\u9001\u4FE1\u3059\u308B",
2243
+ "renderer.requiredField": "\u3053\u306E\u9805\u76EE\u306F\u5FC5\u9808\u3067\u3059\u3002",
2244
+ "renderer.alreadySubmittedTitle": "\u56DE\u7B54\u6E08\u307F\u3067\u3059",
2245
+ "renderer.alreadySubmittedMessage": "\u3053\u306E\u30A2\u30F3\u30B1\u30FC\u30C8\u306B\u306F\u3059\u3067\u306B\u56DE\u7B54\u3057\u3066\u3044\u307E\u3059\u3002",
2246
+ "renderer.serverErrorSummary": "\u9001\u4FE1\u306B\u5931\u6557\u3057\u307E\u3057\u305F\u3002\u5185\u5BB9\u3092\u3054\u78BA\u8A8D\u306E\u4E0A\u3001\u518D\u5EA6\u304A\u8A66\u3057\u304F\u3060\u3055\u3044\u3002",
2247
+ "renderer.confirmSensitiveDataTitle": "\u500B\u4EBA\u60C5\u5831\u304C\u542B\u307E\u308C\u3066\u3044\u308B\u53EF\u80FD\u6027\u304C\u3042\u308A\u307E\u3059",
2248
+ "renderer.confirmSensitiveDataMessage": "\u4EE5\u4E0B\u306E\u9805\u76EE\u306B\u500B\u4EBA\u60C5\u5831\u3068\u307F\u3089\u308C\u308B\u8A18\u8FF0\u304C\u3042\u308A\u307E\u3059\u3002\u3053\u306E\u307E\u307E\u9001\u4FE1\u3057\u3066\u3082\u3088\u308D\u3057\u3044\u3067\u3059\u304B\uFF1F",
2249
+ "renderer.confirmButton": "\u3053\u306E\u307E\u307E\u9001\u4FE1",
2250
+ "renderer.cancelButton": "\u4FEE\u6B63\u3059\u308B",
2251
+ "form.submit": "\u9001\u4FE1\u3059\u308B",
2252
+ "form.submitting": "\u9001\u4FE1\u4E2D...",
2253
+ "form.back": "\u623B\u308B",
2254
+ "form.next": "\u6B21\u3078",
2255
+ "form.step": "{{current}} / {{total}}",
2256
+ "form.draftRestored": "\u4E0B\u66F8\u304D\u3092\u5FA9\u5143\u3057\u307E\u3057\u305F",
2257
+ "form.submissionBlocked": "\u500B\u4EBA\u60C5\u5831\u304C\u691C\u51FA\u3055\u308C\u305F\u305F\u3081\u9001\u4FE1\u3067\u304D\u307E\u305B\u3093\u3002",
2258
+ "form.confirmSensitiveData": "\u500B\u4EBA\u60C5\u5831\u304C\u542B\u307E\u308C\u3066\u3044\u308B\u53EF\u80FD\u6027\u304C\u3042\u308A\u307E\u3059\u3002\u9001\u4FE1\u524D\u306B\u78BA\u8A8D\u3057\u3066\u304F\u3060\u3055\u3044\u3002",
2259
+ "form.confirmSubmission": "\u3053\u306E\u307E\u307E\u9001\u4FE1",
2260
+ "form.cancelSubmission": "\u4FEE\u6B63\u3059\u308B",
2261
+ "form.yes": "\u306F\u3044",
2262
+ "form.no": "\u3044\u3044\u3048",
2263
+ "form.alreadySubmitted": "\u56DE\u7B54\u6E08\u307F\u3067\u3059",
2264
+ "form.submitAnother": "\u5225\u306E\u56DE\u7B54\u3092\u9001\u4FE1",
2265
+ "validation.required": "\u3053\u306E\u9805\u76EE\u306F\u5FC5\u9808\u3067\u3059\u3002",
2266
+ "validation.invalidOption": "\u6709\u52B9\u306A\u9078\u629E\u80A2\u3092\u9078\u629E\u3057\u3066\u304F\u3060\u3055\u3044\u3002",
2267
+ "validation.invalidType": "\u6709\u52B9\u306A\u5024\u3092\u5165\u529B\u3057\u3066\u304F\u3060\u3055\u3044\u3002",
2268
+ "validation.max": "\u5024\u304C\u5927\u304D\u3059\u304E\u307E\u3059\u3002",
2269
+ "validation.maxLength": "\u5165\u529B\u304C\u9577\u3059\u304E\u307E\u3059\u3002",
2270
+ "validation.maxSelections": "\u9078\u629E\u6570\u3092\u6E1B\u3089\u3057\u3066\u304F\u3060\u3055\u3044\u3002",
2271
+ "validation.min": "\u5024\u304C\u5C0F\u3055\u3059\u304E\u307E\u3059\u3002",
2272
+ "validation.minLength": "\u5165\u529B\u304C\u77ED\u3059\u304E\u307E\u3059\u3002",
2273
+ "validation.minSelections": "\u3055\u3089\u306B\u9078\u629E\u3057\u3066\u304F\u3060\u3055\u3044\u3002",
2274
+ "validation.pattern": "\u5165\u529B\u5F62\u5F0F\u304C\u6B63\u3057\u304F\u3042\u308A\u307E\u305B\u3093\u3002",
2275
+ "validation.sensitiveData": "\u500B\u4EBA\u60C5\u5831\u304C\u542B\u307E\u308C\u3066\u3044\u308B\u53EF\u80FD\u6027\u304C\u3042\u308A\u307E\u3059\u3002",
2276
+ "validation.step": "\u6B63\u3057\u3044\u523B\u307F\u5E45\u306E\u5024\u3092\u5165\u529B\u3057\u3066\u304F\u3060\u3055\u3044\u3002",
2277
+ "validation.unknownField": "\u3053\u306E\u9805\u76EE\u306F\u8A8D\u8B58\u3055\u308C\u307E\u305B\u3093\u3002",
2278
+ "workspace.title": "\u591A\u8A00\u8A9E\u7FFB\u8A33\u30EF\u30FC\u30AF\u30B9\u30DA\u30FC\u30B9",
2279
+ "workspace.status.missing": "\u672A\u7FFB\u8A33",
2280
+ "workspace.status.translated": "\u7FFB\u8A33\u6E08\u307F",
2281
+ "workspace.status.stale": "\u539F\u6587\u66F4\u65B0\u3042\u308A",
2282
+ "workspace.status.manual": "\u624B\u52D5\u7DE8\u96C6\u6E08\u307F",
2283
+ "workspace.status.manualStale": "\u624B\u52D5\u7DE8\u96C6\u6E08\u307F (\u539F\u6587\u66F4\u65B0\u3042\u308A)",
2284
+ "workspace.errors.localeNotAllowed": "\u6307\u5B9A\u3055\u308C\u305F\u8A00\u8A9E\u300C{{locale}}\u300D\u306F\u8A2D\u5B9A\u3067\u304D\u307E\u305B\u3093\u3002",
2285
+ "workspace.errors.maxLocalesExceeded": "\u767B\u9332\u53EF\u80FD\u306A\u6700\u5927\u8A00\u8A9E\u6570 ({{max}}) \u306B\u9054\u3057\u307E\u3057\u305F\u3002",
2286
+ "workspace.errors.readOnly": "\u8AAD\u307F\u53D6\u308A\u5C02\u7528\u30E2\u30FC\u30C9\u306E\u305F\u3081\u5909\u66F4\u3067\u304D\u307E\u305B\u3093\u3002",
2287
+ "workspace.errors.adapterNotConfigured": "\u7FFB\u8A33\u30A2\u30C0\u30D7\u30BF\u30FC\u304C\u8A2D\u5B9A\u3055\u308C\u3066\u3044\u307E\u305B\u3093\u3002",
2288
+ "workspace.errors.translationFailed": "\u7FFB\u8A33\u51E6\u7406\u306B\u5931\u6557\u3057\u307E\u3057\u305F\u3002"
2289
+ });
2290
+
2291
+ // src/i18n/translator.ts
2292
+ function formatTemplate(template, params = {}) {
2293
+ return template.replace(
2294
+ /\{\{?(\w+)\}\}?/gu,
2295
+ (token, name) => Object.hasOwn(params, name) ? String(params[name]) : token
2296
+ );
2297
+ }
2298
+ function defaultCatalog(locale) {
2299
+ return locale.toLowerCase().startsWith("ja") ? JA_MESSAGES : EN_MESSAGES;
2300
+ }
2301
+ var createFormEngineTranslator = (options = {}) => {
2302
+ const { locale = "ja", fallbackLocale = "en", messages = {}, customCatalogs = {}, fallbackTextResolver } = options;
2303
+ const currentCatalog = { ...defaultCatalog(locale), ...customCatalogs[locale], ...messages };
2304
+ const fallbackCatalog = { ...defaultCatalog(fallbackLocale), ...customCatalogs[fallbackLocale] };
2305
+ return (rawKey, params = {}) => {
2306
+ const key = rawKey;
2307
+ const template = currentCatalog[key] ?? fallbackCatalog[key];
2308
+ if (template !== void 0 && template !== "") return formatTemplate(template, params);
2309
+ if (fallbackTextResolver !== void 0) return fallbackTextResolver(key, locale);
2310
+ return "";
2311
+ };
2312
+ };
2313
+
1872
2314
  // src/pagination.ts
2315
+ async function paginateWithFilter(params) {
2316
+ const { pageSize, cursor, maxScanPages = 5, fetchPage, filterPredicate, encodeCursor } = params;
2317
+ normalizeSubmissionPageSize(pageSize);
2318
+ if (!Number.isSafeInteger(maxScanPages) || maxScanPages < 1) {
2319
+ throw new TypeError("maxScanPages must be a positive safe integer.");
2320
+ }
2321
+ const collected = [];
2322
+ let currentRawCursor = cursor;
2323
+ let totalScannedCount = 0;
2324
+ let scanCount = 0;
2325
+ while (collected.length < pageSize && scanCount < maxScanPages) {
2326
+ scanCount += 1;
2327
+ const fetchLimit = pageSize - collected.length + 1;
2328
+ const { rawItems, rawNextCursor } = await fetchPage(currentRawCursor, fetchLimit);
2329
+ totalScannedCount += rawItems.length;
2330
+ for (const item of rawItems) {
2331
+ if (!filterPredicate(item)) continue;
2332
+ collected.push(item);
2333
+ if (collected.length === pageSize) {
2334
+ const lastItem = collected.at(-1);
2335
+ if (lastItem === void 0) break;
2336
+ return {
2337
+ items: collected,
2338
+ hasMore: rawNextCursor !== void 0,
2339
+ ...rawNextCursor === void 0 ? {} : { nextCursor: encodeCursor(lastItem) },
2340
+ totalScannedCount
2341
+ };
2342
+ }
2343
+ }
2344
+ if (rawItems.length === 0 || rawNextCursor === void 0) break;
2345
+ currentRawCursor = rawNextCursor;
2346
+ }
2347
+ return { items: collected, hasMore: false, totalScannedCount };
2348
+ }
1873
2349
  function asFormResponse2(submission) {
1874
2350
  return {
1875
2351
  responseId: submission.id,
@@ -1918,6 +2394,43 @@ async function* iterateSubmissionPages(adapter, formId, queryOptions = {}, optio
1918
2394
  cursor = nextCursor;
1919
2395
  }
1920
2396
  }
2397
+ function encodeStorageSubmissionCursor(value) {
2398
+ if (value.kind !== "submission" || value.formId.length === 0 || value.submittedAt.length === 0 || value.id.length === 0) {
2399
+ throw new TypeError("Submission cursor values are invalid.");
2400
+ }
2401
+ return encodeBase64Url(new TextEncoder().encode(JSON.stringify(value)));
2402
+ }
2403
+ function decodeStorageSubmissionCursor(cursor) {
2404
+ const parsed = decodeCursorPayload(cursor, "submission cursor payload is invalid.");
2405
+ if (parsed.kind !== "submission" || typeof parsed.formId !== "string" || parsed.formId.length === 0 || typeof parsed.submittedAt !== "string" || parsed.submittedAt.length === 0 || typeof parsed.id !== "string" || parsed.id.length === 0) {
2406
+ throw new TypeError("submission cursor payload is invalid.");
2407
+ }
2408
+ return {
2409
+ kind: "submission",
2410
+ formId: parsed.formId,
2411
+ submittedAt: parsed.submittedAt,
2412
+ id: parsed.id
2413
+ };
2414
+ }
2415
+ function encodeStorageTextAnswerCursor(value) {
2416
+ if (value.kind !== "text_answer" || value.formId.length === 0 || value.fieldId.length === 0 || value.submittedAt.length === 0 || value.submissionId.length === 0) {
2417
+ throw new TypeError("Text answer cursor values are invalid.");
2418
+ }
2419
+ return encodeBase64Url(new TextEncoder().encode(JSON.stringify(value)));
2420
+ }
2421
+ function decodeStorageTextAnswerCursor(cursor) {
2422
+ const parsed = decodeCursorPayload(cursor, "text answer cursor payload is invalid.");
2423
+ if (parsed.kind !== "text_answer" || typeof parsed.formId !== "string" || parsed.formId.length === 0 || typeof parsed.fieldId !== "string" || parsed.fieldId.length === 0 || typeof parsed.submittedAt !== "string" || parsed.submittedAt.length === 0 || typeof parsed.submissionId !== "string" || parsed.submissionId.length === 0) {
2424
+ throw new TypeError("text answer cursor payload is invalid.");
2425
+ }
2426
+ return {
2427
+ kind: "text_answer",
2428
+ formId: parsed.formId,
2429
+ fieldId: parsed.fieldId,
2430
+ submittedAt: parsed.submittedAt,
2431
+ submissionId: parsed.submissionId
2432
+ };
2433
+ }
1921
2434
  var BASE64_ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
1922
2435
  function encodeBase64(bytes) {
1923
2436
  let result = "";
@@ -1948,6 +2461,20 @@ function decodeBase64(value) {
1948
2461
  }
1949
2462
  return new Uint8Array(bytes);
1950
2463
  }
2464
+ function encodeBase64Url(bytes) {
2465
+ return encodeBase64(bytes).replaceAll("+", "-").replaceAll("/", "_").replace(/=+$/u, "");
2466
+ }
2467
+ function decodeCursorPayload(cursor, invalidMessage) {
2468
+ try {
2469
+ const normalized = cursor.replaceAll("-", "+").replaceAll("_", "/").padEnd(Math.ceil(cursor.length / 4) * 4, "=");
2470
+ const parsed = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(decodeBase64(normalized)));
2471
+ if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) throw new TypeError(invalidMessage);
2472
+ return parsed;
2473
+ } catch (cause) {
2474
+ if (cause instanceof TypeError && cause.message === invalidMessage) throw cause;
2475
+ throw new TypeError("cursor must be a valid Base64URL JSON token.", { cause });
2476
+ }
2477
+ }
1951
2478
  function encodeSubmissionCursor(value) {
1952
2479
  if (value.submittedAt.length === 0 || value.responseId.length === 0) {
1953
2480
  throw new TypeError("Cursor values must not be empty.");
@@ -2185,6 +2712,28 @@ function validatePageAnswers(schema, pageIndex, values) {
2185
2712
  }
2186
2713
  return issues.length === 0 ? { valid: true, issues: [] } : { valid: false, issues };
2187
2714
  }
2715
+ function validateSubmission(schema, submission, options) {
2716
+ const values = submission.values;
2717
+ const answerValidation = validateAnswers(schema, values);
2718
+ const fieldErrors = {};
2719
+ for (const issue2 of answerValidation.issues) {
2720
+ const existing = fieldErrors[issue2.fieldId];
2721
+ fieldErrors[issue2.fieldId] = existing === void 0 ? issue2.messageKey : `${existing}; ${issue2.messageKey}`;
2722
+ }
2723
+ const piiFindings = options?.privacyEngine?.detect(schema, { ...values });
2724
+ if (piiFindings !== void 0) {
2725
+ for (const finding of piiFindings) {
2726
+ const existing = fieldErrors[finding.fieldId];
2727
+ fieldErrors[finding.fieldId] = existing === void 0 ? "validation.sensitiveData" : `${existing}; validation.sensitiveData`;
2728
+ }
2729
+ }
2730
+ return {
2731
+ valid: Object.keys(fieldErrors).length === 0,
2732
+ fieldErrors,
2733
+ formErrors: [],
2734
+ ...piiFindings === void 0 ? {} : { piiFindings }
2735
+ };
2736
+ }
2188
2737
 
2189
2738
  // src/submission.ts
2190
2739
  function cloneValues(values) {
@@ -2192,7 +2741,46 @@ function cloneValues(values) {
2192
2741
  Object.entries(values).map(([key, value]) => [key, Array.isArray(value) ? Object.freeze([...value]) : value])
2193
2742
  );
2194
2743
  }
2195
- function createSubmission(schema, values, options) {
2744
+ function generatedSubmissionId() {
2745
+ return globalThis.crypto?.randomUUID?.() ?? `${Date.now()}-${Math.random().toString(36).slice(2)}`;
2746
+ }
2747
+ function toFormValues(answers) {
2748
+ const values = {};
2749
+ for (const [key, value] of Object.entries(answers)) {
2750
+ if (isFormValue(value)) values[key] = value;
2751
+ }
2752
+ return values;
2753
+ }
2754
+ function isFormValue(value) {
2755
+ return value === void 0 || typeof value === "string" || typeof value === "number" || typeof value === "boolean" || Array.isArray(value) && value.every((item) => typeof item === "string");
2756
+ }
2757
+ function createSubmission(schemaOrInput, values, options) {
2758
+ if ("answers" in schemaOrInput) {
2759
+ const input = schemaOrInput;
2760
+ const id = input.id ?? generatedSubmissionId();
2761
+ if (input.formId.trim().length === 0) throw new TypeError("formId must not be empty.");
2762
+ if (!Number.isSafeInteger(input.formVersion) || input.formVersion < 1) {
2763
+ throw new TypeError("formVersion must be a positive safe integer.");
2764
+ }
2765
+ const submittedAt = input.submittedAt ?? (/* @__PURE__ */ new Date()).toISOString();
2766
+ if (submittedAt.trim().length === 0 || !Number.isFinite(Date.parse(submittedAt))) {
2767
+ throw new TypeError("submittedAt must be a valid date string.");
2768
+ }
2769
+ const answers = Object.freeze({ ...input.answers });
2770
+ return Object.freeze({
2771
+ id,
2772
+ formId: input.formId,
2773
+ formVersion: input.formVersion,
2774
+ locale: "",
2775
+ values: Object.freeze(cloneValues(toFormValues(answers))),
2776
+ answers,
2777
+ metadata: input.metadata,
2778
+ submittedAt,
2779
+ ...input.schemaRevision === void 0 ? {} : { schemaRevision: input.schemaRevision }
2780
+ });
2781
+ }
2782
+ const schema = schemaOrInput;
2783
+ if (values === void 0 || options === void 0) throw new TypeError("values and options are required.");
2196
2784
  assertValidFormSchema(schema);
2197
2785
  if (options.id.trim().length === 0) throw new TypeError("Submission ID must not be empty.");
2198
2786
  if (options.locale.trim().length === 0) throw new TypeError("Submission locale must not be empty.");
@@ -2212,6 +2800,7 @@ function createSubmission(schema, values, options) {
2212
2800
  formVersion: schema.version,
2213
2801
  locale: options.locale,
2214
2802
  values: Object.freeze(cloneValues(visibleValues)),
2803
+ answers: Object.freeze({ ...visibleValues }),
2215
2804
  submittedAt: options.submittedAt,
2216
2805
  ...options.metadata === void 0 ? {} : { metadata: Object.freeze({ ...options.metadata }) },
2217
2806
  ...options.translationMetadata === void 0 ? {} : { translationMetadata: Object.freeze({ ...options.translationMetadata }) }
@@ -2268,8 +2857,15 @@ function withTranslationMetadata(node, locale, property, metadata) {
2268
2857
  }
2269
2858
  };
2270
2859
  }
2271
- function createSlot(kind, nodeId, property, locale, sourceText, existingText, nodeMetadata, existingTranslationMetadata, options = {}) {
2272
- const path = `${kind}.${nodeId}.${property}`;
2860
+ function localeRecordEntry2(record, locale) {
2861
+ const normalizedLocale = normalizeLocale(locale) ?? locale;
2862
+ for (const [candidate, value] of Object.entries(record ?? {})) {
2863
+ if ((normalizeLocale(candidate) ?? candidate) === normalizedLocale) return value;
2864
+ }
2865
+ return void 0;
2866
+ }
2867
+ function createSlot(kind, nodeId, property, locale, sourceText, existingText, nodeMetadata, existingTranslationMetadata, options = {}, parentId) {
2868
+ const path = kind === "form" ? `form.${property}` : kind === "option" ? `fields.${parentId ?? ""}.options.${nodeId}.${property}` : `${kind}s.${nodeId}.${property}`;
2273
2869
  const manual = options.isManualTranslation?.(existingTranslationMetadata, { path, locale }) ?? isManualTranslationMetadata(existingTranslationMetadata);
2274
2870
  const normalizedMetadata = existingTranslationMetadata === void 0 ? void 0 : options.normalizeMetadata === void 0 ? existingTranslationMetadata : { ...options.normalizeMetadata(existingTranslationMetadata, sourceText) };
2275
2871
  const status = getTranslationStatusWithManualOverride(sourceText, existingText, normalizedMetadata, manual);
@@ -2289,7 +2885,10 @@ function createSlot(kind, nodeId, property, locale, sourceText, existingText, no
2289
2885
  };
2290
2886
  }
2291
2887
  function translationSlots(schema, locale, options = {}) {
2888
+ locale = normalizeLocale(locale) ?? locale;
2292
2889
  const descriptors = [];
2890
+ const schemaTranslation = localeRecordEntry2(schema.translations, locale);
2891
+ const schemaTranslationMetadata = localeRecordEntry2(schema.translationMetadata, locale);
2293
2892
  const addFormSlot = (property, sourceText) => {
2294
2893
  const slot = createSlot(
2295
2894
  "form",
@@ -2297,17 +2896,17 @@ function translationSlots(schema, locale, options = {}) {
2297
2896
  property,
2298
2897
  locale,
2299
2898
  sourceText,
2300
- schema.translations?.[locale]?.[property],
2899
+ schemaTranslation?.[property],
2301
2900
  schema.metadata,
2302
- schema.translationMetadata?.[locale]?.[property],
2901
+ schemaTranslationMetadata?.[property],
2303
2902
  options
2304
2903
  );
2305
2904
  descriptors.push({
2306
2905
  slot,
2307
- manual: options.isManualTranslation?.(schema.translationMetadata?.[locale]?.[property], {
2906
+ manual: options.isManualTranslation?.(schemaTranslationMetadata?.[property], {
2308
2907
  path: slot.path ?? "",
2309
2908
  locale
2310
- }) ?? isManualTranslationMetadata(schema.translationMetadata?.[locale]?.[property]),
2909
+ }) ?? isManualTranslationMetadata(schemaTranslationMetadata?.[property]),
2311
2910
  apply: (current, value, metadata) => withTranslationMetadata(
2312
2911
  { ...current, translations: mergeLocalizedText(current.translations, locale, property, value) },
2313
2912
  locale,
@@ -2320,6 +2919,8 @@ function translationSlots(schema, locale, options = {}) {
2320
2919
  if (schema.description !== void 0) addFormSlot("description", schema.description);
2321
2920
  if (schema.completionMessage !== void 0) addFormSlot("completionMessage", schema.completionMessage);
2322
2921
  schema.fields.forEach((field, fieldIndex) => {
2922
+ const fieldTranslation = localeRecordEntry2(field.translations, locale);
2923
+ const fieldTranslationMetadata = localeRecordEntry2(field.translationMetadata, locale);
2323
2924
  const addFieldSlot = (property, sourceText) => {
2324
2925
  const slot = createSlot(
2325
2926
  "field",
@@ -2327,17 +2928,17 @@ function translationSlots(schema, locale, options = {}) {
2327
2928
  property,
2328
2929
  locale,
2329
2930
  sourceText,
2330
- field.translations?.[locale]?.[property],
2931
+ fieldTranslation?.[property],
2331
2932
  field.metadata,
2332
- field.translationMetadata?.[locale]?.[property],
2933
+ fieldTranslationMetadata?.[property],
2333
2934
  options
2334
2935
  );
2335
2936
  descriptors.push({
2336
2937
  slot,
2337
- manual: options.isManualTranslation?.(field.translationMetadata?.[locale]?.[property], {
2938
+ manual: options.isManualTranslation?.(fieldTranslationMetadata?.[property], {
2338
2939
  path: slot.path ?? "",
2339
2940
  locale
2340
- }) ?? isManualTranslationMetadata(field.translationMetadata?.[locale]?.[property]),
2941
+ }) ?? isManualTranslationMetadata(fieldTranslationMetadata?.[property]),
2341
2942
  apply: (current, value, metadata) => ({
2342
2943
  ...current,
2343
2944
  fields: current.fields.map(
@@ -2358,23 +2959,26 @@ function translationSlots(schema, locale, options = {}) {
2358
2959
  if (field.description !== void 0) addFieldSlot("description", field.description);
2359
2960
  if ("options" in field) {
2360
2961
  field.options.forEach((option, optionIndex) => {
2962
+ const optionTranslation = localeRecordEntry2(option.translations, locale);
2963
+ const optionTranslationMetadata = localeRecordEntry2(option.translationMetadata, locale);
2361
2964
  const slot = createSlot(
2362
2965
  "option",
2363
2966
  option.id,
2364
2967
  "label",
2365
2968
  locale,
2366
2969
  option.label,
2367
- option.translations?.[locale],
2970
+ optionTranslation,
2368
2971
  option.metadata,
2369
- option.translationMetadata?.[locale]?.label,
2370
- options
2972
+ optionTranslationMetadata?.label,
2973
+ options,
2974
+ field.id
2371
2975
  );
2372
2976
  descriptors.push({
2373
2977
  slot,
2374
- manual: options.isManualTranslation?.(option.translationMetadata?.[locale]?.label, {
2978
+ manual: options.isManualTranslation?.(optionTranslationMetadata?.label, {
2375
2979
  path: slot.path ?? "",
2376
2980
  locale
2377
- }) ?? isManualTranslationMetadata(option.translationMetadata?.[locale]?.label),
2981
+ }) ?? isManualTranslationMetadata(optionTranslationMetadata?.label),
2378
2982
  apply: (current, value, metadata) => ({
2379
2983
  ...current,
2380
2984
  fields: current.fields.map((candidate, candidateIndex) => {
@@ -2400,6 +3004,8 @@ function translationSlots(schema, locale, options = {}) {
2400
3004
  }
2401
3005
  });
2402
3006
  schema.pages?.forEach((page, pageIndex) => {
3007
+ const pageTranslation = localeRecordEntry2(page.translations, locale);
3008
+ const pageTranslationMetadata = localeRecordEntry2(page.translationMetadata, locale);
2403
3009
  const addPageSlot = (property, sourceText) => {
2404
3010
  const slot = createSlot(
2405
3011
  "page",
@@ -2407,17 +3013,17 @@ function translationSlots(schema, locale, options = {}) {
2407
3013
  property,
2408
3014
  locale,
2409
3015
  sourceText,
2410
- page.translations?.[locale]?.[property],
3016
+ pageTranslation?.[property],
2411
3017
  page.metadata,
2412
- page.translationMetadata?.[locale]?.[property],
3018
+ pageTranslationMetadata?.[property],
2413
3019
  options
2414
3020
  );
2415
3021
  descriptors.push({
2416
3022
  slot,
2417
- manual: options.isManualTranslation?.(page.translationMetadata?.[locale]?.[property], {
3023
+ manual: options.isManualTranslation?.(pageTranslationMetadata?.[property], {
2418
3024
  path: slot.path ?? "",
2419
3025
  locale
2420
- }) ?? isManualTranslationMetadata(page.translationMetadata?.[locale]?.[property]),
3026
+ }) ?? isManualTranslationMetadata(pageTranslationMetadata?.[property]),
2421
3027
  apply: (current, value, metadata) => ({
2422
3028
  ...current,
2423
3029
  ...current.pages === void 0 ? {} : {
@@ -2505,7 +3111,7 @@ var migrateSchemaTranslationMetadata = (schema, migratorOrOptions) => {
2505
3111
  (locale, property) => ({
2506
3112
  locale,
2507
3113
  defaultLocale,
2508
- path: property,
3114
+ path: `form.${property}`,
2509
3115
  property,
2510
3116
  nodeKind: "form"
2511
3117
  }),
@@ -2604,8 +3210,11 @@ function collectTranslationSlots(schema, locale) {
2604
3210
  return translationSlots(schema, locale).map((descriptor) => descriptor.slot);
2605
3211
  }
2606
3212
  function resolveLocalizedSchema(schema, targetLocale) {
2607
- if (targetLocale === void 0 || targetLocale.length === 0 || targetLocale === schema.defaultLocale) return schema;
2608
- const formTranslation = schema.translations?.[targetLocale];
3213
+ if (targetLocale === void 0 || targetLocale.length === 0) return schema;
3214
+ const normalizedTargetLocale = normalizeLocale(targetLocale) ?? targetLocale;
3215
+ const defaultLocale = schema.defaultLocale === void 0 ? void 0 : normalizeLocale(schema.defaultLocale);
3216
+ if (normalizedTargetLocale === defaultLocale || targetLocale === schema.defaultLocale) return schema;
3217
+ const formTranslation = localeRecordEntry2(schema.translations, normalizedTargetLocale);
2609
3218
  const completionMessage = formTranslation?.completionMessage ?? schema.completionMessage;
2610
3219
  return {
2611
3220
  ...schema,
@@ -2613,7 +3222,7 @@ function resolveLocalizedSchema(schema, targetLocale) {
2613
3222
  ...(formTranslation?.description ?? schema.description) === void 0 ? {} : { description: formTranslation?.description ?? schema.description },
2614
3223
  ...completionMessage === void 0 ? {} : { completionMessage },
2615
3224
  fields: schema.fields.map((field) => {
2616
- const translation = field.translations?.[targetLocale];
3225
+ const translation = localeRecordEntry2(field.translations, normalizedTargetLocale);
2617
3226
  const localized = {
2618
3227
  ...field,
2619
3228
  title: translation?.title ?? field.title,
@@ -2624,13 +3233,13 @@ function resolveLocalizedSchema(schema, targetLocale) {
2624
3233
  ...localized,
2625
3234
  options: field.options.map((option) => ({
2626
3235
  ...option,
2627
- label: option.translations?.[targetLocale] ?? option.label
3236
+ label: localeRecordEntry2(option.translations, normalizedTargetLocale) ?? option.label
2628
3237
  }))
2629
3238
  };
2630
3239
  }),
2631
3240
  ...schema.pages === void 0 ? {} : {
2632
3241
  pages: schema.pages.map((page) => {
2633
- const translation = page.translations?.[targetLocale];
3242
+ const translation = localeRecordEntry2(page.translations, normalizedTargetLocale);
2634
3243
  const title = translation?.title ?? page.title;
2635
3244
  const description = translation?.description ?? page.description;
2636
3245
  return {
@@ -2644,8 +3253,13 @@ function resolveLocalizedSchema(schema, targetLocale) {
2644
3253
  }
2645
3254
  async function populateSchemaTranslations(schema, targetLocales, adapter, options = {}) {
2646
3255
  assertValidFormSchema(schema);
2647
- const locales = [...new Set(targetLocales.filter((locale) => locale.length > 0 && locale !== schema.defaultLocale))];
2648
- const allowedLocales = options.policy?.allowedLocales;
3256
+ const defaultLocale = schema.defaultLocale === void 0 ? void 0 : normalizeLocale(schema.defaultLocale) ?? schema.defaultLocale;
3257
+ const locales = [
3258
+ ...new Set(
3259
+ targetLocales.map((locale) => normalizeLocale(locale) ?? locale.trim()).filter((locale) => locale.length > 0 && locale !== defaultLocale)
3260
+ )
3261
+ ];
3262
+ const allowedLocales = options.policy?.allowedLocales?.map((locale) => normalizeLocale(locale) ?? locale);
2649
3263
  const collectedLocales = collectSchemaLocales(schema);
2650
3264
  const disallowedLocale = [...collectedLocales.allUniqueLocales, ...locales].find(
2651
3265
  (locale) => allowedLocales !== void 0 && !allowedLocales.includes(locale)
@@ -2687,7 +3301,7 @@ async function populateSchemaTranslations(schema, targetLocales, adapter, option
2687
3301
  adapter,
2688
3302
  selected.map((descriptor) => descriptor.slot.sourceText),
2689
3303
  locale,
2690
- schema.defaultLocale
3304
+ defaultLocale
2691
3305
  );
2692
3306
  if (translated.length !== selected.length) {
2693
3307
  throw new Error(`Translation adapter returned ${translated.length} texts for ${selected.length} inputs.`);
@@ -2696,7 +3310,7 @@ async function populateSchemaTranslations(schema, targetLocales, adapter, option
2696
3310
  const translatedText = translated[index];
2697
3311
  if (translatedText === void 0) throw new Error("Translation adapter returned an unexpected result.");
2698
3312
  const metadata = options.createMetadata?.(descriptor.slot, translatedText) ?? {
2699
- sourceLocale: schema.defaultLocale ?? "",
3313
+ sourceLocale: defaultLocale ?? "",
2700
3314
  sourceTextHash: computeSourceTextHash(descriptor.slot.sourceText),
2701
3315
  translationSource: "automatic",
2702
3316
  translatedAt: (/* @__PURE__ */ new Date()).toISOString()
@@ -2707,8 +3321,8 @@ async function populateSchemaTranslations(schema, targetLocales, adapter, option
2707
3321
  }
2708
3322
  const supportedLocales = [
2709
3323
  .../* @__PURE__ */ new Set([
2710
- ...schema.defaultLocale === void 0 ? [] : [schema.defaultLocale],
2711
- ...schema.supportedLocales ?? [],
3324
+ ...defaultLocale === void 0 ? [] : [defaultLocale],
3325
+ ...(schema.supportedLocales ?? []).map((locale) => normalizeLocale(locale) ?? locale),
2712
3326
  ...locales
2713
3327
  ])
2714
3328
  ];
@@ -3005,10 +3619,50 @@ function assertVersionMutable(status) {
3005
3619
  throw new TypeError(`A ${status} form version is immutable.`, { cause: error });
3006
3620
  }
3007
3621
  }
3622
+ function applyTransitionPlan(plan) {
3623
+ if (plan.schema !== void 0) return plan.schema;
3624
+ if (plan.publishedRecordToSave !== void 0) return plan.publishedRecordToSave.schema;
3625
+ if (plan.draftToCreate !== void 0) return plan.draftToCreate.schema;
3626
+ const archivedSchema = plan.archivedRecordsToSave?.[0]?.schema;
3627
+ if (archivedSchema !== void 0) return archivedSchema;
3628
+ throw new TypeError("A version transition plan must include a target schema.");
3629
+ }
3630
+ async function commitVersionTransition(options) {
3631
+ const { context, beforeTransition, afterTransition, persistAdapter } = options;
3632
+ const { formId, toVersion, expectedRevision, plan } = context;
3633
+ let currentDomainData = context.domainData;
3634
+ try {
3635
+ if (beforeTransition !== void 0) {
3636
+ const hookResult = await beforeTransition(context);
3637
+ if (hookResult !== void 0) currentDomainData = hookResult;
3638
+ }
3639
+ const nextSchema = applyTransitionPlan(plan);
3640
+ const { nextRevision } = await persistAdapter({
3641
+ formId,
3642
+ targetVersion: toVersion,
3643
+ expectedRevision,
3644
+ schema: nextSchema,
3645
+ ...currentDomainData === void 0 ? {} : { domainData: currentDomainData }
3646
+ });
3647
+ if (afterTransition !== void 0) {
3648
+ await afterTransition({
3649
+ ...context,
3650
+ ...currentDomainData === void 0 ? {} : { domainData: currentDomainData },
3651
+ nextRevision
3652
+ });
3653
+ }
3654
+ return { success: true, nextRevision };
3655
+ } catch (cause) {
3656
+ return { success: false, nextRevision: expectedRevision, error: { type: "transition_failed", cause } };
3657
+ }
3658
+ }
3008
3659
  // Annotate the CommonJS export names for ESM import in node:
3009
3660
  0 && (module.exports = {
3010
3661
  DEFAULT_FIELD_TYPE_DEFINITIONS,
3662
+ EN_MESSAGES,
3663
+ JA_MESSAGES,
3011
3664
  aggregateResponses,
3665
+ applyTransitionPlan,
3012
3666
  assertValidFormSchema,
3013
3667
  assertVersionMutable,
3014
3668
  calculateChoiceDistribution,
@@ -3019,16 +3673,22 @@ function assertVersionMutable(status) {
3019
3673
  cloneVersionToDraft,
3020
3674
  collectSchemaLocales,
3021
3675
  collectTranslationSlots,
3676
+ commitVersionTransition,
3022
3677
  computeSourceTextHash,
3023
3678
  createCloneTransitionPlan,
3024
3679
  createDeleteDraftTransitionPlan,
3680
+ createFormEngineTranslator,
3025
3681
  createPublishTransitionPlan,
3026
3682
  createResponseAccumulator,
3027
3683
  createSubmission,
3684
+ decodeStorageSubmissionCursor,
3685
+ decodeStorageTextAnswerCursor,
3028
3686
  decodeSubmissionCursor,
3029
3687
  decodeTextAnswerCursor,
3030
3688
  deleteDraft,
3031
3689
  dispatchWebhook,
3690
+ encodeStorageSubmissionCursor,
3691
+ encodeStorageTextAnswerCursor,
3032
3692
  encodeSubmissionCursor,
3033
3693
  encodeTextAnswerCursor,
3034
3694
  escapeCsvCell,
@@ -3044,7 +3704,9 @@ function assertVersionMutable(status) {
3044
3704
  matchesSubmissionFilter,
3045
3705
  matchesSubmissionPageFilters,
3046
3706
  migrateSchemaTranslationMetadata,
3707
+ normalizeLocale,
3047
3708
  normalizeSubmissionPageSize,
3709
+ paginateWithFilter,
3048
3710
  pipeResponsesToCsvStream,
3049
3711
  populateSchemaTranslations,
3050
3712
  publishDraft,
@@ -3057,5 +3719,6 @@ function assertVersionMutable(status) {
3057
3719
  validateAnswers,
3058
3720
  validateFormSchema,
3059
3721
  validatePageAnswers,
3060
- validateSchemaStructure
3722
+ validateSchemaStructure,
3723
+ validateSubmission
3061
3724
  });