@toototech/webbuilder-plugins 0.1.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/LICENSE +1 -0
- package/README.md +3 -0
- package/dist/basic/cssScope.d.ts +3 -0
- package/dist/basic/index.d.ts +81 -0
- package/dist/basic/injectStyle.d.ts +20 -0
- package/dist/basic/plugin.d.ts +19 -0
- package/dist/basic/publisher.d.ts +4 -0
- package/dist/basic/registries/interactive/accordion/index.d.ts +3 -0
- package/dist/basic/registries/interactive/backButton/index.d.ts +3 -0
- package/dist/basic/registries/interactive/button/index.d.ts +10 -0
- package/dist/basic/registries/interactive/countUp/index.d.ts +9 -0
- package/dist/basic/registries/interactive/customCode/index.d.ts +3 -0
- package/dist/basic/registries/interactive/index.d.ts +2 -0
- package/dist/basic/registries/interactive/inquiryForm/index.d.ts +3 -0
- package/dist/basic/registries/interactive/klaviyoSubscribe/index.d.ts +3 -0
- package/dist/basic/registries/interactive/popup/index.d.ts +5 -0
- package/dist/basic/registries/interactive/salesmartlyChatButton/index.d.ts +10 -0
- package/dist/basic/registries/interactive/search/index.d.ts +10 -0
- package/dist/basic/registries/interactive/socialShare/index.d.ts +33 -0
- package/dist/basic/registries/interactive/tabs/index.d.ts +3 -0
- package/dist/basic/registries/layout/container/index.d.ts +19 -0
- package/dist/basic/registries/layout/divider/index.d.ts +7 -0
- package/dist/basic/registries/layout/grid/index.d.ts +11 -0
- package/dist/basic/registries/layout/index.d.ts +2 -0
- package/dist/basic/registries/layout/layoutBase/index.d.ts +10 -0
- package/dist/basic/registries/layout/section/index.d.ts +3 -0
- package/dist/basic/registries/layout/sectionGridBlock/index.d.ts +3 -0
- package/dist/basic/registries/layout/spacer/index.d.ts +7 -0
- package/dist/basic/registries/media/banner/index.d.ts +11 -0
- package/dist/basic/registries/media/carousel/index.d.ts +6 -0
- package/dist/basic/registries/media/flipbook/index.d.ts +5 -0
- package/dist/basic/registries/media/icon/index.d.ts +3 -0
- package/dist/basic/registries/media/image/index.d.ts +3 -0
- package/dist/basic/registries/media/index.d.ts +2 -0
- package/dist/basic/registries/media/industryTabs/index.d.ts +3 -0
- package/dist/basic/registries/media/marquee/index.d.ts +4 -0
- package/dist/basic/registries/media/ourSolutions/helpers.d.ts +289 -0
- package/dist/basic/registries/media/ourSolutions/index.d.ts +4 -0
- package/dist/basic/registries/media/ourSolutions/script.d.ts +1 -0
- package/dist/basic/registries/media/ourSolutions/style.d.ts +1 -0
- package/dist/basic/registries/media/pdfViewer/index.d.ts +3 -0
- package/dist/basic/registries/media/productCategories/index.d.ts +4 -0
- package/dist/basic/registries/media/tabMediaGallery/index.d.ts +3 -0
- package/dist/basic/registries/media/video/index.d.ts +12 -0
- package/dist/basic/registries/navigation/footer/index.d.ts +10 -0
- package/dist/basic/registries/navigation/index.d.ts +2 -0
- package/dist/basic/registries/navigation/languageSwitcher/index.d.ts +6 -0
- package/dist/basic/registries/navigation/logo/index.d.ts +9 -0
- package/dist/basic/registries/navigation/navbar/constants.d.ts +38 -0
- package/dist/basic/registries/navigation/navbar/factories.d.ts +848 -0
- package/dist/basic/registries/navigation/navbar/helpers.d.ts +12 -0
- package/dist/basic/registries/navigation/navbar/index.d.ts +4 -0
- package/dist/basic/registries/navigation/navbar/registerMegaTypes.d.ts +2 -0
- package/dist/basic/registries/navigation/navbar/registerMenuTypes.d.ts +2 -0
- package/dist/basic/registries/navigation/navbar/registerRootTypes.d.ts +2 -0
- package/dist/basic/registries/navigation/navbar/script.d.ts +1 -0
- package/dist/basic/registries/navigation/navbar/style.d.ts +1 -0
- package/dist/basic/registries/navigation/socialLinks/index.d.ts +3 -0
- package/dist/basic/registries/section/allApplications/index.d.ts +3 -0
- package/dist/basic/registries/section/cardCarouselSection/index.d.ts +3 -0
- package/dist/basic/registries/section/caseSpotlight/index.d.ts +3 -0
- package/dist/basic/registries/section/companyScale/index.d.ts +3 -0
- package/dist/basic/registries/section/customizationGrid/index.d.ts +3 -0
- package/dist/basic/registries/section/factoryMap/index.d.ts +3 -0
- package/dist/basic/registries/section/focaHistoryTimeline/index.d.ts +3 -0
- package/dist/basic/registries/section/historyTimeline/index.d.ts +3 -0
- package/dist/basic/registries/section/homeBannerCarousel/index.d.ts +4 -0
- package/dist/basic/registries/section/hotspotShowcase/index.d.ts +30 -0
- package/dist/basic/registries/section/index.d.ts +2 -0
- package/dist/basic/registries/section/map/index.d.ts +4 -0
- package/dist/basic/registries/section/milestoneCardStrip/index.d.ts +3 -0
- package/dist/basic/registries/section/moreCardCarousel/index.d.ts +3 -0
- package/dist/basic/registries/section/ourAdvantages/index.d.ts +4 -0
- package/dist/basic/registries/section/overviewSplit/index.d.ts +3 -0
- package/dist/basic/registries/section/processTimeline/index.d.ts +3 -0
- package/dist/basic/registries/section/productCardStrip/index.d.ts +3 -0
- package/dist/basic/registries/section/resourceSection/index.d.ts +6 -0
- package/dist/basic/registries/section/responsiveHeroCarousel/index.d.ts +4 -0
- package/dist/basic/registries/section/serviceIconGrid/index.d.ts +4 -0
- package/dist/basic/registries/section/servicesCarousel/index.d.ts +4 -0
- package/dist/basic/registries/section/servicesShowcase/index.d.ts +4 -0
- package/dist/basic/registries/section/servicesThb/index.d.ts +4 -0
- package/dist/basic/registries/section/solutionList/index.d.ts +4 -0
- package/dist/basic/registries/section/staticPinMap/index.d.ts +4 -0
- package/dist/basic/registries/section/statsCards/index.d.ts +3 -0
- package/dist/basic/registries/section/swiperRuntime.d.ts +3 -0
- package/dist/basic/registries/shared/sharedTraits.d.ts +37 -0
- package/dist/basic/registries/types.d.ts +5 -0
- package/dist/basic/registries/typography/heading/index.d.ts +8 -0
- package/dist/basic/registries/typography/index.d.ts +2 -0
- package/dist/basic/registries/typography/textEditor/index.d.ts +6 -0
- package/dist/basic/registryManifest.d.ts +9 -0
- package/dist/basic/styleHelpers.d.ts +29 -0
- package/dist/basic/svgIcon.d.ts +11 -0
- package/dist/basic/traitBridge.d.ts +20 -0
- package/dist/basic/traitFactory.d.ts +106 -0
- package/dist/basic.js +1146 -0
- package/dist/cms/cmsFactory.d.ts +164 -0
- package/dist/cms/dynamicRenderPipeline.d.ts +12 -0
- package/dist/cms/index.d.ts +31 -0
- package/dist/cms/plugin.d.ts +12 -0
- package/dist/cms/publisher.d.ts +7 -0
- package/dist/cms/registries/dynamic/cms/constants.d.ts +16 -0
- package/dist/cms/registries/dynamic/cms/dynamicField/bindings.d.ts +78 -0
- package/dist/cms/registries/dynamic/cms/dynamicField/blocks/breadcrumbBlock.d.ts +1 -0
- package/dist/cms/registries/dynamic/cms/dynamicField/blocks/conditionalBlock.d.ts +1 -0
- package/dist/cms/registries/dynamic/cms/dynamicField/blocks/datetimeBlock.d.ts +1 -0
- package/dist/cms/registries/dynamic/cms/dynamicField/blocks/htmlBlock.d.ts +1 -0
- package/dist/cms/registries/dynamic/cms/dynamicField/blocks/imageBlock.d.ts +1 -0
- package/dist/cms/registries/dynamic/cms/dynamicField/blocks/linkBlock.d.ts +1 -0
- package/dist/cms/registries/dynamic/cms/dynamicField/blocks/seoBlock.d.ts +1 -0
- package/dist/cms/registries/dynamic/cms/dynamicField/blocks/textBlock.d.ts +1 -0
- package/dist/cms/registries/dynamic/cms/dynamicField/blocks/tocBlock.d.ts +1 -0
- package/dist/cms/registries/dynamic/cms/dynamicField/constants.d.ts +19 -0
- package/dist/cms/registries/dynamic/cms/dynamicField/helpers.d.ts +52 -0
- package/dist/cms/registries/dynamic/cms/dynamicField/registerBlock.d.ts +57 -0
- package/dist/cms/registries/dynamic/cms/dynamicField/styles.d.ts +7 -0
- package/dist/cms/registries/dynamic/cms/media/previewMediaTrait.d.ts +7 -0
- package/dist/cms/registries/dynamic/cms/menu/siteMenuAttrs.d.ts +11 -0
- package/dist/cms/registries/dynamic/cms/menuTree/menuTreeAttrs.d.ts +8 -0
- package/dist/cms/registries/dynamic/cms/post/styles.d.ts +6 -0
- package/dist/cms/registries/dynamic/cms/product/detail.styles.d.ts +1 -0
- package/dist/cms/registries/dynamic/cms/product/detailV2.styles.d.ts +1 -0
- package/dist/cms/registries/dynamic/cms/product/previewProductTrait.d.ts +6 -0
- package/dist/cms/registries/dynamic/cms/product/styles.d.ts +6 -0
- package/dist/cms/registries/dynamic/dataProvider.d.ts +45 -0
- package/dist/cms/registries/dynamic/loopGrid/paginationStyles.d.ts +5 -0
- package/dist/cms/registries/dynamic/loopGrid/preview.d.ts +16 -0
- package/dist/cms/registries/dynamic/loopGrid/publisher.d.ts +3 -0
- package/dist/cms/registries/dynamic/loopGrid/types.d.ts +97 -0
- package/dist/cms/registries/navigation/navbarThb/index.d.ts +3 -0
- package/dist/cms/registries/navigation/navbarThb/script.d.ts +1 -0
- package/dist/cms/registries/navigation/navbarThb/style.d.ts +1 -0
- package/dist/cms.js +4535 -0
- package/dist/global-settings/components/FontFamilySelect.vue.d.ts +29 -0
- package/dist/global-settings/components/FontManagerPanel.vue.d.ts +37 -0
- package/dist/global-settings/index.d.ts +8 -0
- package/dist/global-settings/plugin.d.ts +3 -0
- package/dist/global-settings/publisher.d.ts +15 -0
- package/dist/global-settings/runtime/canvasInjection.d.ts +13 -0
- package/dist/global-settings/runtime/panelDraftSave.d.ts +17 -0
- package/dist/global-settings/runtime/settingsSource.d.ts +4 -0
- package/dist/global-settings/useFontManager.d.ts +38 -0
- package/dist/global-settings/useGoogleFonts.d.ts +20 -0
- package/dist/global-settings/vue.d.ts +1 -0
- package/dist/global-settings.js +66 -0
- package/dist/i18n/I18nPanel.vue.d.ts +23 -0
- package/dist/i18n/i18n.d.ts +25 -0
- package/dist/i18n/index.d.ts +7 -0
- package/dist/i18n/languageOrder.d.ts +9 -0
- package/dist/i18n/plugin.d.ts +21 -0
- package/dist/i18n/types.d.ts +101 -0
- package/dist/i18n/useWebBuilderI18n.d.ts +164 -0
- package/dist/i18n/vue.d.ts +1 -0
- package/dist/i18n-BYR3l48y.js +959 -0
- package/dist/i18n.js +929 -0
- package/dist/index-CxJlLwvG.js +35378 -0
- package/dist/index-DWfJ4PBm.js +5724 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.js +12 -0
- package/dist/layout-template/components/LayoutPanel.vue.d.ts +37 -0
- package/dist/layout-template/components/TemplateRulesPanel.vue.d.ts +41 -0
- package/dist/layout-template/config/layoutSharedResources.d.ts +9 -0
- package/dist/layout-template/config/templateSharedResources.d.ts +28 -0
- package/dist/layout-template/index.d.ts +9 -0
- package/dist/layout-template/plugin.d.ts +13 -0
- package/dist/layout-template/runtime/storageAdapter.d.ts +49 -0
- package/dist/layout-template/utils/layoutProjectData.d.ts +15 -0
- package/dist/layout-template/utils/layoutRulePages.d.ts +19 -0
- package/dist/layout-template/utils/layoutSettings.d.ts +45 -0
- package/dist/layout-template/utils/templateRules.d.ts +52 -0
- package/dist/layout-template/vue.d.ts +2 -0
- package/dist/layout-template.js +435 -0
- package/dist/layoutSettings-D4SYUMri.js +252 -0
- package/dist/plugin-BPA8qlaC.js +40 -0
- package/dist/plugin-C0PrxrIe.js +228 -0
- package/dist/plugin-DQshk1sY.js +361 -0
- package/dist/plugin-DebyCjXx.js +191 -0
- package/dist/plugin-Dr6TOtyH.js +73 -0
- package/dist/publisher/index.d.ts +5 -0
- package/dist/publisher/publisherAssets.d.ts +9 -0
- package/dist/publisher/publisherComponents.d.ts +7 -0
- package/dist/publisher/publisherPlugins.d.ts +12 -0
- package/dist/publisher-C6VWXq8u.js +25 -0
- package/dist/publisher.js +1711 -0
- package/dist/solar-BsElUqfQ.js +29843 -0
- package/dist/style.css +1181 -0
- package/dist/templateSharedResources-D1u7eFIs.js +89 -0
- package/dist/types-DNbok59z.js +2359 -0
- package/dist/useFontManager-CdrLq1eG.js +336 -0
- package/dist/vue.d.ts +3 -0
- package/dist/vue.js +2171 -0
- package/package.json +77 -0
package/dist/i18n.js
ADDED
|
@@ -0,0 +1,929 @@
|
|
|
1
|
+
import { I, a, c, c as c2 } from "./plugin-Dr6TOtyH.js";
|
|
2
|
+
import { m as mergeI18nEntries, g as getWebBuilderI18nEntryId, r as resolveI18nEntryStatus, e as ensureModelI18nKeys, a as extractI18nEntriesFromProjectData, i as isUnchangedNonIdentityTranslation, b as applyI18nTranslationsToProjectData, W as WB_I18N_KEY_ATTR } from "./i18n-BYR3l48y.js";
|
|
3
|
+
import { c as c3, d, h, f, j, k, s, l } from "./i18n-BYR3l48y.js";
|
|
4
|
+
import { ref, computed, unref, watch } from "vue";
|
|
5
|
+
const toFiniteNumber = (value, fallback) => {
|
|
6
|
+
const numberValue = Number(value);
|
|
7
|
+
return Number.isFinite(numberValue) ? numberValue : fallback;
|
|
8
|
+
};
|
|
9
|
+
const compareLanguagesByOrder = (left, right) => {
|
|
10
|
+
const leftSortOrder = toFiniteNumber(left.sortOrder, Number.MAX_SAFE_INTEGER);
|
|
11
|
+
const rightSortOrder = toFiniteNumber(right.sortOrder, Number.MAX_SAFE_INTEGER);
|
|
12
|
+
if (leftSortOrder !== rightSortOrder)
|
|
13
|
+
return leftSortOrder - rightSortOrder;
|
|
14
|
+
const leftId = toFiniteNumber(left.id, Number.MAX_SAFE_INTEGER);
|
|
15
|
+
const rightId = toFiniteNumber(right.id, Number.MAX_SAFE_INTEGER);
|
|
16
|
+
if (leftId !== rightId)
|
|
17
|
+
return leftId - rightId;
|
|
18
|
+
const leftLabel = `${left.code || left.slug || left.name || ""}`;
|
|
19
|
+
const rightLabel = `${right.code || right.slug || right.name || ""}`;
|
|
20
|
+
return leftLabel.localeCompare(rightLabel);
|
|
21
|
+
};
|
|
22
|
+
const sortLanguagesByOrder = (languages) => {
|
|
23
|
+
return Array.isArray(languages) ? [...languages].sort(compareLanguagesByOrder) : [];
|
|
24
|
+
};
|
|
25
|
+
const normalizeEntries = (bundle) => {
|
|
26
|
+
return Array.isArray(bundle == null ? void 0 : bundle.entries) ? bundle.entries : [];
|
|
27
|
+
};
|
|
28
|
+
const noopMessage = {
|
|
29
|
+
success: () => void 0,
|
|
30
|
+
warning: () => void 0,
|
|
31
|
+
info: () => void 0,
|
|
32
|
+
error: () => void 0
|
|
33
|
+
};
|
|
34
|
+
const fallbackHostUi = {
|
|
35
|
+
confirm: async () => false,
|
|
36
|
+
message: noopMessage
|
|
37
|
+
};
|
|
38
|
+
const normalizeLanguageValue = (language) => `${language.code || language.slug || ""}`.trim();
|
|
39
|
+
const languageCodeLabel = (language) => `${language.code || language.slug || ""}`.trim();
|
|
40
|
+
const hasOwn = (source, key) => Object.prototype.hasOwnProperty.call(source, key);
|
|
41
|
+
const normalizeString = (value) => {
|
|
42
|
+
if (typeof value !== "string")
|
|
43
|
+
return void 0;
|
|
44
|
+
const normalized = value.trim();
|
|
45
|
+
return normalized ? normalized : void 0;
|
|
46
|
+
};
|
|
47
|
+
const normalizeNumber = (value) => {
|
|
48
|
+
if (typeof value === "number" && Number.isFinite(value))
|
|
49
|
+
return value;
|
|
50
|
+
if (typeof value !== "string")
|
|
51
|
+
return void 0;
|
|
52
|
+
const normalized = value.trim();
|
|
53
|
+
if (!normalized)
|
|
54
|
+
return void 0;
|
|
55
|
+
const parsed = Number(normalized);
|
|
56
|
+
return Number.isFinite(parsed) ? parsed : void 0;
|
|
57
|
+
};
|
|
58
|
+
const hasPageResourceLocator = (identity) => {
|
|
59
|
+
const resourceId = normalizeNumber(identity == null ? void 0 : identity.resourceId);
|
|
60
|
+
const resourceKey = normalizeString(identity == null ? void 0 : identity.resourceKey);
|
|
61
|
+
const resourceType = normalizeString(identity == null ? void 0 : identity.resourceType);
|
|
62
|
+
const ownerId = normalizeNumber(identity == null ? void 0 : identity.ownerId);
|
|
63
|
+
const ownerType = normalizeString(identity == null ? void 0 : identity.ownerType) || (ownerId !== void 0 ? resourceType : void 0);
|
|
64
|
+
return Boolean(resourceId !== void 0 || resourceKey || ownerType && ownerId !== void 0);
|
|
65
|
+
};
|
|
66
|
+
const isLayoutPageResource = (identity) => {
|
|
67
|
+
const resourceType = `${identity.resourceType ?? ""}`.trim();
|
|
68
|
+
return resourceType === "LAYOUT_PAGE_HEADER" || resourceType === "LAYOUT_PAGE_FOOTER";
|
|
69
|
+
};
|
|
70
|
+
const I18N_DRAFT_STORAGE_PREFIX = "wb:i18n:drafts:v1";
|
|
71
|
+
const getLocalStorage = () => {
|
|
72
|
+
try {
|
|
73
|
+
return typeof window === "undefined" ? null : window.localStorage;
|
|
74
|
+
} catch {
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
const resourceSignature = (resource) => [
|
|
79
|
+
resource.resourceId ?? "",
|
|
80
|
+
resource.resourceKey ?? "",
|
|
81
|
+
resource.resourceType ?? "",
|
|
82
|
+
resource.resourceScope ?? "",
|
|
83
|
+
resource.ownerType ?? "",
|
|
84
|
+
resource.ownerId ?? ""
|
|
85
|
+
].join("|");
|
|
86
|
+
const toModelArray = (value) => {
|
|
87
|
+
if (Array.isArray(value))
|
|
88
|
+
return value;
|
|
89
|
+
if (Array.isArray(value == null ? void 0 : value.models))
|
|
90
|
+
return value.models;
|
|
91
|
+
return [];
|
|
92
|
+
};
|
|
93
|
+
const getModelChildren = (component) => {
|
|
94
|
+
var _a, _b;
|
|
95
|
+
const children = ((_a = component == null ? void 0 : component.components) == null ? void 0 : _a.call(component)) ?? ((_b = component == null ? void 0 : component.get) == null ? void 0 : _b.call(component, "components")) ?? [];
|
|
96
|
+
return toModelArray(children);
|
|
97
|
+
};
|
|
98
|
+
const getModelI18nKey = (component) => {
|
|
99
|
+
var _a, _b, _c, _d;
|
|
100
|
+
return `${((_b = (_a = component == null ? void 0 : component.getAttributes) == null ? void 0 : _a.call(component)) == null ? void 0 : _b[WB_I18N_KEY_ATTR]) ?? ((_d = (_c = component == null ? void 0 : component.get) == null ? void 0 : _c.call(component, "attributes")) == null ? void 0 : _d[WB_I18N_KEY_ATTR]) ?? ""}`.trim();
|
|
101
|
+
};
|
|
102
|
+
const findComponentByI18nKey = (root, key) => {
|
|
103
|
+
if (!root || !key)
|
|
104
|
+
return null;
|
|
105
|
+
const stack = [root];
|
|
106
|
+
const seen = /* @__PURE__ */ new WeakSet();
|
|
107
|
+
while (stack.length) {
|
|
108
|
+
const current = stack.shift();
|
|
109
|
+
if (!current || typeof current !== "object" || seen.has(current))
|
|
110
|
+
continue;
|
|
111
|
+
seen.add(current);
|
|
112
|
+
if (getModelI18nKey(current) === key)
|
|
113
|
+
return current;
|
|
114
|
+
stack.push(...getModelChildren(current));
|
|
115
|
+
}
|
|
116
|
+
return null;
|
|
117
|
+
};
|
|
118
|
+
const toI18nLanguage = (language) => {
|
|
119
|
+
const value = normalizeLanguageValue(language);
|
|
120
|
+
if (!value)
|
|
121
|
+
return null;
|
|
122
|
+
const code = languageCodeLabel(language);
|
|
123
|
+
const suffix = code ? ` / ${code}` : "";
|
|
124
|
+
return {
|
|
125
|
+
label: `${language.name || value}${suffix}`,
|
|
126
|
+
value,
|
|
127
|
+
id: language.id,
|
|
128
|
+
code: language.code,
|
|
129
|
+
slug: language.slug,
|
|
130
|
+
sortOrder: language.sortOrder,
|
|
131
|
+
defaultLang: language.defaultLang
|
|
132
|
+
};
|
|
133
|
+
};
|
|
134
|
+
function useWebBuilderI18n(options) {
|
|
135
|
+
var _a, _b;
|
|
136
|
+
let loadBundleRequestSeq = 0;
|
|
137
|
+
let sourceEntriesRefreshTimer;
|
|
138
|
+
let sourceEntriesInitialized = false;
|
|
139
|
+
let sourceEntriesDirty = true;
|
|
140
|
+
const editorRef = ref(null);
|
|
141
|
+
const locale = ref(options.defaultLocale || "");
|
|
142
|
+
const sourceLocale = ref(options.sourceLocale || "");
|
|
143
|
+
const provider = ref("");
|
|
144
|
+
const languages = ref(sortLanguagesByOrder(options.languages));
|
|
145
|
+
const sourceEntries = ref([]);
|
|
146
|
+
const sourceRevision = ref(0);
|
|
147
|
+
const savedEntries = ref([]);
|
|
148
|
+
const draftTranslations = ref({});
|
|
149
|
+
const draftStatuses = ref({});
|
|
150
|
+
const draftReviewStatuses = ref({});
|
|
151
|
+
const draftTranslationOrigins = ref({});
|
|
152
|
+
const loading = ref(false);
|
|
153
|
+
const saving = ref(false);
|
|
154
|
+
const translating = ref(false);
|
|
155
|
+
const autoTranslating = ref(false);
|
|
156
|
+
const lastError = ref("");
|
|
157
|
+
const lastSavedAt = ref(null);
|
|
158
|
+
const hostUi = options.hostUi ?? fallbackHostUi;
|
|
159
|
+
const resource = computed(() => unref(options.resource));
|
|
160
|
+
const getI18nService = () => {
|
|
161
|
+
var _a2;
|
|
162
|
+
return (_a2 = options.hostServices) == null ? void 0 : _a2.i18n;
|
|
163
|
+
};
|
|
164
|
+
const normalizeProviderConfigs = (value) => {
|
|
165
|
+
if (Array.isArray(value))
|
|
166
|
+
return value;
|
|
167
|
+
if (Array.isArray(value == null ? void 0 : value.list)) {
|
|
168
|
+
return value.list;
|
|
169
|
+
}
|
|
170
|
+
if (value && typeof value === "object" && "engineType" in value) {
|
|
171
|
+
return [value];
|
|
172
|
+
}
|
|
173
|
+
return [];
|
|
174
|
+
};
|
|
175
|
+
const loadProviderConfigs = async () => {
|
|
176
|
+
const service = getI18nService();
|
|
177
|
+
if (service == null ? void 0 : service.getEnabledProviderConfigs) {
|
|
178
|
+
return service.getEnabledProviderConfigs();
|
|
179
|
+
}
|
|
180
|
+
if (!(service == null ? void 0 : service.getTranslationConfig))
|
|
181
|
+
return [];
|
|
182
|
+
return normalizeProviderConfigs(await service.getTranslationConfig());
|
|
183
|
+
};
|
|
184
|
+
const draftStorageKey = () => {
|
|
185
|
+
const signature = resourceSignature(resource.value);
|
|
186
|
+
if (!signature || !sourceLocale.value || !locale.value)
|
|
187
|
+
return "";
|
|
188
|
+
return [
|
|
189
|
+
I18N_DRAFT_STORAGE_PREFIX,
|
|
190
|
+
encodeURIComponent(signature),
|
|
191
|
+
encodeURIComponent(sourceLocale.value),
|
|
192
|
+
encodeURIComponent(locale.value)
|
|
193
|
+
].join(":");
|
|
194
|
+
};
|
|
195
|
+
const readStoredDrafts = () => {
|
|
196
|
+
const key = draftStorageKey();
|
|
197
|
+
const storage = getLocalStorage();
|
|
198
|
+
if (!key || !storage)
|
|
199
|
+
return null;
|
|
200
|
+
try {
|
|
201
|
+
const raw = storage.getItem(key);
|
|
202
|
+
if (!raw)
|
|
203
|
+
return null;
|
|
204
|
+
const parsed = JSON.parse(raw);
|
|
205
|
+
if ((parsed == null ? void 0 : parsed.version) !== 1 || !parsed.entries || typeof parsed.entries !== "object") {
|
|
206
|
+
return null;
|
|
207
|
+
}
|
|
208
|
+
return parsed;
|
|
209
|
+
} catch {
|
|
210
|
+
return null;
|
|
211
|
+
}
|
|
212
|
+
};
|
|
213
|
+
const clearStoredDrafts = () => {
|
|
214
|
+
const key = draftStorageKey();
|
|
215
|
+
const storage = getLocalStorage();
|
|
216
|
+
if (!key || !storage)
|
|
217
|
+
return;
|
|
218
|
+
try {
|
|
219
|
+
storage.removeItem(key);
|
|
220
|
+
} catch {
|
|
221
|
+
}
|
|
222
|
+
};
|
|
223
|
+
const persistDrafts = (translations = draftTranslations.value, statuses = draftStatuses.value, reviewStatuses = draftReviewStatuses.value, origins = draftTranslationOrigins.value) => {
|
|
224
|
+
const key = draftStorageKey();
|
|
225
|
+
const storage = getLocalStorage();
|
|
226
|
+
if (!key || !storage)
|
|
227
|
+
return;
|
|
228
|
+
const sourceMap = new Map(
|
|
229
|
+
sourceEntries.value.map((entry) => [getWebBuilderI18nEntryId(entry), entry])
|
|
230
|
+
);
|
|
231
|
+
const entryIds = Array.from(
|
|
232
|
+
/* @__PURE__ */ new Set([
|
|
233
|
+
...Object.keys(translations),
|
|
234
|
+
...Object.keys(statuses),
|
|
235
|
+
...Object.keys(reviewStatuses),
|
|
236
|
+
...Object.keys(origins)
|
|
237
|
+
])
|
|
238
|
+
);
|
|
239
|
+
const storedEntries = entryIds.reduce((result, id) => {
|
|
240
|
+
if (!hasOwn(translations, id))
|
|
241
|
+
return result;
|
|
242
|
+
const translation = translations[id];
|
|
243
|
+
const sourceEntry = sourceMap.get(id);
|
|
244
|
+
result[id] = {
|
|
245
|
+
translation,
|
|
246
|
+
sourceHash: sourceEntry == null ? void 0 : sourceEntry.sourceHash,
|
|
247
|
+
status: statuses[id],
|
|
248
|
+
reviewStatus: reviewStatuses[id],
|
|
249
|
+
translationOrigin: origins[id],
|
|
250
|
+
updatedAt: Date.now()
|
|
251
|
+
};
|
|
252
|
+
return result;
|
|
253
|
+
}, {});
|
|
254
|
+
try {
|
|
255
|
+
if (!Object.keys(storedEntries).length) {
|
|
256
|
+
storage.removeItem(key);
|
|
257
|
+
return;
|
|
258
|
+
}
|
|
259
|
+
storage.setItem(
|
|
260
|
+
key,
|
|
261
|
+
JSON.stringify({
|
|
262
|
+
version: 1,
|
|
263
|
+
entries: storedEntries
|
|
264
|
+
})
|
|
265
|
+
);
|
|
266
|
+
} catch {
|
|
267
|
+
}
|
|
268
|
+
};
|
|
269
|
+
const replaceDraftState = (translations, statuses, reviewStatuses, origins, shouldPersist = true) => {
|
|
270
|
+
draftTranslations.value = translations;
|
|
271
|
+
draftStatuses.value = statuses;
|
|
272
|
+
draftReviewStatuses.value = reviewStatuses;
|
|
273
|
+
draftTranslationOrigins.value = origins;
|
|
274
|
+
if (shouldPersist) {
|
|
275
|
+
persistDrafts(translations, statuses, reviewStatuses, origins);
|
|
276
|
+
}
|
|
277
|
+
};
|
|
278
|
+
const resetDraftState = (options2 = {}) => {
|
|
279
|
+
replaceDraftState({}, {}, {}, {}, false);
|
|
280
|
+
if (options2.clearStorage) {
|
|
281
|
+
clearStoredDrafts();
|
|
282
|
+
}
|
|
283
|
+
};
|
|
284
|
+
const restoreStoredDrafts = () => {
|
|
285
|
+
const stored = readStoredDrafts();
|
|
286
|
+
if (!stored) {
|
|
287
|
+
resetDraftState();
|
|
288
|
+
return;
|
|
289
|
+
}
|
|
290
|
+
const sourceMap = new Map(
|
|
291
|
+
sourceEntries.value.map((entry) => [getWebBuilderI18nEntryId(entry), entry])
|
|
292
|
+
);
|
|
293
|
+
const nextTranslations = {};
|
|
294
|
+
const nextStatuses = {};
|
|
295
|
+
const nextReviewStatuses = {};
|
|
296
|
+
const nextOrigins = {};
|
|
297
|
+
Object.entries(stored.entries).forEach(([id, draft]) => {
|
|
298
|
+
const sourceEntry = sourceMap.get(id);
|
|
299
|
+
if (!sourceEntry || typeof (draft == null ? void 0 : draft.translation) !== "string")
|
|
300
|
+
return;
|
|
301
|
+
if (draft.sourceHash && draft.sourceHash !== sourceEntry.sourceHash)
|
|
302
|
+
return;
|
|
303
|
+
nextTranslations[id] = draft.translation;
|
|
304
|
+
nextStatuses[id] = draft.status ?? resolveI18nEntryStatus(sourceEntry, {
|
|
305
|
+
sourceHash: sourceEntry.sourceHash,
|
|
306
|
+
translation: draft.translation
|
|
307
|
+
});
|
|
308
|
+
if (draft.reviewStatus) {
|
|
309
|
+
nextReviewStatuses[id] = draft.reviewStatus;
|
|
310
|
+
}
|
|
311
|
+
if (draft.translationOrigin) {
|
|
312
|
+
nextOrigins[id] = draft.translationOrigin;
|
|
313
|
+
}
|
|
314
|
+
});
|
|
315
|
+
replaceDraftState(nextTranslations, nextStatuses, nextReviewStatuses, nextOrigins, false);
|
|
316
|
+
};
|
|
317
|
+
const entries = computed(() => {
|
|
318
|
+
const merged = mergeI18nEntries(sourceEntries.value, savedEntries.value);
|
|
319
|
+
return merged.map((entry) => {
|
|
320
|
+
const id = getWebBuilderI18nEntryId(entry);
|
|
321
|
+
const hasDraftTranslation = hasOwn(draftTranslations.value, id);
|
|
322
|
+
const hasDraftStatus = hasOwn(draftStatuses.value, id);
|
|
323
|
+
const hasDraftReviewStatus = hasOwn(draftReviewStatuses.value, id);
|
|
324
|
+
const hasDraftTranslationOrigin = hasOwn(draftTranslationOrigins.value, id);
|
|
325
|
+
const translation = draftTranslations.value[id] ?? entry.translation ?? "";
|
|
326
|
+
const reviewStatus = hasDraftReviewStatus ? draftReviewStatuses.value[id] : entry.reviewStatus;
|
|
327
|
+
const translationOrigin = hasDraftTranslationOrigin ? draftTranslationOrigins.value[id] : entry.translationOrigin;
|
|
328
|
+
return {
|
|
329
|
+
...entry,
|
|
330
|
+
translation,
|
|
331
|
+
translationOrigin,
|
|
332
|
+
reviewStatus,
|
|
333
|
+
status: (hasDraftStatus ? draftStatuses.value[id] : void 0) ?? (hasDraftTranslation ? resolveI18nEntryStatus(entry, { sourceHash: entry.sourceHash, translation }) : entry.status)
|
|
334
|
+
};
|
|
335
|
+
});
|
|
336
|
+
});
|
|
337
|
+
const dirtyEntryIds = computed(() => {
|
|
338
|
+
const savedMap = new Map(
|
|
339
|
+
savedEntries.value.map((entry) => [getWebBuilderI18nEntryId(entry), entry])
|
|
340
|
+
);
|
|
341
|
+
return entries.value.filter((entry) => {
|
|
342
|
+
const id = getWebBuilderI18nEntryId(entry);
|
|
343
|
+
const saved = savedMap.get(id);
|
|
344
|
+
return hasOwn(draftTranslations.value, id) && (draftTranslations.value[id] ?? "") !== ((saved == null ? void 0 : saved.translation) ?? "") || hasOwn(draftReviewStatuses.value, id) && (draftReviewStatuses.value[id] ?? "") !== ((saved == null ? void 0 : saved.reviewStatus) ?? "") || hasOwn(draftTranslationOrigins.value, id) && (draftTranslationOrigins.value[id] ?? "") !== ((saved == null ? void 0 : saved.translationOrigin) ?? "") || hasOwn(draftStatuses.value, id) && (draftStatuses.value[id] ?? "") !== ((saved == null ? void 0 : saved.status) ?? "");
|
|
345
|
+
}).map(getWebBuilderI18nEntryId);
|
|
346
|
+
});
|
|
347
|
+
const actionableEntries = computed(
|
|
348
|
+
() => entries.value.filter(
|
|
349
|
+
(entry) => entry.status === "missing" || entry.status === "stale" || entry.status === "error"
|
|
350
|
+
)
|
|
351
|
+
);
|
|
352
|
+
const dirty = computed(() => dirtyEntryIds.value.length > 0);
|
|
353
|
+
const missingCount = computed(
|
|
354
|
+
() => entries.value.filter((entry) => entry.status === "missing").length
|
|
355
|
+
);
|
|
356
|
+
const staleCount = computed(
|
|
357
|
+
() => entries.value.filter((entry) => entry.status === "stale").length
|
|
358
|
+
);
|
|
359
|
+
const translatedCount = computed(
|
|
360
|
+
() => entries.value.filter((entry) => entry.status === "translated").length
|
|
361
|
+
);
|
|
362
|
+
const pendingReviewCount = computed(
|
|
363
|
+
() => entries.value.filter((entry) => entry.reviewStatus === "pending_review").length
|
|
364
|
+
);
|
|
365
|
+
const reviewedCount = computed(
|
|
366
|
+
() => entries.value.filter((entry) => entry.reviewStatus === "reviewed").length
|
|
367
|
+
);
|
|
368
|
+
const targetLanguages = computed(
|
|
369
|
+
() => languages.value.filter(
|
|
370
|
+
(lang) => lang.value && lang.value !== sourceLocale.value && lang.defaultLang !== 1
|
|
371
|
+
)
|
|
372
|
+
);
|
|
373
|
+
const applyLanguageSelection = (nextLanguages) => {
|
|
374
|
+
languages.value = nextLanguages;
|
|
375
|
+
if (!nextLanguages.length) {
|
|
376
|
+
locale.value = "";
|
|
377
|
+
sourceLocale.value = "";
|
|
378
|
+
return;
|
|
379
|
+
}
|
|
380
|
+
const defaultLanguage = nextLanguages.find((lang) => lang.defaultLang === 1) || nextLanguages[0];
|
|
381
|
+
sourceLocale.value = defaultLanguage.value;
|
|
382
|
+
const targetLanguageCandidates = nextLanguages.filter(
|
|
383
|
+
(lang) => lang.value && lang.value !== sourceLocale.value && lang.defaultLang !== 1
|
|
384
|
+
);
|
|
385
|
+
const preferredTarget = targetLanguageCandidates.find((lang) => lang.value === options.defaultLocale) || targetLanguageCandidates[0];
|
|
386
|
+
if (!nextLanguages.some((lang) => lang.value === locale.value)) {
|
|
387
|
+
locale.value = (preferredTarget == null ? void 0 : preferredTarget.value) || "";
|
|
388
|
+
}
|
|
389
|
+
if (locale.value === sourceLocale.value) {
|
|
390
|
+
locale.value = (preferredTarget == null ? void 0 : preferredTarget.value) || "";
|
|
391
|
+
}
|
|
392
|
+
};
|
|
393
|
+
const loadLanguages = async () => {
|
|
394
|
+
var _a2;
|
|
395
|
+
if ((_a2 = options.languages) == null ? void 0 : _a2.length) {
|
|
396
|
+
applyLanguageSelection(sortLanguagesByOrder(options.languages));
|
|
397
|
+
return;
|
|
398
|
+
}
|
|
399
|
+
try {
|
|
400
|
+
const service = getI18nService();
|
|
401
|
+
if (!(service == null ? void 0 : service.getEnabledLanguages)) {
|
|
402
|
+
throw new Error("缺少系统语言加载服务");
|
|
403
|
+
}
|
|
404
|
+
const list = await service.getEnabledLanguages();
|
|
405
|
+
const enabledLanguages = sortLanguagesByOrder(list).map(toI18nLanguage).filter(Boolean);
|
|
406
|
+
applyLanguageSelection(enabledLanguages);
|
|
407
|
+
} catch (error) {
|
|
408
|
+
languages.value = [];
|
|
409
|
+
lastError.value = (error == null ? void 0 : error.message) || "加载系统语言失败";
|
|
410
|
+
}
|
|
411
|
+
};
|
|
412
|
+
const clearSourceEntriesRefreshTimer = () => {
|
|
413
|
+
if (!sourceEntriesRefreshTimer)
|
|
414
|
+
return;
|
|
415
|
+
clearTimeout(sourceEntriesRefreshTimer);
|
|
416
|
+
sourceEntriesRefreshTimer = void 0;
|
|
417
|
+
};
|
|
418
|
+
const refreshSourceEntries = (refreshOptions = {}) => {
|
|
419
|
+
var _a2;
|
|
420
|
+
const editor = editorRef.value;
|
|
421
|
+
if (!(editor == null ? void 0 : editor.getProjectData))
|
|
422
|
+
return;
|
|
423
|
+
const includeLayoutPages = isLayoutPageResource(resource.value);
|
|
424
|
+
if (refreshOptions.ensureKeys !== false) {
|
|
425
|
+
ensureModelI18nKeys(editor, { includeLayoutPages });
|
|
426
|
+
}
|
|
427
|
+
sourceEntries.value = extractI18nEntriesFromProjectData(((_a2 = editor.getProjectData) == null ? void 0 : _a2.call(editor)) || null, {
|
|
428
|
+
includeLayoutPages
|
|
429
|
+
});
|
|
430
|
+
sourceRevision.value += 1;
|
|
431
|
+
sourceEntriesDirty = false;
|
|
432
|
+
sourceEntriesInitialized = true;
|
|
433
|
+
};
|
|
434
|
+
const scheduleSourceEntriesRefresh = () => {
|
|
435
|
+
sourceEntriesDirty = true;
|
|
436
|
+
if (!sourceEntriesInitialized)
|
|
437
|
+
return;
|
|
438
|
+
clearSourceEntriesRefreshTimer();
|
|
439
|
+
sourceEntriesRefreshTimer = setTimeout(() => {
|
|
440
|
+
sourceEntriesRefreshTimer = void 0;
|
|
441
|
+
if (!sourceEntriesDirty)
|
|
442
|
+
return;
|
|
443
|
+
refreshSourceEntries({ ensureKeys: false });
|
|
444
|
+
}, 300);
|
|
445
|
+
};
|
|
446
|
+
const loadBundle = async () => {
|
|
447
|
+
const requestId = ++loadBundleRequestSeq;
|
|
448
|
+
const currentResource = resource.value;
|
|
449
|
+
const requestedLocale = locale.value;
|
|
450
|
+
const requestedSourceLocale = sourceLocale.value;
|
|
451
|
+
const requestedResourceSignature = resourceSignature(currentResource);
|
|
452
|
+
if (!locale.value) {
|
|
453
|
+
refreshSourceEntries({ ensureKeys: true });
|
|
454
|
+
savedEntries.value = [];
|
|
455
|
+
resetDraftState();
|
|
456
|
+
loading.value = false;
|
|
457
|
+
return;
|
|
458
|
+
}
|
|
459
|
+
if (!hasPageResourceLocator(currentResource)) {
|
|
460
|
+
refreshSourceEntries({ ensureKeys: true });
|
|
461
|
+
savedEntries.value = [];
|
|
462
|
+
resetDraftState();
|
|
463
|
+
loading.value = false;
|
|
464
|
+
return;
|
|
465
|
+
}
|
|
466
|
+
loading.value = true;
|
|
467
|
+
lastError.value = "";
|
|
468
|
+
try {
|
|
469
|
+
refreshSourceEntries({ ensureKeys: true });
|
|
470
|
+
const service = getI18nService();
|
|
471
|
+
if (!(service == null ? void 0 : service.loadBundle)) {
|
|
472
|
+
throw new Error("缺少多语言 bundle 加载服务");
|
|
473
|
+
}
|
|
474
|
+
const bundle = await service.loadBundle({
|
|
475
|
+
...currentResource,
|
|
476
|
+
locale: requestedLocale,
|
|
477
|
+
sourceLocale: requestedSourceLocale
|
|
478
|
+
});
|
|
479
|
+
if (requestId !== loadBundleRequestSeq || requestedLocale !== locale.value || requestedSourceLocale !== sourceLocale.value || requestedResourceSignature !== resourceSignature(resource.value)) {
|
|
480
|
+
return;
|
|
481
|
+
}
|
|
482
|
+
savedEntries.value = normalizeEntries(bundle);
|
|
483
|
+
restoreStoredDrafts();
|
|
484
|
+
lastSavedAt.value = (bundle == null ? void 0 : bundle.updateTime) ?? null;
|
|
485
|
+
} catch (error) {
|
|
486
|
+
if (requestId !== loadBundleRequestSeq)
|
|
487
|
+
return;
|
|
488
|
+
savedEntries.value = [];
|
|
489
|
+
restoreStoredDrafts();
|
|
490
|
+
lastError.value = (error == null ? void 0 : error.message) || "加载翻译 bundle 失败";
|
|
491
|
+
} finally {
|
|
492
|
+
if (requestId === loadBundleRequestSeq) {
|
|
493
|
+
loading.value = false;
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
};
|
|
497
|
+
const setTranslation = (entry, translation, options2 = {}) => {
|
|
498
|
+
const id = getWebBuilderI18nEntryId(entry);
|
|
499
|
+
const nextTranslations = {
|
|
500
|
+
...draftTranslations.value,
|
|
501
|
+
[id]: translation
|
|
502
|
+
};
|
|
503
|
+
const nextOrigins = {
|
|
504
|
+
...draftTranslationOrigins.value,
|
|
505
|
+
[id]: options2.origin ?? "manual"
|
|
506
|
+
};
|
|
507
|
+
const nextReviewStatuses = {
|
|
508
|
+
...draftReviewStatuses.value,
|
|
509
|
+
[id]: options2.reviewStatus ?? "reviewed"
|
|
510
|
+
};
|
|
511
|
+
const nextStatuses = {
|
|
512
|
+
...draftStatuses.value,
|
|
513
|
+
[id]: options2.status ?? resolveI18nEntryStatus(entry, {
|
|
514
|
+
sourceHash: entry.sourceHash,
|
|
515
|
+
translation
|
|
516
|
+
})
|
|
517
|
+
};
|
|
518
|
+
replaceDraftState(nextTranslations, nextStatuses, nextReviewStatuses, nextOrigins);
|
|
519
|
+
};
|
|
520
|
+
const confirmTranslation = (entry) => {
|
|
521
|
+
const id = getWebBuilderI18nEntryId(entry);
|
|
522
|
+
const translation = draftTranslations.value[id] ?? entry.translation ?? "";
|
|
523
|
+
if (!`${translation ?? ""}`.trim()) {
|
|
524
|
+
lastError.value = "当前片段没有译文,无法确认";
|
|
525
|
+
return;
|
|
526
|
+
}
|
|
527
|
+
lastError.value = "";
|
|
528
|
+
const nextReviewStatuses = {
|
|
529
|
+
...draftReviewStatuses.value,
|
|
530
|
+
[id]: "reviewed"
|
|
531
|
+
};
|
|
532
|
+
const nextOrigins = {
|
|
533
|
+
...draftTranslationOrigins.value,
|
|
534
|
+
[id]: "manual"
|
|
535
|
+
};
|
|
536
|
+
replaceDraftState(draftTranslations.value, draftStatuses.value, nextReviewStatuses, nextOrigins);
|
|
537
|
+
};
|
|
538
|
+
const setLocale = (nextLocale) => {
|
|
539
|
+
locale.value = nextLocale;
|
|
540
|
+
};
|
|
541
|
+
const setProvider = (nextProvider) => {
|
|
542
|
+
provider.value = nextProvider;
|
|
543
|
+
};
|
|
544
|
+
const buildProviderPayload = () => {
|
|
545
|
+
const currentProvider = provider.value.trim();
|
|
546
|
+
return currentProvider ? { provider: currentProvider } : {};
|
|
547
|
+
};
|
|
548
|
+
const requireResourceLocator = () => {
|
|
549
|
+
if (hasPageResourceLocator(resource.value))
|
|
550
|
+
return true;
|
|
551
|
+
lastError.value = "缺少页面资源标识,无法保存或翻译多语言内容";
|
|
552
|
+
return false;
|
|
553
|
+
};
|
|
554
|
+
const saveTranslations = async () => {
|
|
555
|
+
const currentResource = resource.value;
|
|
556
|
+
if (!requireResourceLocator())
|
|
557
|
+
return false;
|
|
558
|
+
if (!locale.value) {
|
|
559
|
+
lastError.value = "请先启用至少一个系统语言";
|
|
560
|
+
return false;
|
|
561
|
+
}
|
|
562
|
+
saving.value = true;
|
|
563
|
+
lastError.value = "";
|
|
564
|
+
try {
|
|
565
|
+
const dirtyIds = new Set(dirtyEntryIds.value);
|
|
566
|
+
const payloadEntries = entries.value.filter((entry) => dirtyIds.has(getWebBuilderI18nEntryId(entry))).map((entry) => ({
|
|
567
|
+
...entry,
|
|
568
|
+
translation: draftTranslations.value[getWebBuilderI18nEntryId(entry)] ?? entry.translation ?? "",
|
|
569
|
+
translationOrigin: draftTranslationOrigins.value[getWebBuilderI18nEntryId(entry)] ?? entry.translationOrigin,
|
|
570
|
+
reviewStatus: draftReviewStatuses.value[getWebBuilderI18nEntryId(entry)] ?? entry.reviewStatus,
|
|
571
|
+
status: resolveI18nEntryStatus(entry, {
|
|
572
|
+
sourceHash: entry.sourceHash,
|
|
573
|
+
translation: draftTranslations.value[getWebBuilderI18nEntryId(entry)] ?? entry.translation ?? ""
|
|
574
|
+
})
|
|
575
|
+
}));
|
|
576
|
+
const service = getI18nService();
|
|
577
|
+
if (!(service == null ? void 0 : service.saveBundle)) {
|
|
578
|
+
throw new Error("缺少多语言 bundle 保存服务");
|
|
579
|
+
}
|
|
580
|
+
const bundle = await service.saveBundle({
|
|
581
|
+
...currentResource,
|
|
582
|
+
locale: locale.value,
|
|
583
|
+
sourceLocale: sourceLocale.value,
|
|
584
|
+
entries: payloadEntries,
|
|
585
|
+
partial: true
|
|
586
|
+
});
|
|
587
|
+
savedEntries.value = normalizeEntries(bundle);
|
|
588
|
+
if (!savedEntries.value.length)
|
|
589
|
+
savedEntries.value = payloadEntries;
|
|
590
|
+
resetDraftState({ clearStorage: true });
|
|
591
|
+
lastSavedAt.value = (bundle == null ? void 0 : bundle.updateTime) ?? /* @__PURE__ */ new Date();
|
|
592
|
+
return true;
|
|
593
|
+
} catch (error) {
|
|
594
|
+
lastError.value = (error == null ? void 0 : error.message) || "保存翻译 bundle 失败";
|
|
595
|
+
throw error;
|
|
596
|
+
} finally {
|
|
597
|
+
saving.value = false;
|
|
598
|
+
}
|
|
599
|
+
};
|
|
600
|
+
const machineTranslateEntries = async (targetEntries) => {
|
|
601
|
+
if (!requireResourceLocator())
|
|
602
|
+
return;
|
|
603
|
+
if (!locale.value) {
|
|
604
|
+
lastError.value = "请先启用至少一个系统语言";
|
|
605
|
+
return;
|
|
606
|
+
}
|
|
607
|
+
const targets = targetEntries.filter(Boolean);
|
|
608
|
+
if (!targets.length)
|
|
609
|
+
return;
|
|
610
|
+
translating.value = true;
|
|
611
|
+
lastError.value = "";
|
|
612
|
+
try {
|
|
613
|
+
const service = getI18nService();
|
|
614
|
+
if (!(service == null ? void 0 : service.translateEntries)) {
|
|
615
|
+
throw new Error("缺少机器翻译服务");
|
|
616
|
+
}
|
|
617
|
+
const res = await service.translateEntries({
|
|
618
|
+
...resource.value,
|
|
619
|
+
locale: locale.value,
|
|
620
|
+
sourceLocale: sourceLocale.value,
|
|
621
|
+
...buildProviderPayload(),
|
|
622
|
+
entries: targets
|
|
623
|
+
});
|
|
624
|
+
if ((res == null ? void 0 : res.success) === false && res.errorMessage) {
|
|
625
|
+
lastError.value = res.errorMessage;
|
|
626
|
+
}
|
|
627
|
+
const translated = Array.isArray(res == null ? void 0 : res.entries) ? res.entries : [];
|
|
628
|
+
const nextDrafts = { ...draftTranslations.value };
|
|
629
|
+
const nextStatuses = { ...draftStatuses.value };
|
|
630
|
+
const nextReviewStatuses = { ...draftReviewStatuses.value };
|
|
631
|
+
const nextTranslationOrigins = { ...draftTranslationOrigins.value };
|
|
632
|
+
let rejectedUnchangedCount = 0;
|
|
633
|
+
translated.forEach((entry) => {
|
|
634
|
+
const id = getWebBuilderI18nEntryId(entry);
|
|
635
|
+
const sourceEntry = targets.find((target) => getWebBuilderI18nEntryId(target) === id) ?? entry;
|
|
636
|
+
const translation = entry.translation ?? "";
|
|
637
|
+
if (entry.status === "error" || entry.status !== "translated" && isUnchangedNonIdentityTranslation(sourceEntry.source, translation)) {
|
|
638
|
+
rejectedUnchangedCount += entry.status === "error" ? 0 : 1;
|
|
639
|
+
nextDrafts[id] = "";
|
|
640
|
+
nextStatuses[id] = "error";
|
|
641
|
+
delete nextReviewStatuses[id];
|
|
642
|
+
delete nextTranslationOrigins[id];
|
|
643
|
+
return;
|
|
644
|
+
}
|
|
645
|
+
nextDrafts[id] = translation;
|
|
646
|
+
nextStatuses[id] = resolveI18nEntryStatus(sourceEntry, {
|
|
647
|
+
sourceHash: sourceEntry.sourceHash,
|
|
648
|
+
translation,
|
|
649
|
+
status: entry.status
|
|
650
|
+
});
|
|
651
|
+
nextReviewStatuses[id] = "reviewed";
|
|
652
|
+
nextTranslationOrigins[id] = entry.translationOrigin ?? "machine";
|
|
653
|
+
});
|
|
654
|
+
if (rejectedUnchangedCount > 0 && !lastError.value) {
|
|
655
|
+
lastError.value = "翻译引擎未返回目标语言内容,请检查翻译配置或换一个引擎";
|
|
656
|
+
}
|
|
657
|
+
replaceDraftState(nextDrafts, nextStatuses, nextReviewStatuses, nextTranslationOrigins);
|
|
658
|
+
} catch (error) {
|
|
659
|
+
lastError.value = (error == null ? void 0 : error.message) || "机器翻译接口暂不可用";
|
|
660
|
+
} finally {
|
|
661
|
+
translating.value = false;
|
|
662
|
+
}
|
|
663
|
+
};
|
|
664
|
+
const machineTranslate = async (mode = "missing") => {
|
|
665
|
+
const targets = entries.value.filter((entry) => {
|
|
666
|
+
if (mode === "all")
|
|
667
|
+
return true;
|
|
668
|
+
return entry.status === mode;
|
|
669
|
+
});
|
|
670
|
+
await machineTranslateEntries(targets);
|
|
671
|
+
};
|
|
672
|
+
const runAutoTranslateMissing = async (autoOptions = {}) => {
|
|
673
|
+
var _a2;
|
|
674
|
+
autoTranslating.value = true;
|
|
675
|
+
if (!autoOptions.silent) {
|
|
676
|
+
lastError.value = "";
|
|
677
|
+
}
|
|
678
|
+
try {
|
|
679
|
+
const service = getI18nService();
|
|
680
|
+
if (!(service == null ? void 0 : service.autoTranslateEntries)) {
|
|
681
|
+
throw new Error("缺少自动翻译服务");
|
|
682
|
+
}
|
|
683
|
+
const response = await service.autoTranslateEntries({
|
|
684
|
+
...resource.value,
|
|
685
|
+
locale: locale.value || ((_a2 = targetLanguages.value[0]) == null ? void 0 : _a2.value) || sourceLocale.value,
|
|
686
|
+
sourceLocale: sourceLocale.value,
|
|
687
|
+
...buildProviderPayload(),
|
|
688
|
+
publishReady: autoOptions.publishReady ?? false,
|
|
689
|
+
locales: targetLanguages.value.map((lang) => lang.value),
|
|
690
|
+
entries: sourceEntries.value
|
|
691
|
+
});
|
|
692
|
+
if ((response == null ? void 0 : response.success) === false) {
|
|
693
|
+
const message = response.errorMessage || "自动翻译未全部完成";
|
|
694
|
+
if (!autoOptions.silent) {
|
|
695
|
+
lastError.value = message;
|
|
696
|
+
}
|
|
697
|
+
return false;
|
|
698
|
+
}
|
|
699
|
+
if (autoOptions.reloadCurrentLocale !== false) {
|
|
700
|
+
await loadBundle();
|
|
701
|
+
}
|
|
702
|
+
return true;
|
|
703
|
+
} catch (error) {
|
|
704
|
+
const message = (error == null ? void 0 : error.message) || "自动翻译任务启动失败";
|
|
705
|
+
if (autoOptions.silent) {
|
|
706
|
+
console.warn("[WebBuilder] auto translate failed:", message);
|
|
707
|
+
} else {
|
|
708
|
+
lastError.value = message;
|
|
709
|
+
}
|
|
710
|
+
return false;
|
|
711
|
+
} finally {
|
|
712
|
+
autoTranslating.value = false;
|
|
713
|
+
}
|
|
714
|
+
};
|
|
715
|
+
const autoTranslateMissing = async (autoOptions = {}) => {
|
|
716
|
+
if (!requireResourceLocator())
|
|
717
|
+
return false;
|
|
718
|
+
if (!languages.value.length) {
|
|
719
|
+
await loadLanguages();
|
|
720
|
+
}
|
|
721
|
+
refreshSourceEntries({ ensureKeys: true });
|
|
722
|
+
if (!sourceEntries.value.length || !targetLanguages.value.length)
|
|
723
|
+
return true;
|
|
724
|
+
if (targetLanguages.value.length === 1 && !actionableEntries.value.length)
|
|
725
|
+
return true;
|
|
726
|
+
return await runAutoTranslateMissing(autoOptions);
|
|
727
|
+
};
|
|
728
|
+
const flushDirtyTranslations = async () => {
|
|
729
|
+
if (!dirty.value) {
|
|
730
|
+
clearStoredDrafts();
|
|
731
|
+
return true;
|
|
732
|
+
}
|
|
733
|
+
return saveTranslations();
|
|
734
|
+
};
|
|
735
|
+
const i18nActionText = {
|
|
736
|
+
publish: "发布",
|
|
737
|
+
save: "保存"
|
|
738
|
+
};
|
|
739
|
+
const confirmContinueAfterI18nIssue = async (action, reason) => {
|
|
740
|
+
var _a2, _b2;
|
|
741
|
+
const actionText = i18nActionText[action];
|
|
742
|
+
const cancelText = action === "publish" ? "取消发布" : "取消保存";
|
|
743
|
+
(_a2 = options.blockingProcess) == null ? void 0 : _a2.stop();
|
|
744
|
+
try {
|
|
745
|
+
const confirmed = await hostUi.confirm({
|
|
746
|
+
message: `多语言自动翻译未全部完成:${reason}。继续${actionText}后,缺失或异常片段可能显示源语言内容或旧译文。是否继续${actionText}?`,
|
|
747
|
+
title: `多语言${actionText}提醒`,
|
|
748
|
+
confirmText: `继续${actionText}`,
|
|
749
|
+
cancelText
|
|
750
|
+
});
|
|
751
|
+
if (!confirmed) {
|
|
752
|
+
hostUi.message.warning(`已${cancelText},当前编辑内容仍保留在页面中`);
|
|
753
|
+
return false;
|
|
754
|
+
}
|
|
755
|
+
(_b2 = options.blockingProcess) == null ? void 0 : _b2.start(
|
|
756
|
+
action,
|
|
757
|
+
action === "publish" ? ["正在继续发布前检查", "正在同步发布前资源"] : ["正在继续保存流程", "正在同步保存资源"]
|
|
758
|
+
);
|
|
759
|
+
return true;
|
|
760
|
+
} catch {
|
|
761
|
+
hostUi.message.warning(`已${cancelText},当前编辑内容仍保留在页面中`);
|
|
762
|
+
return false;
|
|
763
|
+
}
|
|
764
|
+
};
|
|
765
|
+
const ensureReadyOrConfirm = async (action) => {
|
|
766
|
+
var _a2, _b2;
|
|
767
|
+
(_a2 = options.blockingProcess) == null ? void 0 : _a2.setMessage([
|
|
768
|
+
"正在检索翻译内容",
|
|
769
|
+
"正在同步手工译文草稿",
|
|
770
|
+
"正在保存多语言草稿",
|
|
771
|
+
"正在检查缺失翻译",
|
|
772
|
+
"正在自动翻译缺失片段",
|
|
773
|
+
action === "publish" ? "正在校验多语言发布状态" : "正在校验多语言保存状态"
|
|
774
|
+
]);
|
|
775
|
+
let flushed = false;
|
|
776
|
+
try {
|
|
777
|
+
flushed = await flushDirtyTranslations();
|
|
778
|
+
} catch {
|
|
779
|
+
flushed = false;
|
|
780
|
+
}
|
|
781
|
+
if (!flushed) {
|
|
782
|
+
(_b2 = options.blockingProcess) == null ? void 0 : _b2.stop();
|
|
783
|
+
hostUi.message.error(lastError.value || "多语言手工译文保存失败,已中止当前操作");
|
|
784
|
+
return false;
|
|
785
|
+
}
|
|
786
|
+
const ready = await autoTranslateMissing({
|
|
787
|
+
publishReady: action === "publish",
|
|
788
|
+
reloadCurrentLocale: true,
|
|
789
|
+
silent: false
|
|
790
|
+
});
|
|
791
|
+
if (ready)
|
|
792
|
+
return true;
|
|
793
|
+
return confirmContinueAfterI18nIssue(action, lastError.value || "仍存在缺失翻译或翻译错误");
|
|
794
|
+
};
|
|
795
|
+
const getPreviewProjectData = () => {
|
|
796
|
+
var _a2;
|
|
797
|
+
const editor = editorRef.value;
|
|
798
|
+
refreshSourceEntries({ ensureKeys: true });
|
|
799
|
+
const projectData = ((_a2 = editor == null ? void 0 : editor.getProjectData) == null ? void 0 : _a2.call(editor)) || null;
|
|
800
|
+
return applyI18nTranslationsToProjectData(projectData, entries.value);
|
|
801
|
+
};
|
|
802
|
+
const selectEntryComponent = (entry) => {
|
|
803
|
+
var _a2, _b2, _c, _d, _e, _f, _g;
|
|
804
|
+
const editor = editorRef.value;
|
|
805
|
+
const key = `${(entry == null ? void 0 : entry.key) ?? ""}`.trim();
|
|
806
|
+
if (!editor || !key || key.startsWith("page:")) {
|
|
807
|
+
(_a2 = editor == null ? void 0 : editor.select) == null ? void 0 : _a2.call(editor, null);
|
|
808
|
+
return false;
|
|
809
|
+
}
|
|
810
|
+
const pages = toModelArray((_c = (_b2 = editor == null ? void 0 : editor.Pages) == null ? void 0 : _b2.getAll) == null ? void 0 : _c.call(_b2));
|
|
811
|
+
const roots = pages.length ? pages.map((page) => {
|
|
812
|
+
var _a3;
|
|
813
|
+
return (_a3 = page == null ? void 0 : page.getMainComponent) == null ? void 0 : _a3.call(page);
|
|
814
|
+
}).filter(Boolean) : [(_d = editor == null ? void 0 : editor.getWrapper) == null ? void 0 : _d.call(editor)].filter(Boolean);
|
|
815
|
+
const component = roots.map((root) => findComponentByI18nKey(root, key)).find(Boolean);
|
|
816
|
+
if (!component) {
|
|
817
|
+
(_e = editor.select) == null ? void 0 : _e.call(editor, null);
|
|
818
|
+
return false;
|
|
819
|
+
}
|
|
820
|
+
(_f = editor.select) == null ? void 0 : _f.call(editor, component);
|
|
821
|
+
const element = (_g = component == null ? void 0 : component.view) == null ? void 0 : _g.el;
|
|
822
|
+
if (element == null ? void 0 : element.scrollIntoView) {
|
|
823
|
+
element.scrollIntoView({ block: "center", inline: "center" });
|
|
824
|
+
}
|
|
825
|
+
return true;
|
|
826
|
+
};
|
|
827
|
+
(_b = (_a = options.grapes) == null ? void 0 : _a.onInit) == null ? void 0 : _b.call(_a, (editor) => {
|
|
828
|
+
var _a2, _b2, _c, _d, _e, _f;
|
|
829
|
+
editorRef.value = editor;
|
|
830
|
+
const refresh = () => scheduleSourceEntriesRefresh();
|
|
831
|
+
(_a2 = editor.on) == null ? void 0 : _a2.call(editor, "component:add", refresh);
|
|
832
|
+
(_b2 = editor.on) == null ? void 0 : _b2.call(editor, "component:remove", refresh);
|
|
833
|
+
(_c = editor.on) == null ? void 0 : _c.call(editor, "component:update:attributes", refresh);
|
|
834
|
+
(_d = editor.on) == null ? void 0 : _d.call(editor, "component:update:content", refresh);
|
|
835
|
+
(_e = editor.on) == null ? void 0 : _e.call(editor, "page", refresh);
|
|
836
|
+
(_f = editor.on) == null ? void 0 : _f.call(editor, "destroy", () => {
|
|
837
|
+
var _a3, _b3, _c2, _d2, _e2;
|
|
838
|
+
clearSourceEntriesRefreshTimer();
|
|
839
|
+
(_a3 = editor.off) == null ? void 0 : _a3.call(editor, "component:add", refresh);
|
|
840
|
+
(_b3 = editor.off) == null ? void 0 : _b3.call(editor, "component:remove", refresh);
|
|
841
|
+
(_c2 = editor.off) == null ? void 0 : _c2.call(editor, "component:update:attributes", refresh);
|
|
842
|
+
(_d2 = editor.off) == null ? void 0 : _d2.call(editor, "component:update:content", refresh);
|
|
843
|
+
(_e2 = editor.off) == null ? void 0 : _e2.call(editor, "page", refresh);
|
|
844
|
+
editorRef.value = null;
|
|
845
|
+
sourceEntriesInitialized = false;
|
|
846
|
+
sourceEntriesDirty = true;
|
|
847
|
+
});
|
|
848
|
+
});
|
|
849
|
+
watch(locale, () => {
|
|
850
|
+
void loadBundle();
|
|
851
|
+
});
|
|
852
|
+
watch(sourceLocale, () => {
|
|
853
|
+
void loadBundle();
|
|
854
|
+
});
|
|
855
|
+
watch(
|
|
856
|
+
resource,
|
|
857
|
+
() => {
|
|
858
|
+
void loadBundle();
|
|
859
|
+
},
|
|
860
|
+
{ deep: true }
|
|
861
|
+
);
|
|
862
|
+
return {
|
|
863
|
+
locale,
|
|
864
|
+
sourceLocale,
|
|
865
|
+
provider,
|
|
866
|
+
languages,
|
|
867
|
+
entries,
|
|
868
|
+
sourceEntries,
|
|
869
|
+
sourceRevision,
|
|
870
|
+
savedEntries,
|
|
871
|
+
loading,
|
|
872
|
+
saving,
|
|
873
|
+
translating,
|
|
874
|
+
autoTranslating,
|
|
875
|
+
dirty,
|
|
876
|
+
dirtyEntryIds,
|
|
877
|
+
actionableEntries,
|
|
878
|
+
missingCount,
|
|
879
|
+
staleCount,
|
|
880
|
+
translatedCount,
|
|
881
|
+
pendingReviewCount,
|
|
882
|
+
reviewedCount,
|
|
883
|
+
targetLanguages,
|
|
884
|
+
lastError,
|
|
885
|
+
lastSavedAt,
|
|
886
|
+
hostUi,
|
|
887
|
+
setLocale,
|
|
888
|
+
setProvider,
|
|
889
|
+
refreshSourceEntries,
|
|
890
|
+
loadBundle,
|
|
891
|
+
setTranslation,
|
|
892
|
+
confirmTranslation,
|
|
893
|
+
saveTranslations,
|
|
894
|
+
flushDirtyTranslations,
|
|
895
|
+
ensureReadyOrConfirm,
|
|
896
|
+
machineTranslate,
|
|
897
|
+
machineTranslateEntries,
|
|
898
|
+
autoTranslateMissing,
|
|
899
|
+
getPreviewProjectData,
|
|
900
|
+
selectEntryComponent,
|
|
901
|
+
loadLanguages,
|
|
902
|
+
loadProviderConfigs
|
|
903
|
+
};
|
|
904
|
+
}
|
|
905
|
+
export {
|
|
906
|
+
I as I18N_PLUGIN_CAPABILITY,
|
|
907
|
+
a as I18N_PLUGIN_ID,
|
|
908
|
+
WB_I18N_KEY_ATTR,
|
|
909
|
+
c3 as WB_I18N_SKIP_ATTR,
|
|
910
|
+
applyI18nTranslationsToProjectData,
|
|
911
|
+
d as collectI18nKeysFromModel,
|
|
912
|
+
compareLanguagesByOrder,
|
|
913
|
+
c as createI18nPlugin,
|
|
914
|
+
ensureModelI18nKeys,
|
|
915
|
+
extractI18nEntriesFromProjectData,
|
|
916
|
+
getWebBuilderI18nEntryId,
|
|
917
|
+
h as hashI18nSource,
|
|
918
|
+
f as isIdentityTranslationAllowed,
|
|
919
|
+
j as isModelI18nSkipped,
|
|
920
|
+
isUnchangedNonIdentityTranslation,
|
|
921
|
+
mergeI18nEntries,
|
|
922
|
+
resolveI18nEntryStatus,
|
|
923
|
+
k as resolveI18nReviewStatus,
|
|
924
|
+
s as setModelI18nSkipped,
|
|
925
|
+
sortLanguagesByOrder,
|
|
926
|
+
l as stripI18nTranslationsFromProjectData,
|
|
927
|
+
useWebBuilderI18n,
|
|
928
|
+
c2 as webBuilderI18n
|
|
929
|
+
};
|