@form-engine-ts/react 5.1.0 → 6.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/README.md +4 -0
- package/dist/index.cjs +126 -22
- package/dist/index.d.cts +40 -3
- package/dist/index.d.ts +40 -3
- package/dist/index.js +134 -30
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -89,6 +89,10 @@ underscore-separated values such as `EN_us` are accepted as compatibility input.
|
|
|
89
89
|
Use `isAddLocaleAllowed` to disable locale controls before submission. Removing a locale also clears its
|
|
90
90
|
localized values and metadata; the default locale remains protected.
|
|
91
91
|
|
|
92
|
+
`useTranslationWorkspace` can notify `onTranslationStart`, `onTranslationSuccess`, `onTranslationError`, and
|
|
93
|
+
`onTranslationChange` with typed lifecycle payloads. The MUI workspace accepts a `confirmRemoveLocale` slot for an
|
|
94
|
+
async confirmation UI; its `onConfirm` callback completes the locale removal.
|
|
95
|
+
|
|
92
96
|
Wrap a builder or renderer in `FormEngineI18nProvider` to supply a UI locale and typed Core translator independently
|
|
93
97
|
from the schema's `defaultLocale` and `supportedLocales`:
|
|
94
98
|
|
package/dist/index.cjs
CHANGED
|
@@ -3421,26 +3421,27 @@ function workspaceLocaleValidationError(validation, currentLocales, requestedLoc
|
|
|
3421
3421
|
}
|
|
3422
3422
|
return { type: "custom_validation_failed", message: error.message };
|
|
3423
3423
|
}
|
|
3424
|
-
function
|
|
3424
|
+
function translationMetadata(sourceText, sourceLocale, mode) {
|
|
3425
3425
|
return {
|
|
3426
3426
|
sourceLocale,
|
|
3427
3427
|
sourceTextHash: (0, import_core5.computeSourceTextHash)(sourceText),
|
|
3428
|
-
translationSource:
|
|
3429
|
-
editedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
3428
|
+
translationSource: mode,
|
|
3429
|
+
...mode === "manual" ? { editedAt: (/* @__PURE__ */ new Date()).toISOString() } : { translatedAt: (/* @__PURE__ */ new Date()).toISOString() }
|
|
3430
3430
|
};
|
|
3431
3431
|
}
|
|
3432
|
-
function setNodeMetadata(node, slot, text, sourceLocale) {
|
|
3432
|
+
function setNodeMetadata(node, slot, text, sourceLocale, mode) {
|
|
3433
3433
|
const localeMetadata = node.translationMetadata?.[slot.locale];
|
|
3434
|
-
const nextMetadata = text.trim().length === 0 ? Object.fromEntries(Object.entries(localeMetadata ?? {}).filter(([key]) => key !== slot.property)) : { ...localeMetadata, [slot.property]:
|
|
3434
|
+
const nextMetadata = text.trim().length === 0 ? Object.fromEntries(Object.entries(localeMetadata ?? {}).filter(([key]) => key !== slot.property)) : { ...localeMetadata, [slot.property]: translationMetadata(slot.sourceText, sourceLocale, mode) };
|
|
3435
3435
|
return { ...node, translationMetadata: { ...node.translationMetadata, [slot.locale]: nextMetadata } };
|
|
3436
3436
|
}
|
|
3437
|
-
function updateSchemaTranslation(schema, slot, text, sourceLocale) {
|
|
3437
|
+
function updateSchemaTranslation(schema, slot, text, sourceLocale, mode = "manual") {
|
|
3438
3438
|
if (slot.kind === "form") {
|
|
3439
3439
|
return setNodeMetadata(
|
|
3440
3440
|
{ ...schema, translations: updateTranslationMap(schema.translations, slot.locale, slot.property, text) },
|
|
3441
3441
|
slot,
|
|
3442
3442
|
text,
|
|
3443
|
-
sourceLocale
|
|
3443
|
+
sourceLocale,
|
|
3444
|
+
mode
|
|
3444
3445
|
);
|
|
3445
3446
|
}
|
|
3446
3447
|
if (slot.kind === "field") {
|
|
@@ -3449,7 +3450,7 @@ function updateSchemaTranslation(schema, slot, text, sourceLocale) {
|
|
|
3449
3450
|
fields: schema.fields.map((field) => {
|
|
3450
3451
|
if (field.id !== slot.nodeId) return field;
|
|
3451
3452
|
const translations = updateTranslationMap(field.translations, slot.locale, slot.property, text);
|
|
3452
|
-
return setNodeMetadata({ ...field, translations }, slot, text, sourceLocale);
|
|
3453
|
+
return setNodeMetadata({ ...field, translations }, slot, text, sourceLocale, mode);
|
|
3453
3454
|
})
|
|
3454
3455
|
};
|
|
3455
3456
|
}
|
|
@@ -3465,7 +3466,7 @@ function updateSchemaTranslation(schema, slot, text, sourceLocale) {
|
|
|
3465
3466
|
const translations = text.trim().length === 0 ? Object.fromEntries(
|
|
3466
3467
|
Object.entries(option.translations ?? {}).filter(([locale]) => locale !== slot.locale)
|
|
3467
3468
|
) : { ...option.translations, [slot.locale]: text };
|
|
3468
|
-
return setNodeMetadata({ ...option, translations }, slot, text, sourceLocale);
|
|
3469
|
+
return setNodeMetadata({ ...option, translations }, slot, text, sourceLocale, mode);
|
|
3469
3470
|
})
|
|
3470
3471
|
};
|
|
3471
3472
|
})
|
|
@@ -3477,7 +3478,7 @@ function updateSchemaTranslation(schema, slot, text, sourceLocale) {
|
|
|
3477
3478
|
pages: schema.pages.map((page) => {
|
|
3478
3479
|
if (page.id !== slot.nodeId) return page;
|
|
3479
3480
|
const translations = updateTranslationMap(page.translations, slot.locale, slot.property, text);
|
|
3480
|
-
return setNodeMetadata({ ...page, translations }, slot, text, sourceLocale);
|
|
3481
|
+
return setNodeMetadata({ ...page, translations }, slot, text, sourceLocale, mode);
|
|
3481
3482
|
})
|
|
3482
3483
|
}
|
|
3483
3484
|
};
|
|
@@ -3495,13 +3496,22 @@ function useTranslationWorkspace({
|
|
|
3495
3496
|
onLocaleRemoved,
|
|
3496
3497
|
onLocaleChange,
|
|
3497
3498
|
beforeRemoveLocale,
|
|
3499
|
+
confirmRemoveLocale,
|
|
3500
|
+
slots: workspaceSlots,
|
|
3501
|
+
onTranslationStart,
|
|
3502
|
+
onTranslationSuccess,
|
|
3503
|
+
onTranslationError,
|
|
3504
|
+
onTranslationChange,
|
|
3498
3505
|
validateLocale
|
|
3499
3506
|
}) {
|
|
3500
3507
|
const [draftSchema, setDraftSchema] = (0, import_react5.useState)(schema);
|
|
3501
3508
|
const [selectedLocale, setSelectedLocale] = (0, import_react5.useState)((0, import_core5.normalizeLocale)(targetLocale ?? "") ?? targetLocale ?? "");
|
|
3502
3509
|
const [isTranslating, setIsTranslating] = (0, import_react5.useState)(false);
|
|
3503
3510
|
const [error, setError] = (0, import_react5.useState)();
|
|
3511
|
+
const [pendingRemoval, setPendingRemoval] = (0, import_react5.useState)();
|
|
3512
|
+
const pendingRemovalResolver = (0, import_react5.useRef)(void 0);
|
|
3504
3513
|
const currentSchema = onChange === void 0 ? draftSchema : schema;
|
|
3514
|
+
const confirmRemoveLocaleRenderer = confirmRemoveLocale ?? workspaceSlots?.confirmRemoveLocale;
|
|
3505
3515
|
const targetLocales = (0, import_react5.useMemo)(() => {
|
|
3506
3516
|
const locales = (0, import_core5.collectSchemaLocales)(currentSchema).allUniqueLocales;
|
|
3507
3517
|
return [.../* @__PURE__ */ new Set([...currentSchema.supportedLocales ?? [], ...locales])].filter(
|
|
@@ -3551,9 +3561,17 @@ function useTranslationWorkspace({
|
|
|
3551
3561
|
const setTranslation = (0, import_react5.useCallback)(
|
|
3552
3562
|
(slot, text) => {
|
|
3553
3563
|
if (readOnly) return;
|
|
3554
|
-
|
|
3564
|
+
const metadata = translationMetadata(slot.sourceText, sourceLocale, "manual");
|
|
3565
|
+
commit(updateSchemaTranslation(currentSchema, slot, text, sourceLocale, "manual"));
|
|
3566
|
+
onTranslationChange?.({
|
|
3567
|
+
slot,
|
|
3568
|
+
...slot.existingText === void 0 ? {} : { previousText: slot.existingText },
|
|
3569
|
+
nextText: text,
|
|
3570
|
+
mode: "manual",
|
|
3571
|
+
metadata
|
|
3572
|
+
});
|
|
3555
3573
|
},
|
|
3556
|
-
[commit, currentSchema, readOnly, sourceLocale]
|
|
3574
|
+
[commit, currentSchema, onTranslationChange, readOnly, sourceLocale]
|
|
3557
3575
|
);
|
|
3558
3576
|
const addLocale = (0, import_react5.useCallback)(
|
|
3559
3577
|
(locale) => {
|
|
@@ -3614,21 +3632,36 @@ function useTranslationWorkspace({
|
|
|
3614
3632
|
onLocaleRemoved?.(normalized);
|
|
3615
3633
|
};
|
|
3616
3634
|
const slotCount = (0, import_core5.collectTranslationSlots)(currentSchema, normalized).length;
|
|
3635
|
+
const translatedSlotsCount = (0, import_core5.collectTranslationSlots)(currentSchema, normalized).filter(
|
|
3636
|
+
(slot) => slot.existingText !== void 0 && slot.existingText.trim().length > 0
|
|
3637
|
+
).length;
|
|
3638
|
+
const requestConfirmation = () => new Promise((resolve) => {
|
|
3639
|
+
pendingRemovalResolver.current = resolve;
|
|
3640
|
+
setPendingRemoval({
|
|
3641
|
+
locale: normalized,
|
|
3642
|
+
localeLabel: localeOptions.find((option) => option.locale === normalized)?.label ?? normalized,
|
|
3643
|
+
translatedSlotsCount
|
|
3644
|
+
});
|
|
3645
|
+
});
|
|
3646
|
+
const removeAfterApproval = () => {
|
|
3647
|
+
if (confirmRemoveLocaleRenderer === void 0) {
|
|
3648
|
+
remove();
|
|
3649
|
+
return true;
|
|
3650
|
+
}
|
|
3651
|
+
return requestConfirmation();
|
|
3652
|
+
};
|
|
3617
3653
|
if (beforeRemoveLocale === void 0) {
|
|
3618
|
-
|
|
3619
|
-
return true;
|
|
3654
|
+
return removeAfterApproval();
|
|
3620
3655
|
}
|
|
3621
3656
|
try {
|
|
3622
3657
|
const decision = beforeRemoveLocale(normalized, { slotCount });
|
|
3623
3658
|
if (typeof decision === "boolean") {
|
|
3624
3659
|
if (!decision) return false;
|
|
3625
|
-
|
|
3626
|
-
return true;
|
|
3660
|
+
return removeAfterApproval();
|
|
3627
3661
|
}
|
|
3628
3662
|
return decision.then((allowed) => {
|
|
3629
3663
|
if (!allowed) return false;
|
|
3630
|
-
|
|
3631
|
-
return true;
|
|
3664
|
+
return removeAfterApproval();
|
|
3632
3665
|
});
|
|
3633
3666
|
} catch (cause) {
|
|
3634
3667
|
const workspaceError = {
|
|
@@ -3640,8 +3673,45 @@ function useTranslationWorkspace({
|
|
|
3640
3673
|
return Promise.reject(cause);
|
|
3641
3674
|
}
|
|
3642
3675
|
},
|
|
3643
|
-
[
|
|
3676
|
+
[
|
|
3677
|
+
activeLocale,
|
|
3678
|
+
beforeRemoveLocale,
|
|
3679
|
+
commit,
|
|
3680
|
+
confirmRemoveLocaleRenderer,
|
|
3681
|
+
currentSchema,
|
|
3682
|
+
localeOptions,
|
|
3683
|
+
onLocaleRemoved,
|
|
3684
|
+
readOnly,
|
|
3685
|
+
sourceLocale
|
|
3686
|
+
]
|
|
3644
3687
|
);
|
|
3688
|
+
const confirmPendingRemoval = (0, import_react5.useCallback)(() => {
|
|
3689
|
+
const pending = pendingRemoval;
|
|
3690
|
+
const resolve = pendingRemovalResolver.current;
|
|
3691
|
+
if (pending === void 0 || resolve === void 0) return;
|
|
3692
|
+
pendingRemovalResolver.current = void 0;
|
|
3693
|
+
setPendingRemoval(void 0);
|
|
3694
|
+
commit((0, import_core5.removeLocaleFromSchema)(currentSchema, pending.locale));
|
|
3695
|
+
if (activeLocale === pending.locale) setSelectedLocale("");
|
|
3696
|
+
onLocaleRemoved?.(pending.locale);
|
|
3697
|
+
resolve(true);
|
|
3698
|
+
}, [activeLocale, commit, currentSchema, onLocaleRemoved, pendingRemoval]);
|
|
3699
|
+
const cancelPendingRemoval = (0, import_react5.useCallback)(() => {
|
|
3700
|
+
const resolve = pendingRemovalResolver.current;
|
|
3701
|
+
if (resolve === void 0) return;
|
|
3702
|
+
pendingRemovalResolver.current = void 0;
|
|
3703
|
+
setPendingRemoval(void 0);
|
|
3704
|
+
resolve(false);
|
|
3705
|
+
}, []);
|
|
3706
|
+
const removeLocaleConfirmation = (0, import_react5.useMemo)(() => {
|
|
3707
|
+
if (confirmRemoveLocaleRenderer === void 0 || pendingRemoval === void 0) return null;
|
|
3708
|
+
return confirmRemoveLocaleRenderer({
|
|
3709
|
+
...pendingRemoval,
|
|
3710
|
+
isOpen: true,
|
|
3711
|
+
onConfirm: confirmPendingRemoval,
|
|
3712
|
+
onCancel: cancelPendingRemoval
|
|
3713
|
+
});
|
|
3714
|
+
}, [cancelPendingRemoval, confirmPendingRemoval, confirmRemoveLocaleRenderer, pendingRemoval]);
|
|
3645
3715
|
const translateAll = (0, import_react5.useCallback)(
|
|
3646
3716
|
async (options = {}) => {
|
|
3647
3717
|
if (readOnly) {
|
|
@@ -3678,6 +3748,7 @@ function useTranslationWorkspace({
|
|
|
3678
3748
|
}
|
|
3679
3749
|
setIsTranslating(true);
|
|
3680
3750
|
setError(void 0);
|
|
3751
|
+
onTranslationStart?.({ targetLocale: activeLocale, mode: "automatic" });
|
|
3681
3752
|
try {
|
|
3682
3753
|
const populated = await (0, import_core5.populateSchemaTranslations)(
|
|
3683
3754
|
currentSchema,
|
|
@@ -3690,6 +3761,17 @@ function useTranslationWorkspace({
|
|
|
3690
3761
|
}
|
|
3691
3762
|
);
|
|
3692
3763
|
commit(populated.schema);
|
|
3764
|
+
const missingSlotsCount = (0, import_core5.collectTranslationSlots)(populated.schema, activeLocale).filter(
|
|
3765
|
+
(slot) => slot.status === "missing"
|
|
3766
|
+
).length;
|
|
3767
|
+
onTranslationSuccess?.({
|
|
3768
|
+
sourceLocale,
|
|
3769
|
+
targetLocale: activeLocale,
|
|
3770
|
+
mode: "automatic",
|
|
3771
|
+
updatedSlots: populated.report.updatedSlots,
|
|
3772
|
+
skippedSlots: populated.report.skippedSlots,
|
|
3773
|
+
missingSlotsCount
|
|
3774
|
+
});
|
|
3693
3775
|
return { success: true, report: populated.report };
|
|
3694
3776
|
} catch (cause) {
|
|
3695
3777
|
const workspaceError = {
|
|
@@ -3698,12 +3780,25 @@ function useTranslationWorkspace({
|
|
|
3698
3780
|
cause
|
|
3699
3781
|
};
|
|
3700
3782
|
setError(workspaceError);
|
|
3783
|
+
onTranslationError?.({ targetLocale: activeLocale, error: workspaceError });
|
|
3701
3784
|
return { success: false, error: workspaceError };
|
|
3702
3785
|
} finally {
|
|
3703
3786
|
setIsTranslating(false);
|
|
3704
3787
|
}
|
|
3705
3788
|
},
|
|
3706
|
-
[
|
|
3789
|
+
[
|
|
3790
|
+
activeLocale,
|
|
3791
|
+
commit,
|
|
3792
|
+
currentSchema,
|
|
3793
|
+
localeOptions,
|
|
3794
|
+
onTranslationError,
|
|
3795
|
+
onTranslationStart,
|
|
3796
|
+
onTranslationSuccess,
|
|
3797
|
+
readOnly,
|
|
3798
|
+
slots,
|
|
3799
|
+
sourceLocale,
|
|
3800
|
+
translationAdapter
|
|
3801
|
+
]
|
|
3707
3802
|
);
|
|
3708
3803
|
const translateSlot = (0, import_react5.useCallback)(
|
|
3709
3804
|
async (slot) => {
|
|
@@ -3721,7 +3816,15 @@ function useTranslationWorkspace({
|
|
|
3721
3816
|
setError(void 0);
|
|
3722
3817
|
try {
|
|
3723
3818
|
const text = await asAsyncAdapter(translationAdapter).translateText(slot.sourceText, slot.locale, sourceLocale);
|
|
3724
|
-
|
|
3819
|
+
const metadata = translationMetadata(slot.sourceText, sourceLocale, "automatic");
|
|
3820
|
+
commit(updateSchemaTranslation(currentSchema, slot, text, sourceLocale, "automatic"));
|
|
3821
|
+
onTranslationChange?.({
|
|
3822
|
+
slot,
|
|
3823
|
+
...slot.existingText === void 0 ? {} : { previousText: slot.existingText },
|
|
3824
|
+
nextText: text,
|
|
3825
|
+
mode: "automatic",
|
|
3826
|
+
metadata
|
|
3827
|
+
});
|
|
3725
3828
|
return { success: true };
|
|
3726
3829
|
} catch (cause) {
|
|
3727
3830
|
const workspaceError = {
|
|
@@ -3735,7 +3838,7 @@ function useTranslationWorkspace({
|
|
|
3735
3838
|
setIsTranslating(false);
|
|
3736
3839
|
}
|
|
3737
3840
|
},
|
|
3738
|
-
[commit, currentSchema, readOnly, sourceLocale, translationAdapter]
|
|
3841
|
+
[commit, currentSchema, onTranslationChange, readOnly, sourceLocale, translationAdapter]
|
|
3739
3842
|
);
|
|
3740
3843
|
return {
|
|
3741
3844
|
sourceLocale,
|
|
@@ -3752,6 +3855,7 @@ function useTranslationWorkspace({
|
|
|
3752
3855
|
addLocale,
|
|
3753
3856
|
isAddLocaleAllowed,
|
|
3754
3857
|
removeLocale,
|
|
3858
|
+
...removeLocaleConfirmation === null ? {} : { removeLocaleConfirmation },
|
|
3755
3859
|
setTranslation,
|
|
3756
3860
|
translateAll,
|
|
3757
3861
|
translateSlot,
|
package/dist/index.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as _form_engine_ts_core from '@form-engine-ts/core';
|
|
2
|
-
import { QuestionType, FormField, ChoiceOption, FormPage, FormSchema, DisplayCondition, JsonValue, SchemaIssue, FormPolicy, Question, FieldOption, TranslationReport, ValidationIssue, ValidationError, FormValues, LocaleOption, TranslationAdapter, AsyncTranslationAdapter, PopulateTranslationOptions, FormValue, AnswerValidationResult,
|
|
2
|
+
import { QuestionType, FormField, ChoiceOption, FormPage, FormSchema, DisplayCondition, JsonValue, SchemaIssue, FormPolicy, Question, FieldOption, TranslationReport, ValidationIssue, ValidationError, FormValues, LocaleOption, TranslationSlot, CanonicalTranslationMetadata, TranslationAdapter, AsyncTranslationAdapter, PopulateTranslationOptions, FormValue, AnswerValidationResult, FormEngineTranslator, FormEngineMessages, FieldType } from '@form-engine-ts/core';
|
|
3
3
|
export { QuestionType } from '@form-engine-ts/core';
|
|
4
4
|
import * as react from 'react';
|
|
5
5
|
import { ReactNode, ComponentType, KeyboardEvent, MouseEvent, CSSProperties } from 'react';
|
|
@@ -417,6 +417,29 @@ interface TranslationWorkspaceActionsProps {
|
|
|
417
417
|
readonly isTranslating: boolean;
|
|
418
418
|
readonly readOnly: boolean;
|
|
419
419
|
}
|
|
420
|
+
interface TranslationEventPayload {
|
|
421
|
+
readonly sourceLocale: string;
|
|
422
|
+
readonly targetLocale: string;
|
|
423
|
+
readonly mode: "manual" | "automatic";
|
|
424
|
+
readonly updatedSlots: readonly TranslationSlot[];
|
|
425
|
+
readonly skippedSlots: readonly TranslationSlot[];
|
|
426
|
+
readonly missingSlotsCount: number;
|
|
427
|
+
}
|
|
428
|
+
interface TranslationSlotChangeEvent {
|
|
429
|
+
readonly slot: TranslationSlot;
|
|
430
|
+
readonly previousText?: string;
|
|
431
|
+
readonly nextText: string;
|
|
432
|
+
readonly mode: "manual" | "automatic";
|
|
433
|
+
readonly metadata: CanonicalTranslationMetadata;
|
|
434
|
+
}
|
|
435
|
+
interface ConfirmRemoveLocaleSlotProps {
|
|
436
|
+
readonly locale: string;
|
|
437
|
+
readonly localeLabel: string;
|
|
438
|
+
readonly translatedSlotsCount: number;
|
|
439
|
+
readonly isOpen: boolean;
|
|
440
|
+
readonly onConfirm: () => void;
|
|
441
|
+
readonly onCancel: () => void;
|
|
442
|
+
}
|
|
420
443
|
interface TranslationWorkspaceSlots {
|
|
421
444
|
readonly renderHeader?: (props: TranslationWorkspaceHeaderProps) => ReactNode;
|
|
422
445
|
readonly renderSlotRow?: (props: TranslationSlotRowProps) => ReactNode;
|
|
@@ -425,6 +448,7 @@ interface TranslationWorkspaceSlots {
|
|
|
425
448
|
readonly status: _form_engine_ts_core.TranslationStatus;
|
|
426
449
|
}) => ReactNode;
|
|
427
450
|
readonly renderActions?: (props: TranslationWorkspaceActionsProps) => ReactNode;
|
|
451
|
+
readonly confirmRemoveLocale?: (props: ConfirmRemoveLocaleSlotProps) => ReactNode;
|
|
428
452
|
}
|
|
429
453
|
interface LocalizationSummaryContext {
|
|
430
454
|
readonly defaultLocale: string;
|
|
@@ -762,6 +786,18 @@ interface UseTranslationWorkspaceOptions {
|
|
|
762
786
|
readonly beforeRemoveLocale?: (locale: string, context: {
|
|
763
787
|
readonly slotCount: number;
|
|
764
788
|
}) => Promise<boolean> | boolean;
|
|
789
|
+
readonly confirmRemoveLocale?: (props: ConfirmRemoveLocaleSlotProps) => ReactNode;
|
|
790
|
+
readonly slots?: Pick<TranslationWorkspaceSlots, "confirmRemoveLocale">;
|
|
791
|
+
readonly onTranslationStart?: (params: {
|
|
792
|
+
readonly targetLocale: string;
|
|
793
|
+
readonly mode: "manual" | "automatic";
|
|
794
|
+
}) => void;
|
|
795
|
+
readonly onTranslationSuccess?: (payload: TranslationEventPayload) => void;
|
|
796
|
+
readonly onTranslationError?: (params: {
|
|
797
|
+
readonly targetLocale: string;
|
|
798
|
+
readonly error: TranslationWorkspaceError;
|
|
799
|
+
}) => void;
|
|
800
|
+
readonly onTranslationChange?: (event: TranslationSlotChangeEvent) => void;
|
|
765
801
|
readonly validateLocale?: ((locale: string, currentLocales: readonly string[]) => LocaleValidationResult) | CustomLocaleValidator;
|
|
766
802
|
}
|
|
767
803
|
interface LocaleValidationContext {
|
|
@@ -827,6 +863,7 @@ interface UseTranslationWorkspaceResult {
|
|
|
827
863
|
};
|
|
828
864
|
readonly isAddLocaleAllowed: (locale: string) => boolean;
|
|
829
865
|
readonly removeLocale: (locale: string) => boolean | Promise<boolean>;
|
|
866
|
+
readonly removeLocaleConfirmation?: ReactNode;
|
|
830
867
|
readonly setTranslation: (slot: TranslationSlot, text: string) => void;
|
|
831
868
|
readonly translateAll: (options?: PopulateTranslationOptions) => Promise<{
|
|
832
869
|
readonly success: boolean;
|
|
@@ -841,7 +878,7 @@ interface UseTranslationWorkspaceResult {
|
|
|
841
878
|
readonly error?: TranslationWorkspaceError;
|
|
842
879
|
}
|
|
843
880
|
declare const validateLocalePipeline: (locale: string, schema: FormSchema, policy?: FormPolicy, customValidator?: ((locale: string, currentLocales: readonly string[]) => LocaleValidationResult) | CustomLocaleValidator, availableLocales?: readonly (string | LocaleOption)[]) => LocaleValidationResult;
|
|
844
|
-
declare function useTranslationWorkspace({ schema, onChange, sourceLocale, targetLocale, translationAdapter, readOnly, policy, availableLocales, onLocaleAdded, onLocaleRemoved, onLocaleChange, beforeRemoveLocale, validateLocale }: UseTranslationWorkspaceOptions): UseTranslationWorkspaceResult;
|
|
881
|
+
declare function useTranslationWorkspace({ schema, onChange, sourceLocale, targetLocale, translationAdapter, readOnly, policy, availableLocales, onLocaleAdded, onLocaleRemoved, onLocaleChange, beforeRemoveLocale, confirmRemoveLocale, slots: workspaceSlots, onTranslationStart, onTranslationSuccess, onTranslationError, onTranslationChange, validateLocale }: UseTranslationWorkspaceOptions): UseTranslationWorkspaceResult;
|
|
845
882
|
|
|
846
883
|
declare const BUILDER_TRANSLATION_KEYS: {
|
|
847
884
|
readonly ADD_FIELD: "builder.actions.addField";
|
|
@@ -931,4 +968,4 @@ interface StandaloneFormRendererProps extends FormRendererPresentationProps {
|
|
|
931
968
|
type FormRendererProps = FormRendererPresentationProps | StandaloneFormRendererProps;
|
|
932
969
|
declare function FormRenderer(props: FormRendererProps): react.JSX.Element;
|
|
933
970
|
|
|
934
|
-
export { BUILDER_TRANSLATION_ALIASES, BUILDER_TRANSLATION_KEYS, type BeforeSubmit, type BuilderActionContext, type BuilderActionError, type BuilderActionIconType, type BuilderActionResult, type BuilderButtonProps, type BuilderCheckboxProps, type BuilderErrorMessageProps, type BuilderFactories, type BuilderFieldEditorSlotProps, type BuilderFieldsetProps, type BuilderIconButtonProps, type BuilderIdKind, type BuilderLocalizationSlotProps, type BuilderOptionEditorSlotProps, type BuilderPagesSlotProps, type BuilderPolicy, type BuilderSectionProps, type BuilderSelectOption, type BuilderSelectProps, type BuilderSlotActions, type BuilderTextAreaProps, type BuilderTextInputProps, type BuilderTextTarget, type BuilderToolbarSlotProps, type BuilderTranslationActionsSlotProps, type BuilderTranslationKey, type ChoiceFieldLayoutMode, type ChoiceFieldTypeLayoutMap, type ChoiceGroupSlotProps, type ComponentBaseProps, type CustomLocaleValidator, type FieldComponentProps, type FieldComponents, type FieldEditorControlsConfig, type FieldEditorHeaderSlotProps, type FieldEditorMode, type FieldError, type FieldPropertyControlMode, type FieldState, type FieldTypeSelectOptionsConfig, type FieldTypeSelectOptionsContext, type FieldTypeSelectOptionsSorter, type FieldTypeSelectOptionsTransformer, type FieldTypeSelectSlotProps, FormBuilder, type FormBuilderActions, type FormBuilderComponents, type FormBuilderFeatures, type FormBuilderOptions, type FormBuilderProps, type FormBuilderResult, type FormBuilderSectionName, type FormBuilderSlots, type FormBuilderSubmissionSettingsOptions, type FormCompletionSlotProps, type FormContextValue, FormEngineI18nContext, type FormEngineI18nContextValue, FormEngineI18nProvider, type FormEngineI18nProviderProps, type FormFieldsSlotProps, FormProvider, type FormProviderProps, FormRenderer, type FormRendererAppearance, type FormRendererMessages, type FormRendererPresentationProps, type FormRendererProps, type FormRendererSlotProps, type FormRendererSlots, type FormServerErrorPayload, FormSubmissionError, type FormSubmitHandler, type FormSubmitState, type FormSubmitStatus, type FormSubmittedAnswerItem, type FormSuccessRenderMode, type IconButtonProps, type InputComponentProps, type LocaleSelectorProps, type LocaleValidationContext, type LocaleValidationResult, type LocalizationSummaryContext, type ManualTranslationContext, type ManualTranslationTarget, type RenderSubmitButtonProps, type SelectComponentProps, type StandaloneFormRendererProps, type SubmissionAttempt, type SubmissionAttemptStore, type SubmissionConfirmationOptions, type SubmissionConfirmationRenderMode, type SubmissionConfirmationSlotProps, type SubmissionGuard, type SubmissionGuardResult, type SubmissionProtectionProps, type SubmissionReceipt, type SubmissionReceiptQuery, type SubmissionReceiptStore, type SubmitContext, type SubmitResponse, type SubmitResult, type SubmitStatus, type TranslationSlotRowProps, type TranslationSummary, type TranslationWorkspaceActionsProps, type TranslationWorkspaceError, type TranslationWorkspaceHeaderProps, type TranslationWorkspaceSlots, type UseFormBuilderOptions, type UseFormBuilderResult, type UseSubmissionReceiptsResult, type UseTranslationWorkspaceOptions, type UseTranslationWorkspaceResult, createLocalStorageSubmissionAttemptStore, createLocalStorageSubmissionReceiptStore, isTranslationUnresolved, resolveChoiceFieldLayout, resolveFieldEditorControls, resolveFieldTypeSelectOptions, resolveInitialFieldType, resolveTranslation, submissionReceiptQueryKey, useField, useForm, useFormBuilder, useFormEngineI18n, useSubmissionReceipts, useTranslationWorkspace, validateLocalePipeline };
|
|
971
|
+
export { BUILDER_TRANSLATION_ALIASES, BUILDER_TRANSLATION_KEYS, type BeforeSubmit, type BuilderActionContext, type BuilderActionError, type BuilderActionIconType, type BuilderActionResult, type BuilderButtonProps, type BuilderCheckboxProps, type BuilderErrorMessageProps, type BuilderFactories, type BuilderFieldEditorSlotProps, type BuilderFieldsetProps, type BuilderIconButtonProps, type BuilderIdKind, type BuilderLocalizationSlotProps, type BuilderOptionEditorSlotProps, type BuilderPagesSlotProps, type BuilderPolicy, type BuilderSectionProps, type BuilderSelectOption, type BuilderSelectProps, type BuilderSlotActions, type BuilderTextAreaProps, type BuilderTextInputProps, type BuilderTextTarget, type BuilderToolbarSlotProps, type BuilderTranslationActionsSlotProps, type BuilderTranslationKey, type ChoiceFieldLayoutMode, type ChoiceFieldTypeLayoutMap, type ChoiceGroupSlotProps, type ComponentBaseProps, type ConfirmRemoveLocaleSlotProps, type CustomLocaleValidator, type FieldComponentProps, type FieldComponents, type FieldEditorControlsConfig, type FieldEditorHeaderSlotProps, type FieldEditorMode, type FieldError, type FieldPropertyControlMode, type FieldState, type FieldTypeSelectOptionsConfig, type FieldTypeSelectOptionsContext, type FieldTypeSelectOptionsSorter, type FieldTypeSelectOptionsTransformer, type FieldTypeSelectSlotProps, FormBuilder, type FormBuilderActions, type FormBuilderComponents, type FormBuilderFeatures, type FormBuilderOptions, type FormBuilderProps, type FormBuilderResult, type FormBuilderSectionName, type FormBuilderSlots, type FormBuilderSubmissionSettingsOptions, type FormCompletionSlotProps, type FormContextValue, FormEngineI18nContext, type FormEngineI18nContextValue, FormEngineI18nProvider, type FormEngineI18nProviderProps, type FormFieldsSlotProps, FormProvider, type FormProviderProps, FormRenderer, type FormRendererAppearance, type FormRendererMessages, type FormRendererPresentationProps, type FormRendererProps, type FormRendererSlotProps, type FormRendererSlots, type FormServerErrorPayload, FormSubmissionError, type FormSubmitHandler, type FormSubmitState, type FormSubmitStatus, type FormSubmittedAnswerItem, type FormSuccessRenderMode, type IconButtonProps, type InputComponentProps, type LocaleSelectorProps, type LocaleValidationContext, type LocaleValidationResult, type LocalizationSummaryContext, type ManualTranslationContext, type ManualTranslationTarget, type RenderSubmitButtonProps, type SelectComponentProps, type StandaloneFormRendererProps, type SubmissionAttempt, type SubmissionAttemptStore, type SubmissionConfirmationOptions, type SubmissionConfirmationRenderMode, type SubmissionConfirmationSlotProps, type SubmissionGuard, type SubmissionGuardResult, type SubmissionProtectionProps, type SubmissionReceipt, type SubmissionReceiptQuery, type SubmissionReceiptStore, type SubmitContext, type SubmitResponse, type SubmitResult, type SubmitStatus, type TranslationEventPayload, type TranslationSlotChangeEvent, type TranslationSlotRowProps, type TranslationSummary, type TranslationWorkspaceActionsProps, type TranslationWorkspaceError, type TranslationWorkspaceHeaderProps, type TranslationWorkspaceSlots, type UseFormBuilderOptions, type UseFormBuilderResult, type UseSubmissionReceiptsResult, type UseTranslationWorkspaceOptions, type UseTranslationWorkspaceResult, createLocalStorageSubmissionAttemptStore, createLocalStorageSubmissionReceiptStore, isTranslationUnresolved, resolveChoiceFieldLayout, resolveFieldEditorControls, resolveFieldTypeSelectOptions, resolveInitialFieldType, resolveTranslation, submissionReceiptQueryKey, useField, useForm, useFormBuilder, useFormEngineI18n, useSubmissionReceipts, useTranslationWorkspace, validateLocalePipeline };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as _form_engine_ts_core from '@form-engine-ts/core';
|
|
2
|
-
import { QuestionType, FormField, ChoiceOption, FormPage, FormSchema, DisplayCondition, JsonValue, SchemaIssue, FormPolicy, Question, FieldOption, TranslationReport, ValidationIssue, ValidationError, FormValues, LocaleOption, TranslationAdapter, AsyncTranslationAdapter, PopulateTranslationOptions, FormValue, AnswerValidationResult,
|
|
2
|
+
import { QuestionType, FormField, ChoiceOption, FormPage, FormSchema, DisplayCondition, JsonValue, SchemaIssue, FormPolicy, Question, FieldOption, TranslationReport, ValidationIssue, ValidationError, FormValues, LocaleOption, TranslationSlot, CanonicalTranslationMetadata, TranslationAdapter, AsyncTranslationAdapter, PopulateTranslationOptions, FormValue, AnswerValidationResult, FormEngineTranslator, FormEngineMessages, FieldType } from '@form-engine-ts/core';
|
|
3
3
|
export { QuestionType } from '@form-engine-ts/core';
|
|
4
4
|
import * as react from 'react';
|
|
5
5
|
import { ReactNode, ComponentType, KeyboardEvent, MouseEvent, CSSProperties } from 'react';
|
|
@@ -417,6 +417,29 @@ interface TranslationWorkspaceActionsProps {
|
|
|
417
417
|
readonly isTranslating: boolean;
|
|
418
418
|
readonly readOnly: boolean;
|
|
419
419
|
}
|
|
420
|
+
interface TranslationEventPayload {
|
|
421
|
+
readonly sourceLocale: string;
|
|
422
|
+
readonly targetLocale: string;
|
|
423
|
+
readonly mode: "manual" | "automatic";
|
|
424
|
+
readonly updatedSlots: readonly TranslationSlot[];
|
|
425
|
+
readonly skippedSlots: readonly TranslationSlot[];
|
|
426
|
+
readonly missingSlotsCount: number;
|
|
427
|
+
}
|
|
428
|
+
interface TranslationSlotChangeEvent {
|
|
429
|
+
readonly slot: TranslationSlot;
|
|
430
|
+
readonly previousText?: string;
|
|
431
|
+
readonly nextText: string;
|
|
432
|
+
readonly mode: "manual" | "automatic";
|
|
433
|
+
readonly metadata: CanonicalTranslationMetadata;
|
|
434
|
+
}
|
|
435
|
+
interface ConfirmRemoveLocaleSlotProps {
|
|
436
|
+
readonly locale: string;
|
|
437
|
+
readonly localeLabel: string;
|
|
438
|
+
readonly translatedSlotsCount: number;
|
|
439
|
+
readonly isOpen: boolean;
|
|
440
|
+
readonly onConfirm: () => void;
|
|
441
|
+
readonly onCancel: () => void;
|
|
442
|
+
}
|
|
420
443
|
interface TranslationWorkspaceSlots {
|
|
421
444
|
readonly renderHeader?: (props: TranslationWorkspaceHeaderProps) => ReactNode;
|
|
422
445
|
readonly renderSlotRow?: (props: TranslationSlotRowProps) => ReactNode;
|
|
@@ -425,6 +448,7 @@ interface TranslationWorkspaceSlots {
|
|
|
425
448
|
readonly status: _form_engine_ts_core.TranslationStatus;
|
|
426
449
|
}) => ReactNode;
|
|
427
450
|
readonly renderActions?: (props: TranslationWorkspaceActionsProps) => ReactNode;
|
|
451
|
+
readonly confirmRemoveLocale?: (props: ConfirmRemoveLocaleSlotProps) => ReactNode;
|
|
428
452
|
}
|
|
429
453
|
interface LocalizationSummaryContext {
|
|
430
454
|
readonly defaultLocale: string;
|
|
@@ -762,6 +786,18 @@ interface UseTranslationWorkspaceOptions {
|
|
|
762
786
|
readonly beforeRemoveLocale?: (locale: string, context: {
|
|
763
787
|
readonly slotCount: number;
|
|
764
788
|
}) => Promise<boolean> | boolean;
|
|
789
|
+
readonly confirmRemoveLocale?: (props: ConfirmRemoveLocaleSlotProps) => ReactNode;
|
|
790
|
+
readonly slots?: Pick<TranslationWorkspaceSlots, "confirmRemoveLocale">;
|
|
791
|
+
readonly onTranslationStart?: (params: {
|
|
792
|
+
readonly targetLocale: string;
|
|
793
|
+
readonly mode: "manual" | "automatic";
|
|
794
|
+
}) => void;
|
|
795
|
+
readonly onTranslationSuccess?: (payload: TranslationEventPayload) => void;
|
|
796
|
+
readonly onTranslationError?: (params: {
|
|
797
|
+
readonly targetLocale: string;
|
|
798
|
+
readonly error: TranslationWorkspaceError;
|
|
799
|
+
}) => void;
|
|
800
|
+
readonly onTranslationChange?: (event: TranslationSlotChangeEvent) => void;
|
|
765
801
|
readonly validateLocale?: ((locale: string, currentLocales: readonly string[]) => LocaleValidationResult) | CustomLocaleValidator;
|
|
766
802
|
}
|
|
767
803
|
interface LocaleValidationContext {
|
|
@@ -827,6 +863,7 @@ interface UseTranslationWorkspaceResult {
|
|
|
827
863
|
};
|
|
828
864
|
readonly isAddLocaleAllowed: (locale: string) => boolean;
|
|
829
865
|
readonly removeLocale: (locale: string) => boolean | Promise<boolean>;
|
|
866
|
+
readonly removeLocaleConfirmation?: ReactNode;
|
|
830
867
|
readonly setTranslation: (slot: TranslationSlot, text: string) => void;
|
|
831
868
|
readonly translateAll: (options?: PopulateTranslationOptions) => Promise<{
|
|
832
869
|
readonly success: boolean;
|
|
@@ -841,7 +878,7 @@ interface UseTranslationWorkspaceResult {
|
|
|
841
878
|
readonly error?: TranslationWorkspaceError;
|
|
842
879
|
}
|
|
843
880
|
declare const validateLocalePipeline: (locale: string, schema: FormSchema, policy?: FormPolicy, customValidator?: ((locale: string, currentLocales: readonly string[]) => LocaleValidationResult) | CustomLocaleValidator, availableLocales?: readonly (string | LocaleOption)[]) => LocaleValidationResult;
|
|
844
|
-
declare function useTranslationWorkspace({ schema, onChange, sourceLocale, targetLocale, translationAdapter, readOnly, policy, availableLocales, onLocaleAdded, onLocaleRemoved, onLocaleChange, beforeRemoveLocale, validateLocale }: UseTranslationWorkspaceOptions): UseTranslationWorkspaceResult;
|
|
881
|
+
declare function useTranslationWorkspace({ schema, onChange, sourceLocale, targetLocale, translationAdapter, readOnly, policy, availableLocales, onLocaleAdded, onLocaleRemoved, onLocaleChange, beforeRemoveLocale, confirmRemoveLocale, slots: workspaceSlots, onTranslationStart, onTranslationSuccess, onTranslationError, onTranslationChange, validateLocale }: UseTranslationWorkspaceOptions): UseTranslationWorkspaceResult;
|
|
845
882
|
|
|
846
883
|
declare const BUILDER_TRANSLATION_KEYS: {
|
|
847
884
|
readonly ADD_FIELD: "builder.actions.addField";
|
|
@@ -931,4 +968,4 @@ interface StandaloneFormRendererProps extends FormRendererPresentationProps {
|
|
|
931
968
|
type FormRendererProps = FormRendererPresentationProps | StandaloneFormRendererProps;
|
|
932
969
|
declare function FormRenderer(props: FormRendererProps): react.JSX.Element;
|
|
933
970
|
|
|
934
|
-
export { BUILDER_TRANSLATION_ALIASES, BUILDER_TRANSLATION_KEYS, type BeforeSubmit, type BuilderActionContext, type BuilderActionError, type BuilderActionIconType, type BuilderActionResult, type BuilderButtonProps, type BuilderCheckboxProps, type BuilderErrorMessageProps, type BuilderFactories, type BuilderFieldEditorSlotProps, type BuilderFieldsetProps, type BuilderIconButtonProps, type BuilderIdKind, type BuilderLocalizationSlotProps, type BuilderOptionEditorSlotProps, type BuilderPagesSlotProps, type BuilderPolicy, type BuilderSectionProps, type BuilderSelectOption, type BuilderSelectProps, type BuilderSlotActions, type BuilderTextAreaProps, type BuilderTextInputProps, type BuilderTextTarget, type BuilderToolbarSlotProps, type BuilderTranslationActionsSlotProps, type BuilderTranslationKey, type ChoiceFieldLayoutMode, type ChoiceFieldTypeLayoutMap, type ChoiceGroupSlotProps, type ComponentBaseProps, type CustomLocaleValidator, type FieldComponentProps, type FieldComponents, type FieldEditorControlsConfig, type FieldEditorHeaderSlotProps, type FieldEditorMode, type FieldError, type FieldPropertyControlMode, type FieldState, type FieldTypeSelectOptionsConfig, type FieldTypeSelectOptionsContext, type FieldTypeSelectOptionsSorter, type FieldTypeSelectOptionsTransformer, type FieldTypeSelectSlotProps, FormBuilder, type FormBuilderActions, type FormBuilderComponents, type FormBuilderFeatures, type FormBuilderOptions, type FormBuilderProps, type FormBuilderResult, type FormBuilderSectionName, type FormBuilderSlots, type FormBuilderSubmissionSettingsOptions, type FormCompletionSlotProps, type FormContextValue, FormEngineI18nContext, type FormEngineI18nContextValue, FormEngineI18nProvider, type FormEngineI18nProviderProps, type FormFieldsSlotProps, FormProvider, type FormProviderProps, FormRenderer, type FormRendererAppearance, type FormRendererMessages, type FormRendererPresentationProps, type FormRendererProps, type FormRendererSlotProps, type FormRendererSlots, type FormServerErrorPayload, FormSubmissionError, type FormSubmitHandler, type FormSubmitState, type FormSubmitStatus, type FormSubmittedAnswerItem, type FormSuccessRenderMode, type IconButtonProps, type InputComponentProps, type LocaleSelectorProps, type LocaleValidationContext, type LocaleValidationResult, type LocalizationSummaryContext, type ManualTranslationContext, type ManualTranslationTarget, type RenderSubmitButtonProps, type SelectComponentProps, type StandaloneFormRendererProps, type SubmissionAttempt, type SubmissionAttemptStore, type SubmissionConfirmationOptions, type SubmissionConfirmationRenderMode, type SubmissionConfirmationSlotProps, type SubmissionGuard, type SubmissionGuardResult, type SubmissionProtectionProps, type SubmissionReceipt, type SubmissionReceiptQuery, type SubmissionReceiptStore, type SubmitContext, type SubmitResponse, type SubmitResult, type SubmitStatus, type TranslationSlotRowProps, type TranslationSummary, type TranslationWorkspaceActionsProps, type TranslationWorkspaceError, type TranslationWorkspaceHeaderProps, type TranslationWorkspaceSlots, type UseFormBuilderOptions, type UseFormBuilderResult, type UseSubmissionReceiptsResult, type UseTranslationWorkspaceOptions, type UseTranslationWorkspaceResult, createLocalStorageSubmissionAttemptStore, createLocalStorageSubmissionReceiptStore, isTranslationUnresolved, resolveChoiceFieldLayout, resolveFieldEditorControls, resolveFieldTypeSelectOptions, resolveInitialFieldType, resolveTranslation, submissionReceiptQueryKey, useField, useForm, useFormBuilder, useFormEngineI18n, useSubmissionReceipts, useTranslationWorkspace, validateLocalePipeline };
|
|
971
|
+
export { BUILDER_TRANSLATION_ALIASES, BUILDER_TRANSLATION_KEYS, type BeforeSubmit, type BuilderActionContext, type BuilderActionError, type BuilderActionIconType, type BuilderActionResult, type BuilderButtonProps, type BuilderCheckboxProps, type BuilderErrorMessageProps, type BuilderFactories, type BuilderFieldEditorSlotProps, type BuilderFieldsetProps, type BuilderIconButtonProps, type BuilderIdKind, type BuilderLocalizationSlotProps, type BuilderOptionEditorSlotProps, type BuilderPagesSlotProps, type BuilderPolicy, type BuilderSectionProps, type BuilderSelectOption, type BuilderSelectProps, type BuilderSlotActions, type BuilderTextAreaProps, type BuilderTextInputProps, type BuilderTextTarget, type BuilderToolbarSlotProps, type BuilderTranslationActionsSlotProps, type BuilderTranslationKey, type ChoiceFieldLayoutMode, type ChoiceFieldTypeLayoutMap, type ChoiceGroupSlotProps, type ComponentBaseProps, type ConfirmRemoveLocaleSlotProps, type CustomLocaleValidator, type FieldComponentProps, type FieldComponents, type FieldEditorControlsConfig, type FieldEditorHeaderSlotProps, type FieldEditorMode, type FieldError, type FieldPropertyControlMode, type FieldState, type FieldTypeSelectOptionsConfig, type FieldTypeSelectOptionsContext, type FieldTypeSelectOptionsSorter, type FieldTypeSelectOptionsTransformer, type FieldTypeSelectSlotProps, FormBuilder, type FormBuilderActions, type FormBuilderComponents, type FormBuilderFeatures, type FormBuilderOptions, type FormBuilderProps, type FormBuilderResult, type FormBuilderSectionName, type FormBuilderSlots, type FormBuilderSubmissionSettingsOptions, type FormCompletionSlotProps, type FormContextValue, FormEngineI18nContext, type FormEngineI18nContextValue, FormEngineI18nProvider, type FormEngineI18nProviderProps, type FormFieldsSlotProps, FormProvider, type FormProviderProps, FormRenderer, type FormRendererAppearance, type FormRendererMessages, type FormRendererPresentationProps, type FormRendererProps, type FormRendererSlotProps, type FormRendererSlots, type FormServerErrorPayload, FormSubmissionError, type FormSubmitHandler, type FormSubmitState, type FormSubmitStatus, type FormSubmittedAnswerItem, type FormSuccessRenderMode, type IconButtonProps, type InputComponentProps, type LocaleSelectorProps, type LocaleValidationContext, type LocaleValidationResult, type LocalizationSummaryContext, type ManualTranslationContext, type ManualTranslationTarget, type RenderSubmitButtonProps, type SelectComponentProps, type StandaloneFormRendererProps, type SubmissionAttempt, type SubmissionAttemptStore, type SubmissionConfirmationOptions, type SubmissionConfirmationRenderMode, type SubmissionConfirmationSlotProps, type SubmissionGuard, type SubmissionGuardResult, type SubmissionProtectionProps, type SubmissionReceipt, type SubmissionReceiptQuery, type SubmissionReceiptStore, type SubmitContext, type SubmitResponse, type SubmitResult, type SubmitStatus, type TranslationEventPayload, type TranslationSlotChangeEvent, type TranslationSlotRowProps, type TranslationSummary, type TranslationWorkspaceActionsProps, type TranslationWorkspaceError, type TranslationWorkspaceHeaderProps, type TranslationWorkspaceSlots, type UseFormBuilderOptions, type UseFormBuilderResult, type UseSubmissionReceiptsResult, type UseTranslationWorkspaceOptions, type UseTranslationWorkspaceResult, createLocalStorageSubmissionAttemptStore, createLocalStorageSubmissionReceiptStore, isTranslationUnresolved, resolveChoiceFieldLayout, resolveFieldEditorControls, resolveFieldTypeSelectOptions, resolveInitialFieldType, resolveTranslation, submissionReceiptQueryKey, useField, useForm, useFormBuilder, useFormEngineI18n, useSubmissionReceipts, useTranslationWorkspace, validateLocalePipeline };
|
package/dist/index.js
CHANGED
|
@@ -3282,7 +3282,7 @@ import {
|
|
|
3282
3282
|
populateSchemaTranslations as populateSchemaTranslations2,
|
|
3283
3283
|
removeLocaleFromSchema
|
|
3284
3284
|
} from "@form-engine-ts/core";
|
|
3285
|
-
import { useCallback as useCallback3, useMemo as useMemo4, useState as useState4 } from "react";
|
|
3285
|
+
import { useCallback as useCallback3, useMemo as useMemo4, useRef as useRef2, useState as useState4 } from "react";
|
|
3286
3286
|
function updateTranslationMap(translations, locale, property, text) {
|
|
3287
3287
|
if (property === "label") return translations ?? {};
|
|
3288
3288
|
const current = translations?.[locale];
|
|
@@ -3394,26 +3394,27 @@ function workspaceLocaleValidationError(validation, currentLocales, requestedLoc
|
|
|
3394
3394
|
}
|
|
3395
3395
|
return { type: "custom_validation_failed", message: error.message };
|
|
3396
3396
|
}
|
|
3397
|
-
function
|
|
3397
|
+
function translationMetadata(sourceText, sourceLocale, mode) {
|
|
3398
3398
|
return {
|
|
3399
3399
|
sourceLocale,
|
|
3400
3400
|
sourceTextHash: computeSourceTextHash(sourceText),
|
|
3401
|
-
translationSource:
|
|
3402
|
-
editedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
3401
|
+
translationSource: mode,
|
|
3402
|
+
...mode === "manual" ? { editedAt: (/* @__PURE__ */ new Date()).toISOString() } : { translatedAt: (/* @__PURE__ */ new Date()).toISOString() }
|
|
3403
3403
|
};
|
|
3404
3404
|
}
|
|
3405
|
-
function setNodeMetadata(node, slot, text, sourceLocale) {
|
|
3405
|
+
function setNodeMetadata(node, slot, text, sourceLocale, mode) {
|
|
3406
3406
|
const localeMetadata = node.translationMetadata?.[slot.locale];
|
|
3407
|
-
const nextMetadata = text.trim().length === 0 ? Object.fromEntries(Object.entries(localeMetadata ?? {}).filter(([key]) => key !== slot.property)) : { ...localeMetadata, [slot.property]:
|
|
3407
|
+
const nextMetadata = text.trim().length === 0 ? Object.fromEntries(Object.entries(localeMetadata ?? {}).filter(([key]) => key !== slot.property)) : { ...localeMetadata, [slot.property]: translationMetadata(slot.sourceText, sourceLocale, mode) };
|
|
3408
3408
|
return { ...node, translationMetadata: { ...node.translationMetadata, [slot.locale]: nextMetadata } };
|
|
3409
3409
|
}
|
|
3410
|
-
function updateSchemaTranslation(schema, slot, text, sourceLocale) {
|
|
3410
|
+
function updateSchemaTranslation(schema, slot, text, sourceLocale, mode = "manual") {
|
|
3411
3411
|
if (slot.kind === "form") {
|
|
3412
3412
|
return setNodeMetadata(
|
|
3413
3413
|
{ ...schema, translations: updateTranslationMap(schema.translations, slot.locale, slot.property, text) },
|
|
3414
3414
|
slot,
|
|
3415
3415
|
text,
|
|
3416
|
-
sourceLocale
|
|
3416
|
+
sourceLocale,
|
|
3417
|
+
mode
|
|
3417
3418
|
);
|
|
3418
3419
|
}
|
|
3419
3420
|
if (slot.kind === "field") {
|
|
@@ -3422,7 +3423,7 @@ function updateSchemaTranslation(schema, slot, text, sourceLocale) {
|
|
|
3422
3423
|
fields: schema.fields.map((field) => {
|
|
3423
3424
|
if (field.id !== slot.nodeId) return field;
|
|
3424
3425
|
const translations = updateTranslationMap(field.translations, slot.locale, slot.property, text);
|
|
3425
|
-
return setNodeMetadata({ ...field, translations }, slot, text, sourceLocale);
|
|
3426
|
+
return setNodeMetadata({ ...field, translations }, slot, text, sourceLocale, mode);
|
|
3426
3427
|
})
|
|
3427
3428
|
};
|
|
3428
3429
|
}
|
|
@@ -3438,7 +3439,7 @@ function updateSchemaTranslation(schema, slot, text, sourceLocale) {
|
|
|
3438
3439
|
const translations = text.trim().length === 0 ? Object.fromEntries(
|
|
3439
3440
|
Object.entries(option.translations ?? {}).filter(([locale]) => locale !== slot.locale)
|
|
3440
3441
|
) : { ...option.translations, [slot.locale]: text };
|
|
3441
|
-
return setNodeMetadata({ ...option, translations }, slot, text, sourceLocale);
|
|
3442
|
+
return setNodeMetadata({ ...option, translations }, slot, text, sourceLocale, mode);
|
|
3442
3443
|
})
|
|
3443
3444
|
};
|
|
3444
3445
|
})
|
|
@@ -3450,7 +3451,7 @@ function updateSchemaTranslation(schema, slot, text, sourceLocale) {
|
|
|
3450
3451
|
pages: schema.pages.map((page) => {
|
|
3451
3452
|
if (page.id !== slot.nodeId) return page;
|
|
3452
3453
|
const translations = updateTranslationMap(page.translations, slot.locale, slot.property, text);
|
|
3453
|
-
return setNodeMetadata({ ...page, translations }, slot, text, sourceLocale);
|
|
3454
|
+
return setNodeMetadata({ ...page, translations }, slot, text, sourceLocale, mode);
|
|
3454
3455
|
})
|
|
3455
3456
|
}
|
|
3456
3457
|
};
|
|
@@ -3468,13 +3469,22 @@ function useTranslationWorkspace({
|
|
|
3468
3469
|
onLocaleRemoved,
|
|
3469
3470
|
onLocaleChange,
|
|
3470
3471
|
beforeRemoveLocale,
|
|
3472
|
+
confirmRemoveLocale,
|
|
3473
|
+
slots: workspaceSlots,
|
|
3474
|
+
onTranslationStart,
|
|
3475
|
+
onTranslationSuccess,
|
|
3476
|
+
onTranslationError,
|
|
3477
|
+
onTranslationChange,
|
|
3471
3478
|
validateLocale
|
|
3472
3479
|
}) {
|
|
3473
3480
|
const [draftSchema, setDraftSchema] = useState4(schema);
|
|
3474
3481
|
const [selectedLocale, setSelectedLocale] = useState4(normalizeLocale(targetLocale ?? "") ?? targetLocale ?? "");
|
|
3475
3482
|
const [isTranslating, setIsTranslating] = useState4(false);
|
|
3476
3483
|
const [error, setError] = useState4();
|
|
3484
|
+
const [pendingRemoval, setPendingRemoval] = useState4();
|
|
3485
|
+
const pendingRemovalResolver = useRef2(void 0);
|
|
3477
3486
|
const currentSchema = onChange === void 0 ? draftSchema : schema;
|
|
3487
|
+
const confirmRemoveLocaleRenderer = confirmRemoveLocale ?? workspaceSlots?.confirmRemoveLocale;
|
|
3478
3488
|
const targetLocales = useMemo4(() => {
|
|
3479
3489
|
const locales = collectSchemaLocales2(currentSchema).allUniqueLocales;
|
|
3480
3490
|
return [.../* @__PURE__ */ new Set([...currentSchema.supportedLocales ?? [], ...locales])].filter(
|
|
@@ -3524,9 +3534,17 @@ function useTranslationWorkspace({
|
|
|
3524
3534
|
const setTranslation = useCallback3(
|
|
3525
3535
|
(slot, text) => {
|
|
3526
3536
|
if (readOnly) return;
|
|
3527
|
-
|
|
3537
|
+
const metadata = translationMetadata(slot.sourceText, sourceLocale, "manual");
|
|
3538
|
+
commit(updateSchemaTranslation(currentSchema, slot, text, sourceLocale, "manual"));
|
|
3539
|
+
onTranslationChange?.({
|
|
3540
|
+
slot,
|
|
3541
|
+
...slot.existingText === void 0 ? {} : { previousText: slot.existingText },
|
|
3542
|
+
nextText: text,
|
|
3543
|
+
mode: "manual",
|
|
3544
|
+
metadata
|
|
3545
|
+
});
|
|
3528
3546
|
},
|
|
3529
|
-
[commit, currentSchema, readOnly, sourceLocale]
|
|
3547
|
+
[commit, currentSchema, onTranslationChange, readOnly, sourceLocale]
|
|
3530
3548
|
);
|
|
3531
3549
|
const addLocale = useCallback3(
|
|
3532
3550
|
(locale) => {
|
|
@@ -3587,21 +3605,36 @@ function useTranslationWorkspace({
|
|
|
3587
3605
|
onLocaleRemoved?.(normalized);
|
|
3588
3606
|
};
|
|
3589
3607
|
const slotCount = collectTranslationSlots(currentSchema, normalized).length;
|
|
3608
|
+
const translatedSlotsCount = collectTranslationSlots(currentSchema, normalized).filter(
|
|
3609
|
+
(slot) => slot.existingText !== void 0 && slot.existingText.trim().length > 0
|
|
3610
|
+
).length;
|
|
3611
|
+
const requestConfirmation = () => new Promise((resolve) => {
|
|
3612
|
+
pendingRemovalResolver.current = resolve;
|
|
3613
|
+
setPendingRemoval({
|
|
3614
|
+
locale: normalized,
|
|
3615
|
+
localeLabel: localeOptions.find((option) => option.locale === normalized)?.label ?? normalized,
|
|
3616
|
+
translatedSlotsCount
|
|
3617
|
+
});
|
|
3618
|
+
});
|
|
3619
|
+
const removeAfterApproval = () => {
|
|
3620
|
+
if (confirmRemoveLocaleRenderer === void 0) {
|
|
3621
|
+
remove();
|
|
3622
|
+
return true;
|
|
3623
|
+
}
|
|
3624
|
+
return requestConfirmation();
|
|
3625
|
+
};
|
|
3590
3626
|
if (beforeRemoveLocale === void 0) {
|
|
3591
|
-
|
|
3592
|
-
return true;
|
|
3627
|
+
return removeAfterApproval();
|
|
3593
3628
|
}
|
|
3594
3629
|
try {
|
|
3595
3630
|
const decision = beforeRemoveLocale(normalized, { slotCount });
|
|
3596
3631
|
if (typeof decision === "boolean") {
|
|
3597
3632
|
if (!decision) return false;
|
|
3598
|
-
|
|
3599
|
-
return true;
|
|
3633
|
+
return removeAfterApproval();
|
|
3600
3634
|
}
|
|
3601
3635
|
return decision.then((allowed) => {
|
|
3602
3636
|
if (!allowed) return false;
|
|
3603
|
-
|
|
3604
|
-
return true;
|
|
3637
|
+
return removeAfterApproval();
|
|
3605
3638
|
});
|
|
3606
3639
|
} catch (cause) {
|
|
3607
3640
|
const workspaceError = {
|
|
@@ -3613,8 +3646,45 @@ function useTranslationWorkspace({
|
|
|
3613
3646
|
return Promise.reject(cause);
|
|
3614
3647
|
}
|
|
3615
3648
|
},
|
|
3616
|
-
[
|
|
3649
|
+
[
|
|
3650
|
+
activeLocale,
|
|
3651
|
+
beforeRemoveLocale,
|
|
3652
|
+
commit,
|
|
3653
|
+
confirmRemoveLocaleRenderer,
|
|
3654
|
+
currentSchema,
|
|
3655
|
+
localeOptions,
|
|
3656
|
+
onLocaleRemoved,
|
|
3657
|
+
readOnly,
|
|
3658
|
+
sourceLocale
|
|
3659
|
+
]
|
|
3617
3660
|
);
|
|
3661
|
+
const confirmPendingRemoval = useCallback3(() => {
|
|
3662
|
+
const pending = pendingRemoval;
|
|
3663
|
+
const resolve = pendingRemovalResolver.current;
|
|
3664
|
+
if (pending === void 0 || resolve === void 0) return;
|
|
3665
|
+
pendingRemovalResolver.current = void 0;
|
|
3666
|
+
setPendingRemoval(void 0);
|
|
3667
|
+
commit(removeLocaleFromSchema(currentSchema, pending.locale));
|
|
3668
|
+
if (activeLocale === pending.locale) setSelectedLocale("");
|
|
3669
|
+
onLocaleRemoved?.(pending.locale);
|
|
3670
|
+
resolve(true);
|
|
3671
|
+
}, [activeLocale, commit, currentSchema, onLocaleRemoved, pendingRemoval]);
|
|
3672
|
+
const cancelPendingRemoval = useCallback3(() => {
|
|
3673
|
+
const resolve = pendingRemovalResolver.current;
|
|
3674
|
+
if (resolve === void 0) return;
|
|
3675
|
+
pendingRemovalResolver.current = void 0;
|
|
3676
|
+
setPendingRemoval(void 0);
|
|
3677
|
+
resolve(false);
|
|
3678
|
+
}, []);
|
|
3679
|
+
const removeLocaleConfirmation = useMemo4(() => {
|
|
3680
|
+
if (confirmRemoveLocaleRenderer === void 0 || pendingRemoval === void 0) return null;
|
|
3681
|
+
return confirmRemoveLocaleRenderer({
|
|
3682
|
+
...pendingRemoval,
|
|
3683
|
+
isOpen: true,
|
|
3684
|
+
onConfirm: confirmPendingRemoval,
|
|
3685
|
+
onCancel: cancelPendingRemoval
|
|
3686
|
+
});
|
|
3687
|
+
}, [cancelPendingRemoval, confirmPendingRemoval, confirmRemoveLocaleRenderer, pendingRemoval]);
|
|
3618
3688
|
const translateAll = useCallback3(
|
|
3619
3689
|
async (options = {}) => {
|
|
3620
3690
|
if (readOnly) {
|
|
@@ -3651,6 +3721,7 @@ function useTranslationWorkspace({
|
|
|
3651
3721
|
}
|
|
3652
3722
|
setIsTranslating(true);
|
|
3653
3723
|
setError(void 0);
|
|
3724
|
+
onTranslationStart?.({ targetLocale: activeLocale, mode: "automatic" });
|
|
3654
3725
|
try {
|
|
3655
3726
|
const populated = await populateSchemaTranslations2(
|
|
3656
3727
|
currentSchema,
|
|
@@ -3663,6 +3734,17 @@ function useTranslationWorkspace({
|
|
|
3663
3734
|
}
|
|
3664
3735
|
);
|
|
3665
3736
|
commit(populated.schema);
|
|
3737
|
+
const missingSlotsCount = collectTranslationSlots(populated.schema, activeLocale).filter(
|
|
3738
|
+
(slot) => slot.status === "missing"
|
|
3739
|
+
).length;
|
|
3740
|
+
onTranslationSuccess?.({
|
|
3741
|
+
sourceLocale,
|
|
3742
|
+
targetLocale: activeLocale,
|
|
3743
|
+
mode: "automatic",
|
|
3744
|
+
updatedSlots: populated.report.updatedSlots,
|
|
3745
|
+
skippedSlots: populated.report.skippedSlots,
|
|
3746
|
+
missingSlotsCount
|
|
3747
|
+
});
|
|
3666
3748
|
return { success: true, report: populated.report };
|
|
3667
3749
|
} catch (cause) {
|
|
3668
3750
|
const workspaceError = {
|
|
@@ -3671,12 +3753,25 @@ function useTranslationWorkspace({
|
|
|
3671
3753
|
cause
|
|
3672
3754
|
};
|
|
3673
3755
|
setError(workspaceError);
|
|
3756
|
+
onTranslationError?.({ targetLocale: activeLocale, error: workspaceError });
|
|
3674
3757
|
return { success: false, error: workspaceError };
|
|
3675
3758
|
} finally {
|
|
3676
3759
|
setIsTranslating(false);
|
|
3677
3760
|
}
|
|
3678
3761
|
},
|
|
3679
|
-
[
|
|
3762
|
+
[
|
|
3763
|
+
activeLocale,
|
|
3764
|
+
commit,
|
|
3765
|
+
currentSchema,
|
|
3766
|
+
localeOptions,
|
|
3767
|
+
onTranslationError,
|
|
3768
|
+
onTranslationStart,
|
|
3769
|
+
onTranslationSuccess,
|
|
3770
|
+
readOnly,
|
|
3771
|
+
slots,
|
|
3772
|
+
sourceLocale,
|
|
3773
|
+
translationAdapter
|
|
3774
|
+
]
|
|
3680
3775
|
);
|
|
3681
3776
|
const translateSlot = useCallback3(
|
|
3682
3777
|
async (slot) => {
|
|
@@ -3694,7 +3789,15 @@ function useTranslationWorkspace({
|
|
|
3694
3789
|
setError(void 0);
|
|
3695
3790
|
try {
|
|
3696
3791
|
const text = await asAsyncAdapter(translationAdapter).translateText(slot.sourceText, slot.locale, sourceLocale);
|
|
3697
|
-
|
|
3792
|
+
const metadata = translationMetadata(slot.sourceText, sourceLocale, "automatic");
|
|
3793
|
+
commit(updateSchemaTranslation(currentSchema, slot, text, sourceLocale, "automatic"));
|
|
3794
|
+
onTranslationChange?.({
|
|
3795
|
+
slot,
|
|
3796
|
+
...slot.existingText === void 0 ? {} : { previousText: slot.existingText },
|
|
3797
|
+
nextText: text,
|
|
3798
|
+
mode: "automatic",
|
|
3799
|
+
metadata
|
|
3800
|
+
});
|
|
3698
3801
|
return { success: true };
|
|
3699
3802
|
} catch (cause) {
|
|
3700
3803
|
const workspaceError = {
|
|
@@ -3708,7 +3811,7 @@ function useTranslationWorkspace({
|
|
|
3708
3811
|
setIsTranslating(false);
|
|
3709
3812
|
}
|
|
3710
3813
|
},
|
|
3711
|
-
[commit, currentSchema, readOnly, sourceLocale, translationAdapter]
|
|
3814
|
+
[commit, currentSchema, onTranslationChange, readOnly, sourceLocale, translationAdapter]
|
|
3712
3815
|
);
|
|
3713
3816
|
return {
|
|
3714
3817
|
sourceLocale,
|
|
@@ -3725,6 +3828,7 @@ function useTranslationWorkspace({
|
|
|
3725
3828
|
addLocale,
|
|
3726
3829
|
isAddLocaleAllowed,
|
|
3727
3830
|
removeLocale,
|
|
3831
|
+
...removeLocaleConfirmation === null ? {} : { removeLocaleConfirmation },
|
|
3728
3832
|
setTranslation,
|
|
3729
3833
|
translateAll,
|
|
3730
3834
|
translateSlot,
|
|
@@ -3862,7 +3966,7 @@ import {
|
|
|
3862
3966
|
useEffect as useEffect3,
|
|
3863
3967
|
useId,
|
|
3864
3968
|
useMemo as useMemo6,
|
|
3865
|
-
useRef as
|
|
3969
|
+
useRef as useRef3,
|
|
3866
3970
|
useState as useState6
|
|
3867
3971
|
} from "react";
|
|
3868
3972
|
import { Fragment as Fragment3, jsx as jsx4, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
@@ -4378,8 +4482,8 @@ function ContextFormRenderer({
|
|
|
4378
4482
|
const i18n = useFormEngineI18n();
|
|
4379
4483
|
const isProviderValue = useContext4(FormEngineI18nProviderScopeContext);
|
|
4380
4484
|
const prefix = useId().replace(/:/g, "");
|
|
4381
|
-
const formRef =
|
|
4382
|
-
const loadedDraftKey =
|
|
4485
|
+
const formRef = useRef3(null);
|
|
4486
|
+
const loadedDraftKey = useRef3(null);
|
|
4383
4487
|
const [draftRestored, setDraftRestored] = useState6(false);
|
|
4384
4488
|
const [currentPageIndex, setCurrentPageIndex] = useState6(0);
|
|
4385
4489
|
const [focusFieldId, setFocusFieldId] = useState6(null);
|
|
@@ -4389,10 +4493,10 @@ function ContextFormRenderer({
|
|
|
4389
4493
|
const [receipt, setReceipt] = useState6(null);
|
|
4390
4494
|
const [completionData, setCompletionData] = useState6(null);
|
|
4391
4495
|
const [receiptLoaded, setReceiptLoaded] = useState6(receiptStore === void 0);
|
|
4392
|
-
const rendererSubmissionInFlight =
|
|
4393
|
-
const fallbackAttemptId =
|
|
4394
|
-
const completionRef =
|
|
4395
|
-
const confirmationRef =
|
|
4496
|
+
const rendererSubmissionInFlight = useRef3(false);
|
|
4497
|
+
const fallbackAttemptId = useRef3(null);
|
|
4498
|
+
const completionRef = useRef3(null);
|
|
4499
|
+
const confirmationRef = useRef3(null);
|
|
4396
4500
|
const pages = form.schema.pages;
|
|
4397
4501
|
const visiblePageIndexes = useMemo6(
|
|
4398
4502
|
() => pages === void 0 ? [] : pages.flatMap((page, index) => form.pageVisibility[page.id] === true ? [index] : []),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@form-engine-ts/react",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "6.0.0",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
@@ -42,8 +42,8 @@
|
|
|
42
42
|
"typescript"
|
|
43
43
|
],
|
|
44
44
|
"dependencies": {
|
|
45
|
-
"@form-engine-ts/core": "
|
|
46
|
-
"@form-engine-ts/privacy": "
|
|
45
|
+
"@form-engine-ts/core": "6.0.0",
|
|
46
|
+
"@form-engine-ts/privacy": "6.0.0"
|
|
47
47
|
},
|
|
48
48
|
"peerDependencies": {
|
|
49
49
|
"react": ">=18.2 <20",
|