@localazy/strapi-plugin 1.6.0 → 1.7.1

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.
Files changed (41) hide show
  1. package/dist/_chunks/{FetchIdentity-CcEjakiz.js → FetchIdentity-D89DgpbN.js} +1 -1
  2. package/dist/_chunks/{FetchIdentity-Bm7bc5bS.mjs → FetchIdentity-DkHj24S5.mjs} +1 -1
  3. package/dist/_chunks/{LanguagesSelector-DejYCwBl.js → LanguagesSelector-638KGQYw.js} +2 -2
  4. package/dist/_chunks/{LanguagesSelector-B1rwN7-Y.mjs → LanguagesSelector-CR_7I2R1.mjs} +2 -2
  5. package/dist/_chunks/{LocalazyApp-jPO7Yr1S.js → LocalazyApp-Benn8pkA.js} +5 -5
  6. package/dist/_chunks/{LocalazyApp-C4kbsnQh.mjs → LocalazyApp-DM3zg5E4.mjs} +5 -5
  7. package/dist/_chunks/{LocalazyContentTransferSetup-C1wDD9hA.mjs → LocalazyContentTransferSetup-BA_rtSBM.mjs} +4 -4
  8. package/dist/_chunks/{LocalazyContentTransferSetup-DZh4ZdSi.js → LocalazyContentTransferSetup-CWchyGdD.js} +4 -4
  9. package/dist/_chunks/{LocalazyGlobalSettings-D76it6rn.js → LocalazyGlobalSettings-88jqQbD4.js} +5 -5
  10. package/dist/_chunks/{LocalazyGlobalSettings-DOW5rjLn.mjs → LocalazyGlobalSettings-BWF0s9tM.mjs} +5 -5
  11. package/dist/_chunks/{LocalazyPanel-C_Z4W49T.mjs → LocalazyPanel-4HRa1jNl.mjs} +2 -2
  12. package/dist/_chunks/{LocalazyPanel-D2LQpqii.js → LocalazyPanel-D0w9JSIS.js} +2 -2
  13. package/dist/_chunks/{LocalazyStatusColumn-Dy6N4_X6.js → LocalazyStatusColumn-BR3f8rKp.js} +2 -2
  14. package/dist/_chunks/{LocalazyStatusColumn-C_ZCd_s7.mjs → LocalazyStatusColumn-D4-rZZUK.mjs} +2 -2
  15. package/dist/_chunks/{RequireLocalazyAuth-BVwF0bRC.js → RequireLocalazyAuth-C442750b.js} +2 -2
  16. package/dist/_chunks/{RequireLocalazyAuth-DNhTZZ_6.mjs → RequireLocalazyAuth-DbNjEOq-.mjs} +2 -2
  17. package/dist/_chunks/{entry-exclusion-service-CF_yNCly.mjs → entry-exclusion-service-Bd3mUDde.mjs} +1 -1
  18. package/dist/_chunks/{entry-exclusion-service-CH3ZoJQN.js → entry-exclusion-service-CAIcybXX.js} +1 -1
  19. package/dist/_chunks/{has-model-changed-CVJEuGxM.mjs → has-model-changed-BNs3d9q5.mjs} +4 -3
  20. package/dist/_chunks/{has-model-changed-DdYbyv0v.js → has-model-changed-BrDeyHFt.js} +4 -3
  21. package/dist/_chunks/{index-DP2ugzc_.mjs → index-C9Px4v-A.mjs} +7 -7
  22. package/dist/_chunks/{index-CEGaWWh3.js → index-DwFm1TyM.js} +7 -7
  23. package/dist/_chunks/{strapi-api-base-CCUuu7EY.js → strapi-api-base-BWZYbxxj.js} +1 -1
  24. package/dist/_chunks/{strapi-api-base-IiMEtDoH.mjs → strapi-api-base-lPo7wq6I.mjs} +1 -1
  25. package/dist/admin/index.js +1 -1
  26. package/dist/admin/index.mjs +1 -1
  27. package/dist/admin/src/modules/@common/models/supported-content-type-fields.d.ts +1 -1
  28. package/dist/server/index.js +583 -391
  29. package/dist/server/index.mjs +583 -391
  30. package/dist/server/src/functions/should-set-downloaded-property.d.ts +19 -0
  31. package/dist/server/src/utils/align-localized-entry-to-source.d.ts +11 -0
  32. package/dist/server/src/utils/blocks-to-translatable.d.ts +34 -0
  33. package/dist/server/src/utils/build-localized-create-entry.d.ts +6 -0
  34. package/dist/server/src/utils/collect-downloaded-content.d.ts +44 -0
  35. package/dist/server/src/utils/json-fields-download-accumulator.d.ts +19 -0
  36. package/dist/server/src/utils/model-utils.d.ts +3 -1
  37. package/dist/server/src/utils/overlay-json-translation.d.ts +10 -0
  38. package/dist/server/src/utils/parse-localazy-key.d.ts +11 -0
  39. package/dist/server/src/utils/parsed-localazy-entry-to-create-entry.d.ts +9 -1
  40. package/package.json +1 -1
  41. package/dist/server/src/utils/reset-array-keys-deep.d.ts +0 -1
@@ -20520,7 +20520,7 @@ var distExports = dist$1.exports;
20520
20520
  const io = /* @__PURE__ */ getDefaultExportFromCjs(distExports);
20521
20521
  const { Server: Server2, Namespace, Socket: Socket3 } = io;
20522
20522
  const name = "@localazy/strapi-plugin";
20523
- const version = "1.6.0";
20523
+ const version = "1.7.1";
20524
20524
  const description = "The official Strapi Plugin by Localazy.";
20525
20525
  const keywords = [
20526
20526
  "strapi",
@@ -22038,7 +22038,7 @@ const findSetupModelByCollectionUid = (contentTransferSetup, strapiContentTypesM
22038
22038
  const modelContentTransferSetup = contentTransferSetup.setup.find(
22039
22039
  (model) => Object.keys(model)[0] === currentModel.collectionName
22040
22040
  );
22041
- return modelContentTransferSetup[currentModel.collectionName];
22041
+ return modelContentTransferSetup?.[currentModel.collectionName];
22042
22042
  };
22043
22043
  const getCollectionsNames = (setup2) => {
22044
22044
  return getMainKeysOfNestedArrayObjects(setup2);
@@ -25611,182 +25611,6 @@ const PluginSettingsService = ({ strapi: strapi2 }) => ({
25611
25611
  return cursor;
25612
25612
  }
25613
25613
  });
25614
- const LocalazyTransferUploadService = ({ strapi: strapi2 }) => ({
25615
- async upload({ notificationService }) {
25616
- console.time("upload");
25617
- await notificationService.emit(EventType.UPLOAD, {
25618
- message: "Upload started"
25619
- });
25620
- const activityLogsService = getActivityLogsService();
25621
- const sessionId = await activityLogsService.startSession("upload", "Strapi User");
25622
- await activityLogsService.addEntry(sessionId, "Upload started");
25623
- let success = true;
25624
- const StrapiService2 = getStrapiService();
25625
- const StrapiI18nService2 = getStrapiI18nService();
25626
- const LocalazyUploadService2 = getLocalazyUploadService();
25627
- const EntryExclusionService2 = getEntryExclusionService();
25628
- const contentTransferSetup = await getPluginSettingsService().getContentTransferSetup();
25629
- if (!contentTransferSetup.has_setup) {
25630
- const message = "Content transfer setup is not set up.";
25631
- success = false;
25632
- await notificationService.emit(EventType.UPLOAD_FINISHED, {
25633
- success,
25634
- message
25635
- });
25636
- await activityLogsService.addEntry(sessionId, message);
25637
- await activityLogsService.finishSession(sessionId, "failed", message);
25638
- strapi2.log.info(message);
25639
- return;
25640
- }
25641
- const { setup: setup2 } = contentTransferSetup;
25642
- const collectionsNames = getCollectionsNames(setup2);
25643
- const models = await StrapiService2.getModels();
25644
- const strapiDefaultLocaleCode = await StrapiI18nService2.getDefaultLocaleCode();
25645
- const attemptedTuples = [];
25646
- let pickedFlattenStrapiContent = {};
25647
- for (const collectionName of collectionsNames) {
25648
- const currentModel = models.find((model) => model.collectionName === collectionName);
25649
- const modelUid = currentModel.uid;
25650
- if (!currentModel) {
25651
- strapi2.log.warn(`Model with uid ${modelUid} is not found.`);
25652
- continue;
25653
- }
25654
- const transferSetupModel = findSetupModelByCollectionName(setup2, collectionName);
25655
- if (!isCollectionTransferEnabled(setup2, collectionName)) {
25656
- const message2 = `Collection ${collectionName} transfer is disabled.`;
25657
- await notificationService.emit(EventType.UPLOAD, {
25658
- message: message2
25659
- });
25660
- await activityLogsService.addEntry(sessionId, message2);
25661
- strapi2.log.info(message2);
25662
- continue;
25663
- }
25664
- const currentTransferSetupModel = transferSetupModel[collectionName];
25665
- const pickPaths = getPickPathsWithComponents(currentTransferSetupModel);
25666
- if (!pickPaths.length) {
25667
- const message2 = `No fields for collection ${collectionName} transfer are enabled.`;
25668
- await notificationService.emit(EventType.UPLOAD, {
25669
- message: message2
25670
- });
25671
- await activityLogsService.addEntry(sessionId, message2);
25672
- strapi2.log.warn(message2);
25673
- continue;
25674
- }
25675
- const pickPathsWithUid = pickPaths.map((pickPath) => `${modelUid}.${pickPath}`);
25676
- let entries = await strapi2.documents(modelUid).findMany({
25677
- locUploadPLevel: 6,
25678
- status: "draft"
25679
- });
25680
- if (!entries.length) {
25681
- strapi2.log.info(`No entries found for model ${modelUid}`);
25682
- continue;
25683
- }
25684
- const excludedEntries = await EntryExclusionService2.getContentTypeExclusions(modelUid);
25685
- const filteredEntries = [];
25686
- for (const entry of entries) {
25687
- const isExcluded = excludedEntries.includes(entry.documentId);
25688
- if (!isExcluded) {
25689
- filteredEntries.push(entry);
25690
- }
25691
- }
25692
- entries = filteredEntries;
25693
- if (!entries.length) {
25694
- const message2 = `All entries for model ${collectionName} are excluded from translation`;
25695
- await notificationService.emit(EventType.UPLOAD, {
25696
- message: message2
25697
- });
25698
- await activityLogsService.addEntry(sessionId, message2);
25699
- strapi2.log.info(message2);
25700
- continue;
25701
- }
25702
- const message = `Excluding ${excludedEntries.length} entries for model ${collectionName} from upload. Entries to translate: ${entries.length}.`;
25703
- await notificationService.emit(EventType.UPLOAD, {
25704
- message
25705
- });
25706
- await activityLogsService.addEntry(sessionId, message);
25707
- strapi2.log.info(message);
25708
- if (strapiDefaultLocaleCode) {
25709
- for (const entry of entries) {
25710
- attemptedTuples.push({
25711
- uid: modelUid,
25712
- documentId: entry.documentId,
25713
- locale: strapiDefaultLocaleCode
25714
- });
25715
- }
25716
- }
25717
- entries = omitDeep(entries, ["locale", "createdAt", "updatedAt", "publishedAt"]);
25718
- entries.forEach((entry) => {
25719
- const flatten = flattenObject({
25720
- [modelUid]: entry
25721
- });
25722
- const pickedFlatten = pickEntries(flatten, pickPathsWithUid);
25723
- pickedFlattenStrapiContent = {
25724
- ...pickedFlattenStrapiContent,
25725
- ...pickedFlatten
25726
- };
25727
- });
25728
- const characterLimitsMetadata = getCharacterLimitsMetadata(pickedFlattenStrapiContent, modelUid);
25729
- pickedFlattenStrapiContent = {
25730
- ...pickedFlattenStrapiContent,
25731
- ...characterLimitsMetadata
25732
- };
25733
- }
25734
- const localazyLocaleCode = strapiDefaultLocaleCode ? isoStrapiToLocalazy(strapiDefaultLocaleCode) : config.default.LOCALAZY_DEFAULT_LOCALE;
25735
- const importFile = LocalazyUploadService2.createImportFileRepresentation(
25736
- localazyLocaleCode,
25737
- pickedFlattenStrapiContent
25738
- );
25739
- const uploadConfig = {
25740
- contentOptions: {
25741
- type: config.default.LOCALAZY_DEFAULT_FILE_EXTENSION
25742
- },
25743
- i18nOptions: { deprecate: "file" },
25744
- fileOptions: {
25745
- name: config.default.LOCALAZY_DEFAULT_FILE_NAME,
25746
- path: config.default.LOCALAZY_DEFAULT_FILE_PATH
25747
- }
25748
- };
25749
- await notificationService.emit(EventType.UPLOAD, {
25750
- message: "Uploading collections to Localazy..."
25751
- });
25752
- await activityLogsService.addEntry(sessionId, "Uploading collections to Localazy...");
25753
- try {
25754
- await LocalazyUploadService2.upload(importFile, uploadConfig);
25755
- await activityLogsService.recordAttemptedEntries(
25756
- sessionId,
25757
- attemptedTuples.map((t3) => ({ ...t3, status: "success" }))
25758
- );
25759
- } catch (error) {
25760
- success = false;
25761
- const errorMessage = `Upload to Localazy failed: ${error instanceof Error ? error.message : String(error)}`;
25762
- strapi2.log.error(errorMessage);
25763
- await notificationService.emit(EventType.UPLOAD_FINISHED, {
25764
- success,
25765
- message: errorMessage
25766
- });
25767
- await activityLogsService.addEntry(sessionId, errorMessage);
25768
- await activityLogsService.recordAttemptedEntries(
25769
- sessionId,
25770
- attemptedTuples.map((t3) => ({ ...t3, status: "failed", errorMessage }))
25771
- );
25772
- await activityLogsService.finishSession(sessionId, "failed", errorMessage);
25773
- console.timeEnd("upload");
25774
- return;
25775
- }
25776
- strapi2.log.info("Upload finished in");
25777
- await notificationService.emit(EventType.UPLOAD_FINISHED, {
25778
- success,
25779
- message: "Upload finished"
25780
- });
25781
- await activityLogsService.addEntry(sessionId, "Upload finished");
25782
- await activityLogsService.finishSession(
25783
- sessionId,
25784
- success ? "completed" : "failed",
25785
- success ? "Upload completed successfully" : "Upload finished with errors"
25786
- );
25787
- console.timeEnd("upload");
25788
- }
25789
- });
25790
25614
  var symbolTag$2 = "[object Symbol]";
25791
25615
  function isSymbol(value) {
25792
25616
  return typeof value == "symbol" || isObjectLike(value) && baseGetTag(value) == symbolTag$2;
@@ -26093,20 +25917,274 @@ function baseSet(object, path, value, customizer) {
26093
25917
  newValue = isObject(objValue) ? objValue : isIndex(path[index2 + 1]) ? [] : {};
26094
25918
  }
26095
25919
  }
26096
- assignValue(nested, key, newValue);
26097
- nested = nested[key];
25920
+ assignValue(nested, key, newValue);
25921
+ nested = nested[key];
25922
+ }
25923
+ return object;
25924
+ }
25925
+ function set(object, path, value) {
25926
+ return object == null ? object : baseSet(object, path, value);
25927
+ }
25928
+ const BLOCKS_ATTRIBUTE_TYPE = "blocks";
25929
+ const projectBlocksFields = (entry, model, getModel) => {
25930
+ const cloned = cloneDeep(entry);
25931
+ walkAndProject(cloned, model, getModel);
25932
+ return cloned;
25933
+ };
25934
+ const walkAndProject = (value, model, getModel) => {
25935
+ if (!value || !model?.attributes) {
25936
+ return;
25937
+ }
25938
+ for (const [attributeName, attribute] of Object.entries(model.attributes)) {
25939
+ const fieldValue = value[attributeName];
25940
+ if (fieldValue === void 0 || fieldValue === null) {
25941
+ continue;
25942
+ }
25943
+ if (attribute.type === BLOCKS_ATTRIBUTE_TYPE) {
25944
+ value[attributeName] = projectBlocksValue(fieldValue);
25945
+ } else if (attribute.type === "component") {
25946
+ const componentModel = getModel(attribute.component);
25947
+ if (attribute.repeatable && Array.isArray(fieldValue)) {
25948
+ fieldValue.forEach((item) => walkAndProject(item, componentModel, getModel));
25949
+ } else if (isPlainObject(fieldValue)) {
25950
+ walkAndProject(fieldValue, componentModel, getModel);
25951
+ }
25952
+ } else if (attribute.type === "dynamiczone" && Array.isArray(fieldValue)) {
25953
+ fieldValue.forEach((item) => {
25954
+ if (item?.__component) {
25955
+ walkAndProject(item, getModel(item.__component), getModel);
25956
+ }
25957
+ });
25958
+ }
25959
+ }
25960
+ };
25961
+ const projectBlocksValue = (nodes) => {
25962
+ if (!Array.isArray(nodes)) {
25963
+ return nodes;
25964
+ }
25965
+ return nodes.map(projectNode);
25966
+ };
25967
+ const projectNode = (node) => {
25968
+ if (!isPlainObject(node)) {
25969
+ return {};
25970
+ }
25971
+ const projected = {};
25972
+ if (typeof node.text === "string") {
25973
+ projected.text = node.text;
25974
+ }
25975
+ if (Array.isArray(node.children)) {
25976
+ projected.children = node.children.map(projectNode);
25977
+ }
25978
+ return projected;
25979
+ };
25980
+ const overlayBlocksTranslation = (sourceAst, translated) => {
25981
+ if (!Array.isArray(sourceAst)) {
25982
+ return void 0;
25983
+ }
25984
+ return sourceAst.map((node, index2) => overlayNode(node, get(translated, [String(index2)])));
25985
+ };
25986
+ const overlayNode = (node, translatedNode) => {
25987
+ if (!isPlainObject(node)) {
25988
+ return cloneDeep(node);
25989
+ }
25990
+ if (typeof node.text === "string") {
25991
+ const translatedText = isPlainObject(translatedNode) ? translatedNode.text : void 0;
25992
+ return typeof translatedText === "string" ? { ...node, text: translatedText } : cloneDeep(node);
25993
+ }
25994
+ if (Array.isArray(node.children)) {
25995
+ return {
25996
+ ...node,
25997
+ children: node.children.map(
25998
+ (child, index2) => overlayNode(child, translatedNode ? get(translatedNode, ["children", String(index2)]) : void 0)
25999
+ )
26000
+ };
26001
+ }
26002
+ return cloneDeep(node);
26003
+ };
26004
+ const LocalazyTransferUploadService = ({ strapi: strapi2 }) => ({
26005
+ async upload({ notificationService }) {
26006
+ console.time("upload");
26007
+ await notificationService.emit(EventType.UPLOAD, {
26008
+ message: "Upload started"
26009
+ });
26010
+ const activityLogsService = getActivityLogsService();
26011
+ const sessionId = await activityLogsService.startSession("upload", "Strapi User");
26012
+ await activityLogsService.addEntry(sessionId, "Upload started");
26013
+ let success = true;
26014
+ const StrapiService2 = getStrapiService();
26015
+ const StrapiI18nService2 = getStrapiI18nService();
26016
+ const LocalazyUploadService2 = getLocalazyUploadService();
26017
+ const EntryExclusionService2 = getEntryExclusionService();
26018
+ const contentTransferSetup = await getPluginSettingsService().getContentTransferSetup();
26019
+ if (!contentTransferSetup.has_setup) {
26020
+ const message = "Content transfer setup is not set up.";
26021
+ success = false;
26022
+ await notificationService.emit(EventType.UPLOAD_FINISHED, {
26023
+ success,
26024
+ message
26025
+ });
26026
+ await activityLogsService.addEntry(sessionId, message);
26027
+ await activityLogsService.finishSession(sessionId, "failed", message);
26028
+ strapi2.log.info(message);
26029
+ return;
26030
+ }
26031
+ const { setup: setup2 } = contentTransferSetup;
26032
+ const collectionsNames = getCollectionsNames(setup2);
26033
+ const models = await StrapiService2.getModels();
26034
+ const strapiDefaultLocaleCode = await StrapiI18nService2.getDefaultLocaleCode();
26035
+ const attemptedTuples = [];
26036
+ let pickedFlattenStrapiContent = {};
26037
+ for (const collectionName of collectionsNames) {
26038
+ const currentModel = models.find((model) => model.collectionName === collectionName);
26039
+ const modelUid = currentModel.uid;
26040
+ if (!currentModel) {
26041
+ strapi2.log.warn(`Model with uid ${modelUid} is not found.`);
26042
+ continue;
26043
+ }
26044
+ const transferSetupModel = findSetupModelByCollectionName(setup2, collectionName);
26045
+ if (!isCollectionTransferEnabled(setup2, collectionName)) {
26046
+ const message2 = `Collection ${collectionName} transfer is disabled.`;
26047
+ await notificationService.emit(EventType.UPLOAD, {
26048
+ message: message2
26049
+ });
26050
+ await activityLogsService.addEntry(sessionId, message2);
26051
+ strapi2.log.info(message2);
26052
+ continue;
26053
+ }
26054
+ const currentTransferSetupModel = transferSetupModel[collectionName];
26055
+ const pickPaths = getPickPathsWithComponents(currentTransferSetupModel);
26056
+ if (!pickPaths.length) {
26057
+ const message2 = `No fields for collection ${collectionName} transfer are enabled.`;
26058
+ await notificationService.emit(EventType.UPLOAD, {
26059
+ message: message2
26060
+ });
26061
+ await activityLogsService.addEntry(sessionId, message2);
26062
+ strapi2.log.warn(message2);
26063
+ continue;
26064
+ }
26065
+ const pickPathsWithUid = pickPaths.map((pickPath) => `${modelUid}.${pickPath}`);
26066
+ let entries = await strapi2.documents(modelUid).findMany({
26067
+ locUploadPLevel: 6,
26068
+ status: "draft"
26069
+ });
26070
+ if (!entries.length) {
26071
+ strapi2.log.info(`No entries found for model ${modelUid}`);
26072
+ continue;
26073
+ }
26074
+ const excludedEntries = await EntryExclusionService2.getContentTypeExclusions(modelUid);
26075
+ const filteredEntries = [];
26076
+ for (const entry of entries) {
26077
+ const isExcluded = excludedEntries.includes(entry.documentId);
26078
+ if (!isExcluded) {
26079
+ filteredEntries.push(entry);
26080
+ }
26081
+ }
26082
+ entries = filteredEntries;
26083
+ if (!entries.length) {
26084
+ const message2 = `All entries for model ${collectionName} are excluded from translation`;
26085
+ await notificationService.emit(EventType.UPLOAD, {
26086
+ message: message2
26087
+ });
26088
+ await activityLogsService.addEntry(sessionId, message2);
26089
+ strapi2.log.info(message2);
26090
+ continue;
26091
+ }
26092
+ const message = `Excluding ${excludedEntries.length} entries for model ${collectionName} from upload. Entries to translate: ${entries.length}.`;
26093
+ await notificationService.emit(EventType.UPLOAD, {
26094
+ message
26095
+ });
26096
+ await activityLogsService.addEntry(sessionId, message);
26097
+ strapi2.log.info(message);
26098
+ if (strapiDefaultLocaleCode) {
26099
+ for (const entry of entries) {
26100
+ attemptedTuples.push({
26101
+ uid: modelUid,
26102
+ documentId: entry.documentId,
26103
+ locale: strapiDefaultLocaleCode
26104
+ });
26105
+ }
26106
+ }
26107
+ entries = omitDeep(entries, ["locale", "createdAt", "updatedAt", "publishedAt"]);
26108
+ entries.forEach((entry) => {
26109
+ const projectedEntry = projectBlocksFields(
26110
+ entry,
26111
+ strapi2.getModel(modelUid),
26112
+ (uid) => strapi2.getModel(uid)
26113
+ );
26114
+ const flatten = flattenObject({
26115
+ [modelUid]: projectedEntry
26116
+ });
26117
+ const pickedFlatten = pickEntries(flatten, pickPathsWithUid);
26118
+ pickedFlattenStrapiContent = {
26119
+ ...pickedFlattenStrapiContent,
26120
+ ...pickedFlatten
26121
+ };
26122
+ });
26123
+ const characterLimitsMetadata = getCharacterLimitsMetadata(pickedFlattenStrapiContent, modelUid);
26124
+ pickedFlattenStrapiContent = {
26125
+ ...pickedFlattenStrapiContent,
26126
+ ...characterLimitsMetadata
26127
+ };
26128
+ }
26129
+ const localazyLocaleCode = strapiDefaultLocaleCode ? isoStrapiToLocalazy(strapiDefaultLocaleCode) : config.default.LOCALAZY_DEFAULT_LOCALE;
26130
+ const importFile = LocalazyUploadService2.createImportFileRepresentation(
26131
+ localazyLocaleCode,
26132
+ pickedFlattenStrapiContent
26133
+ );
26134
+ const uploadConfig = {
26135
+ contentOptions: {
26136
+ type: config.default.LOCALAZY_DEFAULT_FILE_EXTENSION
26137
+ },
26138
+ i18nOptions: { deprecate: "file" },
26139
+ fileOptions: {
26140
+ name: config.default.LOCALAZY_DEFAULT_FILE_NAME,
26141
+ path: config.default.LOCALAZY_DEFAULT_FILE_PATH
26142
+ }
26143
+ };
26144
+ await notificationService.emit(EventType.UPLOAD, {
26145
+ message: "Uploading collections to Localazy..."
26146
+ });
26147
+ await activityLogsService.addEntry(sessionId, "Uploading collections to Localazy...");
26148
+ try {
26149
+ await LocalazyUploadService2.upload(importFile, uploadConfig);
26150
+ await activityLogsService.recordAttemptedEntries(
26151
+ sessionId,
26152
+ attemptedTuples.map((t3) => ({ ...t3, status: "success" }))
26153
+ );
26154
+ } catch (error) {
26155
+ success = false;
26156
+ const errorMessage = `Upload to Localazy failed: ${error instanceof Error ? error.message : String(error)}`;
26157
+ strapi2.log.error(errorMessage);
26158
+ await notificationService.emit(EventType.UPLOAD_FINISHED, {
26159
+ success,
26160
+ message: errorMessage
26161
+ });
26162
+ await activityLogsService.addEntry(sessionId, errorMessage);
26163
+ await activityLogsService.recordAttemptedEntries(
26164
+ sessionId,
26165
+ attemptedTuples.map((t3) => ({ ...t3, status: "failed", errorMessage }))
26166
+ );
26167
+ await activityLogsService.finishSession(sessionId, "failed", errorMessage);
26168
+ console.timeEnd("upload");
26169
+ return;
26170
+ }
26171
+ strapi2.log.info("Upload finished in");
26172
+ await notificationService.emit(EventType.UPLOAD_FINISHED, {
26173
+ success,
26174
+ message: "Upload finished"
26175
+ });
26176
+ await activityLogsService.addEntry(sessionId, "Upload finished");
26177
+ await activityLogsService.finishSession(
26178
+ sessionId,
26179
+ success ? "completed" : "failed",
26180
+ success ? "Upload completed successfully" : "Upload finished with errors"
26181
+ );
26182
+ console.timeEnd("upload");
26098
26183
  }
26099
- return object;
26100
- }
26101
- function set(object, path, value) {
26102
- return object == null ? object : baseSet(object, path, value);
26103
- }
26184
+ });
26104
26185
  const hasDynamicZoneKeySegment = (parsedKey) => {
26105
26186
  return parsedKey.some((segment) => segment.includes(";"));
26106
26187
  };
26107
- const getDynamicZoneKeySegment = (parsedKey) => {
26108
- return parsedKey.find((segment) => segment.includes(";"));
26109
- };
26110
26188
  const getComponentNameFromDynamicZoneKeySegment = (dynamicZoneKeySegment) => {
26111
26189
  return dynamicZoneKeySegment.split(";")[1];
26112
26190
  };
@@ -26126,52 +26204,116 @@ var ShouldSetDownloadedPropertyReturnType = /* @__PURE__ */ ((ShouldSetDownloade
26126
26204
  ShouldSetDownloadedPropertyReturnType2["JSON"] = "json";
26127
26205
  return ShouldSetDownloadedPropertyReturnType2;
26128
26206
  })(ShouldSetDownloadedPropertyReturnType || {});
26129
- const shouldSetDownloadedProperty = (modelContentTransferSetup, parsedKeyRest) => {
26207
+ const locateDownloadedField = (modelContentTransferSetup, parsedKeyRest) => {
26208
+ const notFound = { type: "no", fieldSegmentIndex: -1 };
26130
26209
  if (!modelContentTransferSetup.__model__) {
26131
- return "no";
26210
+ return notFound;
26132
26211
  }
26212
+ let setupModel = modelContentTransferSetup;
26213
+ let startIndex2 = 0;
26133
26214
  if (hasDynamicZoneKeySegment(parsedKeyRest)) {
26134
- const dynamicZonePropertyName = getDynamicZonePropertyName(parsedKeyRest);
26135
- const componentName = getComponentNameFromDynamicZoneKeySegment(getDynamicZoneKeySegment(parsedKeyRest));
26215
+ const dynamicZoneKeySegmentIndex = getDynamicZoneKeySegmentIndex(parsedKeyRest);
26216
+ const componentName = getComponentNameFromDynamicZoneKeySegment(parsedKeyRest[dynamicZoneKeySegmentIndex]);
26136
26217
  const dzContentTransferSetupModel = get(
26137
26218
  modelContentTransferSetup,
26138
- dynamicZonePropertyName
26219
+ getDynamicZonePropertyName(parsedKeyRest)
26139
26220
  );
26140
26221
  if (!Array.isArray(dzContentTransferSetupModel)) {
26141
- return "no";
26222
+ return notFound;
26142
26223
  }
26143
- const dzContentTransferSetupComponentModel = dzContentTransferSetupModel.find(
26144
- (c2) => c2.__component__ === componentName
26145
- );
26146
- if (!dzContentTransferSetupComponentModel) {
26147
- return "no";
26224
+ setupModel = dzContentTransferSetupModel.find((c2) => c2.__component__ === componentName);
26225
+ if (!setupModel) {
26226
+ return notFound;
26148
26227
  }
26149
- const dynamicZoneKeySegmentIndex = getDynamicZoneKeySegmentIndex(parsedKeyRest);
26150
- const slicedParsedKeyRest = parsedKeyRest.slice(dynamicZoneKeySegmentIndex + 1);
26151
- const filteredSlicedParsedKeyRest = slicedParsedKeyRest.filter((segment) => isNaN(parseInt(segment)));
26152
- if (get(dzContentTransferSetupComponentModel, filteredSlicedParsedKeyRest) === true) {
26153
- return "yes";
26154
- }
26155
- while (filteredSlicedParsedKeyRest.length > 0) {
26156
- filteredSlicedParsedKeyRest.pop();
26157
- if (get(dzContentTransferSetupComponentModel, filteredSlicedParsedKeyRest) === true) {
26158
- return "json";
26228
+ startIndex2 = dynamicZoneKeySegmentIndex + 1;
26229
+ }
26230
+ const namedSegmentIndexes = [];
26231
+ for (let index2 = startIndex2; index2 < parsedKeyRest.length; index2++) {
26232
+ if (isNaN(parseInt(parsedKeyRest[index2]))) {
26233
+ namedSegmentIndexes.push(index2);
26234
+ }
26235
+ }
26236
+ for (let length2 = namedSegmentIndexes.length; length2 > 0; length2--) {
26237
+ const fieldPath = namedSegmentIndexes.slice(0, length2).map((index2) => parsedKeyRest[index2]);
26238
+ if (get(setupModel, fieldPath) === true) {
26239
+ const fieldSegmentIndex = namedSegmentIndexes[length2 - 1];
26240
+ const type2 = fieldSegmentIndex === parsedKeyRest.length - 1 ? "yes" : "json";
26241
+ return { type: type2, fieldSegmentIndex };
26242
+ }
26243
+ }
26244
+ return notFound;
26245
+ };
26246
+ const createJsonFieldsDownloadAccumulator = () => {
26247
+ const fields = /* @__PURE__ */ new Map();
26248
+ return {
26249
+ /**
26250
+ * @param fieldKey path to the field in the parsed content: `[iso, uid, documentId, ...ownerPath, fieldName]`
26251
+ * @param valuePath path of this leaf inside the field's value
26252
+ */
26253
+ add(fieldKey, valuePath, value) {
26254
+ const id = JSON.stringify(fieldKey);
26255
+ let field = fields.get(id);
26256
+ if (!field) {
26257
+ field = { fieldKey, value: {} };
26258
+ fields.set(id, field);
26259
+ }
26260
+ set(field.value, valuePath, value);
26261
+ },
26262
+ /** Write every collected field value into `parsedContent` at its own path. */
26263
+ applyTo(parsedContent) {
26264
+ for (const { fieldKey, value } of fields.values()) {
26265
+ set(parsedContent, fieldKey, value);
26159
26266
  }
26160
26267
  }
26161
- return "no";
26162
- } else {
26163
- const filteredParsedKeyRest = parsedKeyRest.filter((partialKey) => isNaN(parseInt(partialKey)));
26164
- if (get(modelContentTransferSetup, filteredParsedKeyRest) === true) {
26165
- return "yes";
26166
- }
26167
- while (filteredParsedKeyRest.length > 0) {
26168
- filteredParsedKeyRest.pop();
26169
- if (get(modelContentTransferSetup, filteredParsedKeyRest) === true) {
26170
- return "json";
26268
+ };
26269
+ };
26270
+ const collectDownloadedContent = ({
26271
+ languages: languages2,
26272
+ processedKeys,
26273
+ contentTransferSetup,
26274
+ models,
26275
+ parseLocalazyKey: parseLocalazyKey2
26276
+ }) => {
26277
+ const parsedLocalazyContent = {};
26278
+ const entryKeySourceMap = {};
26279
+ const jsonFieldsAccumulator = createJsonFieldsDownloadAccumulator();
26280
+ for (const { isoStrapi, keys: keys2 } of languages2) {
26281
+ const parsedKeys = keys2.map((localazyEntry) => {
26282
+ const storedEvent = processedKeys[isoStrapi]?.[localazyEntry.id];
26283
+ const isChanged = !(storedEvent !== void 0 && localazyEntry.event !== void 0 && localazyEntry.event <= storedEvent);
26284
+ const parsedKey = parseLocalazyKey2(localazyEntry.key[0]);
26285
+ return { localazyEntry, parsedKey, isChanged, entryKey: `${isoStrapi}:${parsedKey.uid}:${parsedKey.id}` };
26286
+ });
26287
+ for (const { localazyEntry, entryKey, isChanged } of parsedKeys) {
26288
+ if (isChanged) {
26289
+ if (!entryKeySourceMap[entryKey]) {
26290
+ entryKeySourceMap[entryKey] = [];
26291
+ }
26292
+ entryKeySourceMap[entryKey].push({ lang: isoStrapi, id: localazyEntry.id, event: localazyEntry.event });
26293
+ }
26294
+ }
26295
+ for (const { localazyEntry, parsedKey, entryKey } of parsedKeys) {
26296
+ if (!entryKeySourceMap[entryKey]) {
26297
+ continue;
26298
+ }
26299
+ const modelContentTransferSetup = findSetupModelByCollectionUid(contentTransferSetup, models, parsedKey.uid);
26300
+ if (typeof modelContentTransferSetup === "undefined") {
26301
+ continue;
26302
+ }
26303
+ const { type: type2, fieldSegmentIndex } = locateDownloadedField(modelContentTransferSetup, parsedKey.rest);
26304
+ if (type2 === ShouldSetDownloadedPropertyReturnType.JSON) {
26305
+ jsonFieldsAccumulator.add(
26306
+ [isoStrapi, parsedKey.uid, parsedKey.id, ...parsedKey.rest.slice(0, fieldSegmentIndex + 1)],
26307
+ parsedKey.rest.slice(fieldSegmentIndex + 1),
26308
+ localazyEntry.value
26309
+ );
26310
+ } else if (type2 === ShouldSetDownloadedPropertyReturnType.YES) {
26311
+ set(parsedLocalazyContent, [isoStrapi, parsedKey.uid, parsedKey.id, ...parsedKey.rest], localazyEntry.value);
26171
26312
  }
26172
26313
  }
26173
- return "no";
26174
26314
  }
26315
+ jsonFieldsAccumulator.applyTo(parsedLocalazyContent);
26316
+ return { parsedLocalazyContent, entryKeySourceMap };
26175
26317
  };
26176
26318
  const getFilteredLanguagesCodesForDownload = async (languagesCodes, requestedUiLanguages) => {
26177
26319
  const pluginSettingsServiceHelper = new PluginSettingsServiceHelper();
@@ -26358,10 +26500,8 @@ const LocalazyTransferDownloadService = ({ strapi: strapi2 }) => ({
26358
26500
  }
26359
26501
  await persistCursor();
26360
26502
  };
26361
- const parsedLocalazyContent = {};
26362
26503
  const strapiContentTypesModels = await StrapiService2.getModels();
26363
- const jsonFields = [];
26364
- const entryKeySourceMap = {};
26504
+ const languagesToParse = [];
26365
26505
  for (const [isoLocalazy, keys2] of Object.entries(localazyContent)) {
26366
26506
  const isoStrapi = isoLocalazyToStrapi(isoLocalazy);
26367
26507
  if (!isoStrapi) {
@@ -26370,78 +26510,15 @@ const LocalazyTransferDownloadService = ({ strapi: strapi2 }) => ({
26370
26510
  });
26371
26511
  continue;
26372
26512
  }
26373
- for (const localazyEntry of keys2) {
26374
- const key = localazyEntry.key[0];
26375
- const value = localazyEntry.value;
26376
- const localazyKeyId = localazyEntry.id;
26377
- const localazyKeyEvent = localazyEntry.event;
26378
- const storedEvent = processedKeys[isoStrapi]?.[localazyKeyId];
26379
- if (storedEvent !== void 0 && localazyKeyEvent !== void 0 && localazyKeyEvent <= storedEvent) {
26380
- continue;
26381
- }
26382
- const parsedKey = StrapiI18nService2.parseLocalazyKey(key);
26383
- const entryKey = `${isoStrapi}:${parsedKey.uid}:${parsedKey.id}`;
26384
- if (!entryKeySourceMap[entryKey]) {
26385
- entryKeySourceMap[entryKey] = [];
26386
- }
26387
- entryKeySourceMap[entryKey].push({ lang: isoStrapi, id: localazyKeyId, event: localazyKeyEvent });
26388
- const modelContentTransferSetup = findSetupModelByCollectionUid(
26389
- contentTransferSetup,
26390
- strapiContentTypesModels,
26391
- parsedKey.uid
26392
- );
26393
- if (typeof modelContentTransferSetup !== "undefined") {
26394
- const shouldSetDownloadedPropertyResult = shouldSetDownloadedProperty(
26395
- modelContentTransferSetup,
26396
- parsedKey.rest
26397
- );
26398
- if (shouldSetDownloadedPropertyResult === ShouldSetDownloadedPropertyReturnType.NO) {
26399
- continue;
26400
- }
26401
- let parsedKeyRestWithoutComponents = parsedKey.rest;
26402
- if (shouldSetDownloadedPropertyResult === ShouldSetDownloadedPropertyReturnType.JSON) {
26403
- const setKey = [isoStrapi, parsedKey.uid, parsedKey.id];
26404
- let updatedParsedKeyRestWithoutComponents = parsedKeyRestWithoutComponents;
26405
- let segmentsToAdd = [];
26406
- for (const segment of parsedKeyRestWithoutComponents) {
26407
- const hasEntry = get(modelContentTransferSetup, [...segmentsToAdd, segment]);
26408
- const hasEntryNotFinal = hasEntry && typeof hasEntry !== "boolean";
26409
- const isComponent2 = parseInt(segment) > 0;
26410
- if (hasEntryNotFinal || !hasEntry && isComponent2) {
26411
- segmentsToAdd.push(segment);
26412
- setKey.push(segment);
26413
- updatedParsedKeyRestWithoutComponents = updatedParsedKeyRestWithoutComponents.slice(1);
26414
- } else {
26415
- break;
26416
- }
26417
- }
26418
- parsedKeyRestWithoutComponents = updatedParsedKeyRestWithoutComponents;
26419
- let foundJsonFieldIndex = jsonFields.findIndex((jsonField) => {
26420
- return jsonField.setKey.join() === setKey.join();
26421
- });
26422
- if (foundJsonFieldIndex === -1) {
26423
- jsonFields.push({
26424
- setKey,
26425
- jsonKey: parsedKeyRestWithoutComponents[0],
26426
- jsonValue: {}
26427
- });
26428
- }
26429
- foundJsonFieldIndex = foundJsonFieldIndex === -1 ? jsonFields.length - 1 : foundJsonFieldIndex;
26430
- const foundJsonField = jsonFields[foundJsonFieldIndex];
26431
- const restSliced = parsedKeyRestWithoutComponents.slice(1);
26432
- set(foundJsonField, ["jsonValue", ...restSliced], value);
26433
- jsonFields[foundJsonFieldIndex] = foundJsonField;
26434
- }
26435
- if (shouldSetDownloadedPropertyResult === ShouldSetDownloadedPropertyReturnType.YES) {
26436
- const setKey = [isoStrapi, parsedKey.uid, parsedKey.id, ...parsedKeyRestWithoutComponents];
26437
- set(parsedLocalazyContent, setKey, value);
26438
- }
26439
- }
26440
- }
26441
- }
26442
- for (const jsonField of jsonFields) {
26443
- set(parsedLocalazyContent, [...jsonField.setKey, jsonField.jsonKey], jsonField.jsonValue);
26444
- }
26513
+ languagesToParse.push({ isoStrapi, keys: keys2 });
26514
+ }
26515
+ const { parsedLocalazyContent, entryKeySourceMap } = collectDownloadedContent({
26516
+ languages: languagesToParse,
26517
+ processedKeys,
26518
+ contentTransferSetup,
26519
+ models: strapiContentTypesModels,
26520
+ parseLocalazyKey: (key) => StrapiI18nService2.parseLocalazyKey(key)
26521
+ });
26445
26522
  for (const [isoStrapi, contentTypes2] of Object.entries(parsedLocalazyContent)) {
26446
26523
  for (const [uid, models] of Object.entries(contentTypes2)) {
26447
26524
  const strapiContentTypeModel = strapiContentTypesModels.find((model) => model.uid === uid);
@@ -26625,6 +26702,15 @@ const intlDisplayName = (isoStrapi) => {
26625
26702
  }
26626
26703
  return languageNames.of(isoStrapi.toLowerCase());
26627
26704
  };
26705
+ const parseLocalazyKey = (key) => {
26706
+ const split = key.split(/\.(?![^[]*])|\[|\]/);
26707
+ const filteredSplit = split.filter((item) => item !== "");
26708
+ return {
26709
+ uid: `${filteredSplit[0]}.${filteredSplit[1]}`,
26710
+ id: filteredSplit[2],
26711
+ rest: filteredSplit.slice(3)
26712
+ };
26713
+ };
26628
26714
  const StrapiI18nService = ({ strapi: strapi2 }) => ({
26629
26715
  async getLocales() {
26630
26716
  return strapi2.plugin("i18n").service("locales").find();
@@ -26652,13 +26738,7 @@ const StrapiI18nService = ({ strapi: strapi2 }) => ({
26652
26738
  }
26653
26739
  },
26654
26740
  parseLocalazyKey(key) {
26655
- const split = key.split(/\.(?![^[]*])|\[|\]/);
26656
- const filteredSplit = split.filter((item) => item !== "");
26657
- return {
26658
- uid: `${filteredSplit[0]}.${filteredSplit[1]}`,
26659
- id: filteredSplit[2],
26660
- rest: filteredSplit.slice(3)
26661
- };
26741
+ return parseLocalazyKey(key);
26662
26742
  },
26663
26743
  async getEntryInLocale(modelUid, documentId, isoStrapi) {
26664
26744
  const entry = await strapi2.documents(modelUid).findOne({
@@ -26757,18 +26837,6 @@ const LocalazyUploadService = ({ strapi: strapi2 }) => ({
26757
26837
  return file;
26758
26838
  }
26759
26839
  });
26760
- const resetArrayKeysDeep = (object, keysToFilter) => {
26761
- const sortedKeysToFilter = keysToFilter.sort((a2, b2) => {
26762
- const aLvl = a2.match(/\./g)?.length || 0;
26763
- const bLvl = b2.match(/\./g)?.length || 0;
26764
- return bLvl - aLvl;
26765
- });
26766
- for (const key of sortedKeysToFilter) {
26767
- const part = get(object, key);
26768
- const filteredPart = part.filter((item) => item !== void 0);
26769
- set(object, key, filteredPart);
26770
- }
26771
- };
26772
26840
  const getAttribute = (model, attribute) => {
26773
26841
  if (isEmpty(model)) {
26774
26842
  return void 0;
@@ -26788,22 +26856,66 @@ const isRepeatable = (attributeObj) => {
26788
26856
  const isRelation = (attributeObj) => {
26789
26857
  return attributeObj.type === "relation" && attributeObj.target !== "plugin::upload.file";
26790
26858
  };
26859
+ const isBlocks = (attributeObj) => {
26860
+ return attributeObj.type === BLOCKS_ATTRIBUTE_TYPE;
26861
+ };
26862
+ const isJson = (attributeObj) => {
26863
+ return attributeObj.type === "json";
26864
+ };
26791
26865
  const findModel = (models, uid) => {
26792
26866
  const model = models.find((model2) => model2.uid === uid);
26793
26867
  return model;
26794
26868
  };
26869
+ const arrayItemSegment = (item, index2) => {
26870
+ if (isPlainObject(item) && item.id && item.__component) {
26871
+ return `${item.id};${item.__component}`;
26872
+ }
26873
+ return String(item?.documentId || item?.id || index2);
26874
+ };
26875
+ const objectIdSegment = (value) => {
26876
+ if (isPlainObject(value) && (value.documentId || value.id)) {
26877
+ return String(value.documentId || value.id);
26878
+ }
26879
+ return void 0;
26880
+ };
26881
+ const overlayValue = (source, translated) => {
26882
+ if (typeof source === "string") {
26883
+ return typeof translated === "string" ? translated : source;
26884
+ }
26885
+ if (Array.isArray(source)) {
26886
+ return source.map((item, index2) => overlayValue(item, get(translated, [arrayItemSegment(item, index2)])));
26887
+ }
26888
+ if (isPlainObject(source)) {
26889
+ const result = {};
26890
+ for (const [key, value] of Object.entries(source)) {
26891
+ result[key] = key === "id" || key === "documentId" ? value : overlayChild(value, get(translated, [key]));
26892
+ }
26893
+ return result;
26894
+ }
26895
+ return source;
26896
+ };
26897
+ const overlayChild = (source, translated) => {
26898
+ const idSegment = Array.isArray(source) ? void 0 : objectIdSegment(source);
26899
+ return overlayValue(source, idSegment ? get(translated, [idSegment]) : translated);
26900
+ };
26901
+ const overlayJsonTranslation = (sourceValue, translated) => {
26902
+ if (sourceValue === void 0 || sourceValue === null) {
26903
+ return void 0;
26904
+ }
26905
+ if (typeof sourceValue !== "object") {
26906
+ return typeof sourceValue === "string" && typeof translated === "string" ? translated : sourceValue;
26907
+ }
26908
+ return overlayChild(cloneDeep(sourceValue), translated);
26909
+ };
26795
26910
  const parsedLocalazyEntryToCreateEntry = (models, parsedLocalazyEntry, baseEntry, uid, locale = "") => {
26796
26911
  const createEntry = {};
26797
- const repeatableComponentsKeystoFilter = [];
26798
26912
  const dynamicZoneComponentKeys = [];
26913
+ const rebuiltFieldPaths = [];
26799
26914
  const toCreateEntry = (entry, model2, key = "", prefix = "", component = "", isRepeatableComponent = false, isDZ = false, isInsideDZ = false) => {
26800
26915
  if (Array.isArray(entry)) {
26801
26916
  Object.entries(entry).forEach(([baseEntryItemId, value]) => {
26802
26917
  if (value !== null) {
26803
26918
  if (component && isRepeatableComponent) {
26804
- if (!repeatableComponentsKeystoFilter.includes(prefix)) {
26805
- repeatableComponentsKeystoFilter.push(prefix);
26806
- }
26807
26919
  const baseEntryRepeatableItemId = parseInt(baseEntryItemId);
26808
26920
  const baseEntryRepeateableGroup = get(baseEntry, prefix);
26809
26921
  if (baseEntryRepeateableGroup !== void 0) {
@@ -26825,9 +26937,6 @@ const parsedLocalazyEntryToCreateEntry = (models, parsedLocalazyEntry, baseEntry
26825
26937
  toCreateEntry(value, model2, `${prefix}`, `${prefix}`);
26826
26938
  }
26827
26939
  if (!component && isRepeatableComponent) {
26828
- if (!repeatableComponentsKeystoFilter.includes(prefix)) {
26829
- repeatableComponentsKeystoFilter.push(prefix);
26830
- }
26831
26940
  const baseEntryRepeatableItemId = parseInt(baseEntryItemId);
26832
26941
  const baseEntryRepeateableGroup = get(baseEntry, prefix);
26833
26942
  if (baseEntryRepeateableGroup !== void 0) {
@@ -26931,7 +27040,20 @@ const parsedLocalazyEntryToCreateEntry = (models, parsedLocalazyEntry, baseEntry
26931
27040
  newPrefixBase = `${dzParamKey}.${baseEntryDZIndex}`;
26932
27041
  newPrefix = `${newPrefixBase}.${objectKey}`;
26933
27042
  }
26934
- set(createEntry, newPrefix, value);
27043
+ const isRebuiltField = isBlocks(attribute) || isJson(attribute);
27044
+ let valueToSet = value;
27045
+ if (isBlocks(attribute)) {
27046
+ valueToSet = overlayBlocksTranslation(get(baseEntry, newPrefix), value);
27047
+ } else if (isJson(attribute)) {
27048
+ valueToSet = overlayJsonTranslation(get(baseEntry, newPrefix), value);
27049
+ }
27050
+ if (valueToSet === void 0) {
27051
+ return;
27052
+ }
27053
+ set(createEntry, newPrefix, valueToSet);
27054
+ if (isRebuiltField) {
27055
+ rebuiltFieldPaths.push(newPrefix);
27056
+ }
26935
27057
  if (component) {
26936
27058
  const componentKeyToSet = `${newPrefixBase}.__component`;
26937
27059
  set(createEntry, componentKeyToSet, component);
@@ -26953,8 +27075,59 @@ const parsedLocalazyEntryToCreateEntry = (models, parsedLocalazyEntry, baseEntry
26953
27075
  if (locale) {
26954
27076
  createEntry.locale = locale;
26955
27077
  }
26956
- resetArrayKeysDeep(createEntry, repeatableComponentsKeystoFilter);
26957
- return { createEntry, dynamicZoneComponentKeys };
27078
+ return { createEntry, dynamicZoneComponentKeys, rebuiltFieldPaths };
27079
+ };
27080
+ const isMediaObject = (obj) => {
27081
+ if (typeof obj !== "object" || obj === null) return false;
27082
+ return "url" in obj && "name" in obj && "ext" in obj && ("mime" in obj || "mimeType" in obj) && typeof obj.url === "string" && typeof obj.name === "string" && typeof obj.ext === "string";
27083
+ };
27084
+ const dropPropertyDeepWithSkip = (obj, propertyName, isRoot = true, skipPredicates = []) => {
27085
+ if (Array.isArray(obj)) {
27086
+ return obj.filter((item) => {
27087
+ if (skipPredicates.length > 0) {
27088
+ return true;
27089
+ }
27090
+ return isRoot || !(typeof item === "object" && item !== null && propertyName in item);
27091
+ }).map(
27092
+ (item) => typeof item === "object" && item !== null ? dropPropertyDeepWithSkip(item, propertyName, false, skipPredicates) : item
27093
+ );
27094
+ }
27095
+ if (typeof obj === "object" && obj !== null) {
27096
+ const shouldSkip = skipPredicates.some((predicate) => predicate(obj));
27097
+ if (shouldSkip) {
27098
+ const result2 = {};
27099
+ for (const key in obj) {
27100
+ if (key === propertyName) {
27101
+ result2[key] = obj[key];
27102
+ } else {
27103
+ result2[key] = typeof obj[key] === "object" && obj[key] !== null ? dropPropertyDeepWithSkip(obj[key], propertyName, false, skipPredicates) : obj[key];
27104
+ }
27105
+ }
27106
+ return result2;
27107
+ }
27108
+ const result = {};
27109
+ for (const key in obj) {
27110
+ if (key === propertyName && !isRoot) {
27111
+ continue;
27112
+ }
27113
+ result[key] = typeof obj[key] === "object" && obj[key] !== null ? dropPropertyDeepWithSkip(obj[key], propertyName, false, skipPredicates) : obj[key];
27114
+ }
27115
+ return result;
27116
+ }
27117
+ return obj;
27118
+ };
27119
+ const dropDocumentIdExceptMedia = (obj) => {
27120
+ return dropPropertyDeepWithSkip(obj, "documentId", true, [isMediaObject]);
27121
+ };
27122
+ const OMIT_KEYS = ["locale", "localizations", "createdAt", "createdBy", "updatedAt", "updatedBy", "publishedAt"];
27123
+ const buildLocalizedCreateEntry = (models, translatedModel, baseEntry, uid, isoStrapi) => {
27124
+ const { createEntry } = parsedLocalazyEntryToCreateEntry(models, translatedModel, baseEntry, uid, isoStrapi);
27125
+ const filteredBaseEntry = dropDocumentIdExceptMedia(omitDeep(baseEntry, OMIT_KEYS));
27126
+ let mergedCreateEntry = {};
27127
+ merge(mergedCreateEntry, filteredBaseEntry, createEntry);
27128
+ mergedCreateEntry = omitDeep(mergedCreateEntry, OMIT_KEYS);
27129
+ mergedCreateEntry.locale = isoStrapi;
27130
+ return mergedCreateEntry;
26958
27131
  };
26959
27132
  const doesExistInPopulatedLocalizedEntry = (val) => {
26960
27133
  if (Array.isArray(val)) {
@@ -26993,17 +27166,17 @@ const populateCreateUpdateEntryWithBaseEntry = async (models, createUpdateEntry,
26993
27166
  }
26994
27167
  }
26995
27168
  } else if (!component && isRepeatableComponent && isDZ) {
26996
- Object.entries(partialBaseEntry).forEach(async ([partialBaseEntryItemIndex, partialBaseEntryItem]) => {
27169
+ for (const [partialBaseEntryItemIndex, partialBaseEntryItem] of Object.entries(partialBaseEntry)) {
26997
27170
  const component2 = partialBaseEntryItem.__component;
26998
27171
  const model3 = findModel(models, component2);
26999
27172
  const newPrefix = `${prefix}.${partialBaseEntryItemIndex}`;
27000
27173
  await populateEntry(partialBaseEntryItem, model3, partialBaseEntryItemIndex, newPrefix);
27001
- });
27174
+ }
27002
27175
  } else if (component && isRepeatableComponent) {
27003
- Object.entries(partialBaseEntry).forEach(async ([partialBaseEntryItemIndex, partialBaseEntryItem]) => {
27176
+ for (const [partialBaseEntryItemIndex, partialBaseEntryItem] of Object.entries(partialBaseEntry)) {
27004
27177
  const newPrefix = `${prefix}.${partialBaseEntryItemIndex}`;
27005
27178
  await populateEntry(partialBaseEntryItem, model2, partialBaseEntryItemIndex, newPrefix);
27006
- });
27179
+ }
27007
27180
  }
27008
27181
  } else if (typeof partialBaseEntry === "object") {
27009
27182
  if (partialBaseEntry === null) {
@@ -27116,7 +27289,7 @@ const populateCreateUpdateEntryWithBaseEntry = async (models, createUpdateEntry,
27116
27289
  } else {
27117
27290
  set(populatedEntry, newPrefix, value);
27118
27291
  }
27119
- } else {
27292
+ } else if (!isBlocks(attribute) && !isJson(attribute)) {
27120
27293
  await populateEntry(value, model2, objectKey2, newPrefix);
27121
27294
  }
27122
27295
  }
@@ -27138,15 +27311,80 @@ const populateCreateUpdateEntryWithBaseEntry = async (models, createUpdateEntry,
27138
27311
  await populateEntry(baseEntry, model);
27139
27312
  return populatedEntry;
27140
27313
  };
27314
+ const dropComponentIds = (models, item, model) => {
27315
+ if (!isPlainObject(item)) {
27316
+ return;
27317
+ }
27318
+ delete item.id;
27319
+ for (const [name2, attribute] of Object.entries(model?.attributes || {})) {
27320
+ const value = item[name2];
27321
+ if (attribute.type === "component") {
27322
+ const componentModel = findModel(models, attribute.component);
27323
+ (Array.isArray(value) ? value : [value]).forEach((child) => dropComponentIds(models, child, componentModel));
27324
+ } else if (attribute.type === "dynamiczone" && Array.isArray(value)) {
27325
+ value.forEach((child) => dropComponentIds(models, child, findModel(models, child?.__component)));
27326
+ }
27327
+ }
27328
+ };
27329
+ const asNewComponent = (models, sourceItem, model) => {
27330
+ const copy = cloneDeep(sourceItem);
27331
+ dropComponentIds(models, copy, model);
27332
+ return copy;
27333
+ };
27334
+ const alignLocalizedEntryToSource = (models, localizedEntry, sourceEntry, model, downloadedEntry) => {
27335
+ if (!isPlainObject(localizedEntry) || !isPlainObject(sourceEntry) || !isPlainObject(downloadedEntry)) {
27336
+ return localizedEntry;
27337
+ }
27338
+ const aligned = { ...localizedEntry };
27339
+ for (const [name2, attribute] of Object.entries(model?.attributes || {})) {
27340
+ const source = sourceEntry[name2];
27341
+ const current = localizedEntry[name2];
27342
+ const downloaded = downloadedEntry[name2];
27343
+ if (downloaded === void 0 || downloaded === null || current === void 0) {
27344
+ continue;
27345
+ }
27346
+ if (attribute.type === "component") {
27347
+ const componentModel = findModel(models, attribute.component);
27348
+ if (attribute.repeatable) {
27349
+ if (!Array.isArray(source)) continue;
27350
+ const currentItems = Array.isArray(current) ? current : [];
27351
+ aligned[name2] = currentItems.length === source.length ? currentItems.map(
27352
+ (item, index2) => alignLocalizedEntryToSource(models, item, source[index2], componentModel, downloaded[index2])
27353
+ ) : source.map((item) => asNewComponent(models, item, componentModel));
27354
+ } else if (isPlainObject(source) && isPlainObject(current)) {
27355
+ aligned[name2] = alignLocalizedEntryToSource(models, current, source, componentModel, downloaded);
27356
+ }
27357
+ } else if (attribute.type === "dynamiczone") {
27358
+ if (!Array.isArray(source)) continue;
27359
+ const currentItems = Array.isArray(current) ? current : [];
27360
+ const sameLayout = currentItems.length === source.length && currentItems.every((item, index2) => item?.__component === source[index2]?.__component);
27361
+ aligned[name2] = sameLayout ? currentItems.map(
27362
+ (item, index2) => alignLocalizedEntryToSource(
27363
+ models,
27364
+ item,
27365
+ source[index2],
27366
+ findModel(models, item.__component),
27367
+ downloaded[index2]
27368
+ )
27369
+ ) : source.map((item) => asNewComponent(models, item, findModel(models, item.__component)));
27370
+ }
27371
+ }
27372
+ return aligned;
27373
+ };
27141
27374
  const parsedLocalazyEntryToUpdateEntry = async (allModels, localazyEntry, fullyPopulatedLocalizedEntry, currentEntry, baseEntry, uid, locale) => {
27142
- const { createEntry, dynamicZoneComponentKeys } = parsedLocalazyEntryToCreateEntry(
27375
+ const { createEntry, dynamicZoneComponentKeys, rebuiltFieldPaths } = parsedLocalazyEntryToCreateEntry(
27143
27376
  allModels,
27144
27377
  localazyEntry,
27145
27378
  baseEntry,
27146
27379
  uid
27147
27380
  );
27381
+ const model = findModel(allModels, uid);
27382
+ const alignedCurrentEntry = alignLocalizedEntryToSource(allModels, currentEntry, baseEntry, model, createEntry);
27148
27383
  let updateEntry = {};
27149
- merge(updateEntry, currentEntry, createEntry);
27384
+ merge(updateEntry, alignedCurrentEntry, createEntry);
27385
+ for (const rebuiltFieldPath of rebuiltFieldPaths) {
27386
+ set(updateEntry, rebuiltFieldPath, cloneDeep(get(createEntry, rebuiltFieldPath)));
27387
+ }
27150
27388
  updateEntry = omitDeep(updateEntry, [
27151
27389
  // '__component', // do not omit the __component
27152
27390
  "locale",
@@ -27170,16 +27408,19 @@ const parsedLocalazyEntryToUpdateEntry = async (allModels, localazyEntry, fullyP
27170
27408
  "updatedBy",
27171
27409
  "publishedAt"
27172
27410
  ]);
27173
- const filteredFullyPopulatedLocalizedEntry = omitDeep(fullyPopulatedLocalizedEntry, [
27174
- // "__component", // do not omit the __component
27175
- "locale",
27176
- "localizations",
27177
- "createdAt",
27178
- "createdBy",
27179
- "updatedAt",
27180
- "updatedBy",
27181
- "publishedAt"
27182
- ]);
27411
+ const filteredFullyPopulatedLocalizedEntry = omitDeep(
27412
+ alignLocalizedEntryToSource(allModels, fullyPopulatedLocalizedEntry, baseEntry, model, createEntry),
27413
+ [
27414
+ // "__component", // do not omit the __component
27415
+ "locale",
27416
+ "localizations",
27417
+ "createdAt",
27418
+ "createdBy",
27419
+ "updatedAt",
27420
+ "updatedBy",
27421
+ "publishedAt"
27422
+ ]
27423
+ );
27183
27424
  const populatedEntry = await populateCreateUpdateEntryWithBaseEntry(
27184
27425
  allModels,
27185
27426
  updateEntry,
@@ -27190,65 +27431,16 @@ const parsedLocalazyEntryToUpdateEntry = async (allModels, localazyEntry, fullyP
27190
27431
  );
27191
27432
  return populatedEntry;
27192
27433
  };
27193
- const isMediaObject = (obj) => {
27194
- if (typeof obj !== "object" || obj === null) return false;
27195
- return "url" in obj && "name" in obj && "ext" in obj && ("mime" in obj || "mimeType" in obj) && typeof obj.url === "string" && typeof obj.name === "string" && typeof obj.ext === "string";
27196
- };
27197
- const dropPropertyDeepWithSkip = (obj, propertyName, isRoot = true, skipPredicates = []) => {
27198
- if (Array.isArray(obj)) {
27199
- return obj.filter((item) => {
27200
- if (skipPredicates.length > 0) {
27201
- return true;
27202
- }
27203
- return isRoot || !(typeof item === "object" && item !== null && propertyName in item);
27204
- }).map(
27205
- (item) => typeof item === "object" && item !== null ? dropPropertyDeepWithSkip(item, propertyName, false, skipPredicates) : item
27206
- );
27207
- }
27208
- if (typeof obj === "object" && obj !== null) {
27209
- const shouldSkip = skipPredicates.some((predicate) => predicate(obj));
27210
- if (shouldSkip) {
27211
- const result2 = {};
27212
- for (const key in obj) {
27213
- if (key === propertyName) {
27214
- result2[key] = obj[key];
27215
- } else {
27216
- result2[key] = typeof obj[key] === "object" && obj[key] !== null ? dropPropertyDeepWithSkip(obj[key], propertyName, false, skipPredicates) : obj[key];
27217
- }
27218
- }
27219
- return result2;
27220
- }
27221
- const result = {};
27222
- for (const key in obj) {
27223
- if (key === propertyName && !isRoot) {
27224
- continue;
27225
- }
27226
- result[key] = typeof obj[key] === "object" && obj[key] !== null ? dropPropertyDeepWithSkip(obj[key], propertyName, false, skipPredicates) : obj[key];
27227
- }
27228
- return result;
27229
- }
27230
- return obj;
27231
- };
27232
- const dropDocumentIdExceptMedia = (obj) => {
27233
- return dropPropertyDeepWithSkip(obj, "documentId", true, [isMediaObject]);
27234
- };
27235
27434
  const StrapiLocalazyI18nService = ({ strapi: strapi2 }) => ({
27236
27435
  async createEntry(uid, strapiContentTypesModels, translatedModel, baseEntry, isoStrapi) {
27237
27436
  const StrapiI18nService2 = getStrapiI18nService();
27238
- const { createEntry } = parsedLocalazyEntryToCreateEntry(
27437
+ const mergedCreateEntry = buildLocalizedCreateEntry(
27239
27438
  strapiContentTypesModels,
27240
27439
  translatedModel,
27241
27440
  baseEntry,
27242
27441
  uid,
27243
27442
  isoStrapi
27244
27443
  );
27245
- const omitKeys = ["locale", "localizations", "createdAt", "createdBy", "updatedAt", "updatedBy", "publishedAt"];
27246
- let filteredBaseEntry = omitDeep(baseEntry, omitKeys);
27247
- filteredBaseEntry = dropDocumentIdExceptMedia(filteredBaseEntry);
27248
- let mergedCreateEntry = {};
27249
- merge(mergedCreateEntry, filteredBaseEntry, createEntry);
27250
- mergedCreateEntry = omitDeep(mergedCreateEntry, omitKeys);
27251
- mergedCreateEntry.locale = isoStrapi;
27252
27444
  const createdEntry = await StrapiI18nService2.createLocalizationForAnExistingEntry(
27253
27445
  uid,
27254
27446
  baseEntry,