@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
@@ -20534,7 +20534,7 @@ var distExports = dist$1.exports;
20534
20534
  const io = /* @__PURE__ */ getDefaultExportFromCjs(distExports);
20535
20535
  const { Server: Server2, Namespace, Socket: Socket3 } = io;
20536
20536
  const name = "@localazy/strapi-plugin";
20537
- const version = "1.6.0";
20537
+ const version = "1.7.1";
20538
20538
  const description = "The official Strapi Plugin by Localazy.";
20539
20539
  const keywords = [
20540
20540
  "strapi",
@@ -22052,7 +22052,7 @@ const findSetupModelByCollectionUid = (contentTransferSetup, strapiContentTypesM
22052
22052
  const modelContentTransferSetup = contentTransferSetup.setup.find(
22053
22053
  (model) => Object.keys(model)[0] === currentModel.collectionName
22054
22054
  );
22055
- return modelContentTransferSetup[currentModel.collectionName];
22055
+ return modelContentTransferSetup?.[currentModel.collectionName];
22056
22056
  };
22057
22057
  const getCollectionsNames = (setup2) => {
22058
22058
  return getMainKeysOfNestedArrayObjects(setup2);
@@ -25625,182 +25625,6 @@ const PluginSettingsService = ({ strapi: strapi2 }) => ({
25625
25625
  return cursor;
25626
25626
  }
25627
25627
  });
25628
- const LocalazyTransferUploadService = ({ strapi: strapi2 }) => ({
25629
- async upload({ notificationService }) {
25630
- console.time("upload");
25631
- await notificationService.emit(EventType.UPLOAD, {
25632
- message: "Upload started"
25633
- });
25634
- const activityLogsService = getActivityLogsService();
25635
- const sessionId = await activityLogsService.startSession("upload", "Strapi User");
25636
- await activityLogsService.addEntry(sessionId, "Upload started");
25637
- let success = true;
25638
- const StrapiService2 = getStrapiService();
25639
- const StrapiI18nService2 = getStrapiI18nService();
25640
- const LocalazyUploadService2 = getLocalazyUploadService();
25641
- const EntryExclusionService2 = getEntryExclusionService();
25642
- const contentTransferSetup = await getPluginSettingsService().getContentTransferSetup();
25643
- if (!contentTransferSetup.has_setup) {
25644
- const message = "Content transfer setup is not set up.";
25645
- success = false;
25646
- await notificationService.emit(EventType.UPLOAD_FINISHED, {
25647
- success,
25648
- message
25649
- });
25650
- await activityLogsService.addEntry(sessionId, message);
25651
- await activityLogsService.finishSession(sessionId, "failed", message);
25652
- strapi2.log.info(message);
25653
- return;
25654
- }
25655
- const { setup: setup2 } = contentTransferSetup;
25656
- const collectionsNames = getCollectionsNames(setup2);
25657
- const models = await StrapiService2.getModels();
25658
- const strapiDefaultLocaleCode = await StrapiI18nService2.getDefaultLocaleCode();
25659
- const attemptedTuples = [];
25660
- let pickedFlattenStrapiContent = {};
25661
- for (const collectionName of collectionsNames) {
25662
- const currentModel = models.find((model) => model.collectionName === collectionName);
25663
- const modelUid = currentModel.uid;
25664
- if (!currentModel) {
25665
- strapi2.log.warn(`Model with uid ${modelUid} is not found.`);
25666
- continue;
25667
- }
25668
- const transferSetupModel = findSetupModelByCollectionName(setup2, collectionName);
25669
- if (!isCollectionTransferEnabled(setup2, collectionName)) {
25670
- const message2 = `Collection ${collectionName} transfer is disabled.`;
25671
- await notificationService.emit(EventType.UPLOAD, {
25672
- message: message2
25673
- });
25674
- await activityLogsService.addEntry(sessionId, message2);
25675
- strapi2.log.info(message2);
25676
- continue;
25677
- }
25678
- const currentTransferSetupModel = transferSetupModel[collectionName];
25679
- const pickPaths = getPickPathsWithComponents(currentTransferSetupModel);
25680
- if (!pickPaths.length) {
25681
- const message2 = `No fields for collection ${collectionName} transfer are enabled.`;
25682
- await notificationService.emit(EventType.UPLOAD, {
25683
- message: message2
25684
- });
25685
- await activityLogsService.addEntry(sessionId, message2);
25686
- strapi2.log.warn(message2);
25687
- continue;
25688
- }
25689
- const pickPathsWithUid = pickPaths.map((pickPath) => `${modelUid}.${pickPath}`);
25690
- let entries = await strapi2.documents(modelUid).findMany({
25691
- locUploadPLevel: 6,
25692
- status: "draft"
25693
- });
25694
- if (!entries.length) {
25695
- strapi2.log.info(`No entries found for model ${modelUid}`);
25696
- continue;
25697
- }
25698
- const excludedEntries = await EntryExclusionService2.getContentTypeExclusions(modelUid);
25699
- const filteredEntries = [];
25700
- for (const entry of entries) {
25701
- const isExcluded = excludedEntries.includes(entry.documentId);
25702
- if (!isExcluded) {
25703
- filteredEntries.push(entry);
25704
- }
25705
- }
25706
- entries = filteredEntries;
25707
- if (!entries.length) {
25708
- const message2 = `All entries for model ${collectionName} are excluded from translation`;
25709
- await notificationService.emit(EventType.UPLOAD, {
25710
- message: message2
25711
- });
25712
- await activityLogsService.addEntry(sessionId, message2);
25713
- strapi2.log.info(message2);
25714
- continue;
25715
- }
25716
- const message = `Excluding ${excludedEntries.length} entries for model ${collectionName} from upload. Entries to translate: ${entries.length}.`;
25717
- await notificationService.emit(EventType.UPLOAD, {
25718
- message
25719
- });
25720
- await activityLogsService.addEntry(sessionId, message);
25721
- strapi2.log.info(message);
25722
- if (strapiDefaultLocaleCode) {
25723
- for (const entry of entries) {
25724
- attemptedTuples.push({
25725
- uid: modelUid,
25726
- documentId: entry.documentId,
25727
- locale: strapiDefaultLocaleCode
25728
- });
25729
- }
25730
- }
25731
- entries = omitDeep(entries, ["locale", "createdAt", "updatedAt", "publishedAt"]);
25732
- entries.forEach((entry) => {
25733
- const flatten = flattenObject({
25734
- [modelUid]: entry
25735
- });
25736
- const pickedFlatten = pickEntries(flatten, pickPathsWithUid);
25737
- pickedFlattenStrapiContent = {
25738
- ...pickedFlattenStrapiContent,
25739
- ...pickedFlatten
25740
- };
25741
- });
25742
- const characterLimitsMetadata = getCharacterLimitsMetadata(pickedFlattenStrapiContent, modelUid);
25743
- pickedFlattenStrapiContent = {
25744
- ...pickedFlattenStrapiContent,
25745
- ...characterLimitsMetadata
25746
- };
25747
- }
25748
- const localazyLocaleCode = strapiDefaultLocaleCode ? isoStrapiToLocalazy(strapiDefaultLocaleCode) : config.default.LOCALAZY_DEFAULT_LOCALE;
25749
- const importFile = LocalazyUploadService2.createImportFileRepresentation(
25750
- localazyLocaleCode,
25751
- pickedFlattenStrapiContent
25752
- );
25753
- const uploadConfig = {
25754
- contentOptions: {
25755
- type: config.default.LOCALAZY_DEFAULT_FILE_EXTENSION
25756
- },
25757
- i18nOptions: { deprecate: "file" },
25758
- fileOptions: {
25759
- name: config.default.LOCALAZY_DEFAULT_FILE_NAME,
25760
- path: config.default.LOCALAZY_DEFAULT_FILE_PATH
25761
- }
25762
- };
25763
- await notificationService.emit(EventType.UPLOAD, {
25764
- message: "Uploading collections to Localazy..."
25765
- });
25766
- await activityLogsService.addEntry(sessionId, "Uploading collections to Localazy...");
25767
- try {
25768
- await LocalazyUploadService2.upload(importFile, uploadConfig);
25769
- await activityLogsService.recordAttemptedEntries(
25770
- sessionId,
25771
- attemptedTuples.map((t3) => ({ ...t3, status: "success" }))
25772
- );
25773
- } catch (error) {
25774
- success = false;
25775
- const errorMessage = `Upload to Localazy failed: ${error instanceof Error ? error.message : String(error)}`;
25776
- strapi2.log.error(errorMessage);
25777
- await notificationService.emit(EventType.UPLOAD_FINISHED, {
25778
- success,
25779
- message: errorMessage
25780
- });
25781
- await activityLogsService.addEntry(sessionId, errorMessage);
25782
- await activityLogsService.recordAttemptedEntries(
25783
- sessionId,
25784
- attemptedTuples.map((t3) => ({ ...t3, status: "failed", errorMessage }))
25785
- );
25786
- await activityLogsService.finishSession(sessionId, "failed", errorMessage);
25787
- console.timeEnd("upload");
25788
- return;
25789
- }
25790
- strapi2.log.info("Upload finished in");
25791
- await notificationService.emit(EventType.UPLOAD_FINISHED, {
25792
- success,
25793
- message: "Upload finished"
25794
- });
25795
- await activityLogsService.addEntry(sessionId, "Upload finished");
25796
- await activityLogsService.finishSession(
25797
- sessionId,
25798
- success ? "completed" : "failed",
25799
- success ? "Upload completed successfully" : "Upload finished with errors"
25800
- );
25801
- console.timeEnd("upload");
25802
- }
25803
- });
25804
25628
  var symbolTag$2 = "[object Symbol]";
25805
25629
  function isSymbol(value) {
25806
25630
  return typeof value == "symbol" || isObjectLike(value) && baseGetTag(value) == symbolTag$2;
@@ -26107,20 +25931,274 @@ function baseSet(object, path, value, customizer) {
26107
25931
  newValue = isObject(objValue) ? objValue : isIndex(path[index2 + 1]) ? [] : {};
26108
25932
  }
26109
25933
  }
26110
- assignValue(nested, key, newValue);
26111
- nested = nested[key];
25934
+ assignValue(nested, key, newValue);
25935
+ nested = nested[key];
25936
+ }
25937
+ return object;
25938
+ }
25939
+ function set(object, path, value) {
25940
+ return object == null ? object : baseSet(object, path, value);
25941
+ }
25942
+ const BLOCKS_ATTRIBUTE_TYPE = "blocks";
25943
+ const projectBlocksFields = (entry, model, getModel) => {
25944
+ const cloned = cloneDeep(entry);
25945
+ walkAndProject(cloned, model, getModel);
25946
+ return cloned;
25947
+ };
25948
+ const walkAndProject = (value, model, getModel) => {
25949
+ if (!value || !model?.attributes) {
25950
+ return;
25951
+ }
25952
+ for (const [attributeName, attribute] of Object.entries(model.attributes)) {
25953
+ const fieldValue = value[attributeName];
25954
+ if (fieldValue === void 0 || fieldValue === null) {
25955
+ continue;
25956
+ }
25957
+ if (attribute.type === BLOCKS_ATTRIBUTE_TYPE) {
25958
+ value[attributeName] = projectBlocksValue(fieldValue);
25959
+ } else if (attribute.type === "component") {
25960
+ const componentModel = getModel(attribute.component);
25961
+ if (attribute.repeatable && Array.isArray(fieldValue)) {
25962
+ fieldValue.forEach((item) => walkAndProject(item, componentModel, getModel));
25963
+ } else if (isPlainObject(fieldValue)) {
25964
+ walkAndProject(fieldValue, componentModel, getModel);
25965
+ }
25966
+ } else if (attribute.type === "dynamiczone" && Array.isArray(fieldValue)) {
25967
+ fieldValue.forEach((item) => {
25968
+ if (item?.__component) {
25969
+ walkAndProject(item, getModel(item.__component), getModel);
25970
+ }
25971
+ });
25972
+ }
25973
+ }
25974
+ };
25975
+ const projectBlocksValue = (nodes) => {
25976
+ if (!Array.isArray(nodes)) {
25977
+ return nodes;
25978
+ }
25979
+ return nodes.map(projectNode);
25980
+ };
25981
+ const projectNode = (node) => {
25982
+ if (!isPlainObject(node)) {
25983
+ return {};
25984
+ }
25985
+ const projected = {};
25986
+ if (typeof node.text === "string") {
25987
+ projected.text = node.text;
25988
+ }
25989
+ if (Array.isArray(node.children)) {
25990
+ projected.children = node.children.map(projectNode);
25991
+ }
25992
+ return projected;
25993
+ };
25994
+ const overlayBlocksTranslation = (sourceAst, translated) => {
25995
+ if (!Array.isArray(sourceAst)) {
25996
+ return void 0;
25997
+ }
25998
+ return sourceAst.map((node, index2) => overlayNode(node, get(translated, [String(index2)])));
25999
+ };
26000
+ const overlayNode = (node, translatedNode) => {
26001
+ if (!isPlainObject(node)) {
26002
+ return cloneDeep(node);
26003
+ }
26004
+ if (typeof node.text === "string") {
26005
+ const translatedText = isPlainObject(translatedNode) ? translatedNode.text : void 0;
26006
+ return typeof translatedText === "string" ? { ...node, text: translatedText } : cloneDeep(node);
26007
+ }
26008
+ if (Array.isArray(node.children)) {
26009
+ return {
26010
+ ...node,
26011
+ children: node.children.map(
26012
+ (child, index2) => overlayNode(child, translatedNode ? get(translatedNode, ["children", String(index2)]) : void 0)
26013
+ )
26014
+ };
26015
+ }
26016
+ return cloneDeep(node);
26017
+ };
26018
+ const LocalazyTransferUploadService = ({ strapi: strapi2 }) => ({
26019
+ async upload({ notificationService }) {
26020
+ console.time("upload");
26021
+ await notificationService.emit(EventType.UPLOAD, {
26022
+ message: "Upload started"
26023
+ });
26024
+ const activityLogsService = getActivityLogsService();
26025
+ const sessionId = await activityLogsService.startSession("upload", "Strapi User");
26026
+ await activityLogsService.addEntry(sessionId, "Upload started");
26027
+ let success = true;
26028
+ const StrapiService2 = getStrapiService();
26029
+ const StrapiI18nService2 = getStrapiI18nService();
26030
+ const LocalazyUploadService2 = getLocalazyUploadService();
26031
+ const EntryExclusionService2 = getEntryExclusionService();
26032
+ const contentTransferSetup = await getPluginSettingsService().getContentTransferSetup();
26033
+ if (!contentTransferSetup.has_setup) {
26034
+ const message = "Content transfer setup is not set up.";
26035
+ success = false;
26036
+ await notificationService.emit(EventType.UPLOAD_FINISHED, {
26037
+ success,
26038
+ message
26039
+ });
26040
+ await activityLogsService.addEntry(sessionId, message);
26041
+ await activityLogsService.finishSession(sessionId, "failed", message);
26042
+ strapi2.log.info(message);
26043
+ return;
26044
+ }
26045
+ const { setup: setup2 } = contentTransferSetup;
26046
+ const collectionsNames = getCollectionsNames(setup2);
26047
+ const models = await StrapiService2.getModels();
26048
+ const strapiDefaultLocaleCode = await StrapiI18nService2.getDefaultLocaleCode();
26049
+ const attemptedTuples = [];
26050
+ let pickedFlattenStrapiContent = {};
26051
+ for (const collectionName of collectionsNames) {
26052
+ const currentModel = models.find((model) => model.collectionName === collectionName);
26053
+ const modelUid = currentModel.uid;
26054
+ if (!currentModel) {
26055
+ strapi2.log.warn(`Model with uid ${modelUid} is not found.`);
26056
+ continue;
26057
+ }
26058
+ const transferSetupModel = findSetupModelByCollectionName(setup2, collectionName);
26059
+ if (!isCollectionTransferEnabled(setup2, collectionName)) {
26060
+ const message2 = `Collection ${collectionName} transfer is disabled.`;
26061
+ await notificationService.emit(EventType.UPLOAD, {
26062
+ message: message2
26063
+ });
26064
+ await activityLogsService.addEntry(sessionId, message2);
26065
+ strapi2.log.info(message2);
26066
+ continue;
26067
+ }
26068
+ const currentTransferSetupModel = transferSetupModel[collectionName];
26069
+ const pickPaths = getPickPathsWithComponents(currentTransferSetupModel);
26070
+ if (!pickPaths.length) {
26071
+ const message2 = `No fields for collection ${collectionName} transfer are enabled.`;
26072
+ await notificationService.emit(EventType.UPLOAD, {
26073
+ message: message2
26074
+ });
26075
+ await activityLogsService.addEntry(sessionId, message2);
26076
+ strapi2.log.warn(message2);
26077
+ continue;
26078
+ }
26079
+ const pickPathsWithUid = pickPaths.map((pickPath) => `${modelUid}.${pickPath}`);
26080
+ let entries = await strapi2.documents(modelUid).findMany({
26081
+ locUploadPLevel: 6,
26082
+ status: "draft"
26083
+ });
26084
+ if (!entries.length) {
26085
+ strapi2.log.info(`No entries found for model ${modelUid}`);
26086
+ continue;
26087
+ }
26088
+ const excludedEntries = await EntryExclusionService2.getContentTypeExclusions(modelUid);
26089
+ const filteredEntries = [];
26090
+ for (const entry of entries) {
26091
+ const isExcluded = excludedEntries.includes(entry.documentId);
26092
+ if (!isExcluded) {
26093
+ filteredEntries.push(entry);
26094
+ }
26095
+ }
26096
+ entries = filteredEntries;
26097
+ if (!entries.length) {
26098
+ const message2 = `All entries for model ${collectionName} are excluded from translation`;
26099
+ await notificationService.emit(EventType.UPLOAD, {
26100
+ message: message2
26101
+ });
26102
+ await activityLogsService.addEntry(sessionId, message2);
26103
+ strapi2.log.info(message2);
26104
+ continue;
26105
+ }
26106
+ const message = `Excluding ${excludedEntries.length} entries for model ${collectionName} from upload. Entries to translate: ${entries.length}.`;
26107
+ await notificationService.emit(EventType.UPLOAD, {
26108
+ message
26109
+ });
26110
+ await activityLogsService.addEntry(sessionId, message);
26111
+ strapi2.log.info(message);
26112
+ if (strapiDefaultLocaleCode) {
26113
+ for (const entry of entries) {
26114
+ attemptedTuples.push({
26115
+ uid: modelUid,
26116
+ documentId: entry.documentId,
26117
+ locale: strapiDefaultLocaleCode
26118
+ });
26119
+ }
26120
+ }
26121
+ entries = omitDeep(entries, ["locale", "createdAt", "updatedAt", "publishedAt"]);
26122
+ entries.forEach((entry) => {
26123
+ const projectedEntry = projectBlocksFields(
26124
+ entry,
26125
+ strapi2.getModel(modelUid),
26126
+ (uid) => strapi2.getModel(uid)
26127
+ );
26128
+ const flatten = flattenObject({
26129
+ [modelUid]: projectedEntry
26130
+ });
26131
+ const pickedFlatten = pickEntries(flatten, pickPathsWithUid);
26132
+ pickedFlattenStrapiContent = {
26133
+ ...pickedFlattenStrapiContent,
26134
+ ...pickedFlatten
26135
+ };
26136
+ });
26137
+ const characterLimitsMetadata = getCharacterLimitsMetadata(pickedFlattenStrapiContent, modelUid);
26138
+ pickedFlattenStrapiContent = {
26139
+ ...pickedFlattenStrapiContent,
26140
+ ...characterLimitsMetadata
26141
+ };
26142
+ }
26143
+ const localazyLocaleCode = strapiDefaultLocaleCode ? isoStrapiToLocalazy(strapiDefaultLocaleCode) : config.default.LOCALAZY_DEFAULT_LOCALE;
26144
+ const importFile = LocalazyUploadService2.createImportFileRepresentation(
26145
+ localazyLocaleCode,
26146
+ pickedFlattenStrapiContent
26147
+ );
26148
+ const uploadConfig = {
26149
+ contentOptions: {
26150
+ type: config.default.LOCALAZY_DEFAULT_FILE_EXTENSION
26151
+ },
26152
+ i18nOptions: { deprecate: "file" },
26153
+ fileOptions: {
26154
+ name: config.default.LOCALAZY_DEFAULT_FILE_NAME,
26155
+ path: config.default.LOCALAZY_DEFAULT_FILE_PATH
26156
+ }
26157
+ };
26158
+ await notificationService.emit(EventType.UPLOAD, {
26159
+ message: "Uploading collections to Localazy..."
26160
+ });
26161
+ await activityLogsService.addEntry(sessionId, "Uploading collections to Localazy...");
26162
+ try {
26163
+ await LocalazyUploadService2.upload(importFile, uploadConfig);
26164
+ await activityLogsService.recordAttemptedEntries(
26165
+ sessionId,
26166
+ attemptedTuples.map((t3) => ({ ...t3, status: "success" }))
26167
+ );
26168
+ } catch (error) {
26169
+ success = false;
26170
+ const errorMessage = `Upload to Localazy failed: ${error instanceof Error ? error.message : String(error)}`;
26171
+ strapi2.log.error(errorMessage);
26172
+ await notificationService.emit(EventType.UPLOAD_FINISHED, {
26173
+ success,
26174
+ message: errorMessage
26175
+ });
26176
+ await activityLogsService.addEntry(sessionId, errorMessage);
26177
+ await activityLogsService.recordAttemptedEntries(
26178
+ sessionId,
26179
+ attemptedTuples.map((t3) => ({ ...t3, status: "failed", errorMessage }))
26180
+ );
26181
+ await activityLogsService.finishSession(sessionId, "failed", errorMessage);
26182
+ console.timeEnd("upload");
26183
+ return;
26184
+ }
26185
+ strapi2.log.info("Upload finished in");
26186
+ await notificationService.emit(EventType.UPLOAD_FINISHED, {
26187
+ success,
26188
+ message: "Upload finished"
26189
+ });
26190
+ await activityLogsService.addEntry(sessionId, "Upload finished");
26191
+ await activityLogsService.finishSession(
26192
+ sessionId,
26193
+ success ? "completed" : "failed",
26194
+ success ? "Upload completed successfully" : "Upload finished with errors"
26195
+ );
26196
+ console.timeEnd("upload");
26112
26197
  }
26113
- return object;
26114
- }
26115
- function set(object, path, value) {
26116
- return object == null ? object : baseSet(object, path, value);
26117
- }
26198
+ });
26118
26199
  const hasDynamicZoneKeySegment = (parsedKey) => {
26119
26200
  return parsedKey.some((segment) => segment.includes(";"));
26120
26201
  };
26121
- const getDynamicZoneKeySegment = (parsedKey) => {
26122
- return parsedKey.find((segment) => segment.includes(";"));
26123
- };
26124
26202
  const getComponentNameFromDynamicZoneKeySegment = (dynamicZoneKeySegment) => {
26125
26203
  return dynamicZoneKeySegment.split(";")[1];
26126
26204
  };
@@ -26140,52 +26218,116 @@ var ShouldSetDownloadedPropertyReturnType = /* @__PURE__ */ ((ShouldSetDownloade
26140
26218
  ShouldSetDownloadedPropertyReturnType2["JSON"] = "json";
26141
26219
  return ShouldSetDownloadedPropertyReturnType2;
26142
26220
  })(ShouldSetDownloadedPropertyReturnType || {});
26143
- const shouldSetDownloadedProperty = (modelContentTransferSetup, parsedKeyRest) => {
26221
+ const locateDownloadedField = (modelContentTransferSetup, parsedKeyRest) => {
26222
+ const notFound = { type: "no", fieldSegmentIndex: -1 };
26144
26223
  if (!modelContentTransferSetup.__model__) {
26145
- return "no";
26224
+ return notFound;
26146
26225
  }
26226
+ let setupModel = modelContentTransferSetup;
26227
+ let startIndex2 = 0;
26147
26228
  if (hasDynamicZoneKeySegment(parsedKeyRest)) {
26148
- const dynamicZonePropertyName = getDynamicZonePropertyName(parsedKeyRest);
26149
- const componentName = getComponentNameFromDynamicZoneKeySegment(getDynamicZoneKeySegment(parsedKeyRest));
26229
+ const dynamicZoneKeySegmentIndex = getDynamicZoneKeySegmentIndex(parsedKeyRest);
26230
+ const componentName = getComponentNameFromDynamicZoneKeySegment(parsedKeyRest[dynamicZoneKeySegmentIndex]);
26150
26231
  const dzContentTransferSetupModel = get(
26151
26232
  modelContentTransferSetup,
26152
- dynamicZonePropertyName
26233
+ getDynamicZonePropertyName(parsedKeyRest)
26153
26234
  );
26154
26235
  if (!Array.isArray(dzContentTransferSetupModel)) {
26155
- return "no";
26236
+ return notFound;
26156
26237
  }
26157
- const dzContentTransferSetupComponentModel = dzContentTransferSetupModel.find(
26158
- (c2) => c2.__component__ === componentName
26159
- );
26160
- if (!dzContentTransferSetupComponentModel) {
26161
- return "no";
26238
+ setupModel = dzContentTransferSetupModel.find((c2) => c2.__component__ === componentName);
26239
+ if (!setupModel) {
26240
+ return notFound;
26162
26241
  }
26163
- const dynamicZoneKeySegmentIndex = getDynamicZoneKeySegmentIndex(parsedKeyRest);
26164
- const slicedParsedKeyRest = parsedKeyRest.slice(dynamicZoneKeySegmentIndex + 1);
26165
- const filteredSlicedParsedKeyRest = slicedParsedKeyRest.filter((segment) => isNaN(parseInt(segment)));
26166
- if (get(dzContentTransferSetupComponentModel, filteredSlicedParsedKeyRest) === true) {
26167
- return "yes";
26168
- }
26169
- while (filteredSlicedParsedKeyRest.length > 0) {
26170
- filteredSlicedParsedKeyRest.pop();
26171
- if (get(dzContentTransferSetupComponentModel, filteredSlicedParsedKeyRest) === true) {
26172
- return "json";
26242
+ startIndex2 = dynamicZoneKeySegmentIndex + 1;
26243
+ }
26244
+ const namedSegmentIndexes = [];
26245
+ for (let index2 = startIndex2; index2 < parsedKeyRest.length; index2++) {
26246
+ if (isNaN(parseInt(parsedKeyRest[index2]))) {
26247
+ namedSegmentIndexes.push(index2);
26248
+ }
26249
+ }
26250
+ for (let length2 = namedSegmentIndexes.length; length2 > 0; length2--) {
26251
+ const fieldPath = namedSegmentIndexes.slice(0, length2).map((index2) => parsedKeyRest[index2]);
26252
+ if (get(setupModel, fieldPath) === true) {
26253
+ const fieldSegmentIndex = namedSegmentIndexes[length2 - 1];
26254
+ const type2 = fieldSegmentIndex === parsedKeyRest.length - 1 ? "yes" : "json";
26255
+ return { type: type2, fieldSegmentIndex };
26256
+ }
26257
+ }
26258
+ return notFound;
26259
+ };
26260
+ const createJsonFieldsDownloadAccumulator = () => {
26261
+ const fields = /* @__PURE__ */ new Map();
26262
+ return {
26263
+ /**
26264
+ * @param fieldKey path to the field in the parsed content: `[iso, uid, documentId, ...ownerPath, fieldName]`
26265
+ * @param valuePath path of this leaf inside the field's value
26266
+ */
26267
+ add(fieldKey, valuePath, value) {
26268
+ const id = JSON.stringify(fieldKey);
26269
+ let field = fields.get(id);
26270
+ if (!field) {
26271
+ field = { fieldKey, value: {} };
26272
+ fields.set(id, field);
26273
+ }
26274
+ set(field.value, valuePath, value);
26275
+ },
26276
+ /** Write every collected field value into `parsedContent` at its own path. */
26277
+ applyTo(parsedContent) {
26278
+ for (const { fieldKey, value } of fields.values()) {
26279
+ set(parsedContent, fieldKey, value);
26173
26280
  }
26174
26281
  }
26175
- return "no";
26176
- } else {
26177
- const filteredParsedKeyRest = parsedKeyRest.filter((partialKey) => isNaN(parseInt(partialKey)));
26178
- if (get(modelContentTransferSetup, filteredParsedKeyRest) === true) {
26179
- return "yes";
26180
- }
26181
- while (filteredParsedKeyRest.length > 0) {
26182
- filteredParsedKeyRest.pop();
26183
- if (get(modelContentTransferSetup, filteredParsedKeyRest) === true) {
26184
- return "json";
26282
+ };
26283
+ };
26284
+ const collectDownloadedContent = ({
26285
+ languages: languages2,
26286
+ processedKeys,
26287
+ contentTransferSetup,
26288
+ models,
26289
+ parseLocalazyKey: parseLocalazyKey2
26290
+ }) => {
26291
+ const parsedLocalazyContent = {};
26292
+ const entryKeySourceMap = {};
26293
+ const jsonFieldsAccumulator = createJsonFieldsDownloadAccumulator();
26294
+ for (const { isoStrapi, keys: keys2 } of languages2) {
26295
+ const parsedKeys = keys2.map((localazyEntry) => {
26296
+ const storedEvent = processedKeys[isoStrapi]?.[localazyEntry.id];
26297
+ const isChanged = !(storedEvent !== void 0 && localazyEntry.event !== void 0 && localazyEntry.event <= storedEvent);
26298
+ const parsedKey = parseLocalazyKey2(localazyEntry.key[0]);
26299
+ return { localazyEntry, parsedKey, isChanged, entryKey: `${isoStrapi}:${parsedKey.uid}:${parsedKey.id}` };
26300
+ });
26301
+ for (const { localazyEntry, entryKey, isChanged } of parsedKeys) {
26302
+ if (isChanged) {
26303
+ if (!entryKeySourceMap[entryKey]) {
26304
+ entryKeySourceMap[entryKey] = [];
26305
+ }
26306
+ entryKeySourceMap[entryKey].push({ lang: isoStrapi, id: localazyEntry.id, event: localazyEntry.event });
26307
+ }
26308
+ }
26309
+ for (const { localazyEntry, parsedKey, entryKey } of parsedKeys) {
26310
+ if (!entryKeySourceMap[entryKey]) {
26311
+ continue;
26312
+ }
26313
+ const modelContentTransferSetup = findSetupModelByCollectionUid(contentTransferSetup, models, parsedKey.uid);
26314
+ if (typeof modelContentTransferSetup === "undefined") {
26315
+ continue;
26316
+ }
26317
+ const { type: type2, fieldSegmentIndex } = locateDownloadedField(modelContentTransferSetup, parsedKey.rest);
26318
+ if (type2 === ShouldSetDownloadedPropertyReturnType.JSON) {
26319
+ jsonFieldsAccumulator.add(
26320
+ [isoStrapi, parsedKey.uid, parsedKey.id, ...parsedKey.rest.slice(0, fieldSegmentIndex + 1)],
26321
+ parsedKey.rest.slice(fieldSegmentIndex + 1),
26322
+ localazyEntry.value
26323
+ );
26324
+ } else if (type2 === ShouldSetDownloadedPropertyReturnType.YES) {
26325
+ set(parsedLocalazyContent, [isoStrapi, parsedKey.uid, parsedKey.id, ...parsedKey.rest], localazyEntry.value);
26185
26326
  }
26186
26327
  }
26187
- return "no";
26188
26328
  }
26329
+ jsonFieldsAccumulator.applyTo(parsedLocalazyContent);
26330
+ return { parsedLocalazyContent, entryKeySourceMap };
26189
26331
  };
26190
26332
  const getFilteredLanguagesCodesForDownload = async (languagesCodes, requestedUiLanguages) => {
26191
26333
  const pluginSettingsServiceHelper = new PluginSettingsServiceHelper();
@@ -26372,10 +26514,8 @@ const LocalazyTransferDownloadService = ({ strapi: strapi2 }) => ({
26372
26514
  }
26373
26515
  await persistCursor();
26374
26516
  };
26375
- const parsedLocalazyContent = {};
26376
26517
  const strapiContentTypesModels = await StrapiService2.getModels();
26377
- const jsonFields = [];
26378
- const entryKeySourceMap = {};
26518
+ const languagesToParse = [];
26379
26519
  for (const [isoLocalazy, keys2] of Object.entries(localazyContent)) {
26380
26520
  const isoStrapi = isoLocalazyToStrapi(isoLocalazy);
26381
26521
  if (!isoStrapi) {
@@ -26384,78 +26524,15 @@ const LocalazyTransferDownloadService = ({ strapi: strapi2 }) => ({
26384
26524
  });
26385
26525
  continue;
26386
26526
  }
26387
- for (const localazyEntry of keys2) {
26388
- const key = localazyEntry.key[0];
26389
- const value = localazyEntry.value;
26390
- const localazyKeyId = localazyEntry.id;
26391
- const localazyKeyEvent = localazyEntry.event;
26392
- const storedEvent = processedKeys[isoStrapi]?.[localazyKeyId];
26393
- if (storedEvent !== void 0 && localazyKeyEvent !== void 0 && localazyKeyEvent <= storedEvent) {
26394
- continue;
26395
- }
26396
- const parsedKey = StrapiI18nService2.parseLocalazyKey(key);
26397
- const entryKey = `${isoStrapi}:${parsedKey.uid}:${parsedKey.id}`;
26398
- if (!entryKeySourceMap[entryKey]) {
26399
- entryKeySourceMap[entryKey] = [];
26400
- }
26401
- entryKeySourceMap[entryKey].push({ lang: isoStrapi, id: localazyKeyId, event: localazyKeyEvent });
26402
- const modelContentTransferSetup = findSetupModelByCollectionUid(
26403
- contentTransferSetup,
26404
- strapiContentTypesModels,
26405
- parsedKey.uid
26406
- );
26407
- if (typeof modelContentTransferSetup !== "undefined") {
26408
- const shouldSetDownloadedPropertyResult = shouldSetDownloadedProperty(
26409
- modelContentTransferSetup,
26410
- parsedKey.rest
26411
- );
26412
- if (shouldSetDownloadedPropertyResult === ShouldSetDownloadedPropertyReturnType.NO) {
26413
- continue;
26414
- }
26415
- let parsedKeyRestWithoutComponents = parsedKey.rest;
26416
- if (shouldSetDownloadedPropertyResult === ShouldSetDownloadedPropertyReturnType.JSON) {
26417
- const setKey = [isoStrapi, parsedKey.uid, parsedKey.id];
26418
- let updatedParsedKeyRestWithoutComponents = parsedKeyRestWithoutComponents;
26419
- let segmentsToAdd = [];
26420
- for (const segment of parsedKeyRestWithoutComponents) {
26421
- const hasEntry = get(modelContentTransferSetup, [...segmentsToAdd, segment]);
26422
- const hasEntryNotFinal = hasEntry && typeof hasEntry !== "boolean";
26423
- const isComponent2 = parseInt(segment) > 0;
26424
- if (hasEntryNotFinal || !hasEntry && isComponent2) {
26425
- segmentsToAdd.push(segment);
26426
- setKey.push(segment);
26427
- updatedParsedKeyRestWithoutComponents = updatedParsedKeyRestWithoutComponents.slice(1);
26428
- } else {
26429
- break;
26430
- }
26431
- }
26432
- parsedKeyRestWithoutComponents = updatedParsedKeyRestWithoutComponents;
26433
- let foundJsonFieldIndex = jsonFields.findIndex((jsonField) => {
26434
- return jsonField.setKey.join() === setKey.join();
26435
- });
26436
- if (foundJsonFieldIndex === -1) {
26437
- jsonFields.push({
26438
- setKey,
26439
- jsonKey: parsedKeyRestWithoutComponents[0],
26440
- jsonValue: {}
26441
- });
26442
- }
26443
- foundJsonFieldIndex = foundJsonFieldIndex === -1 ? jsonFields.length - 1 : foundJsonFieldIndex;
26444
- const foundJsonField = jsonFields[foundJsonFieldIndex];
26445
- const restSliced = parsedKeyRestWithoutComponents.slice(1);
26446
- set(foundJsonField, ["jsonValue", ...restSliced], value);
26447
- jsonFields[foundJsonFieldIndex] = foundJsonField;
26448
- }
26449
- if (shouldSetDownloadedPropertyResult === ShouldSetDownloadedPropertyReturnType.YES) {
26450
- const setKey = [isoStrapi, parsedKey.uid, parsedKey.id, ...parsedKeyRestWithoutComponents];
26451
- set(parsedLocalazyContent, setKey, value);
26452
- }
26453
- }
26454
- }
26455
- }
26456
- for (const jsonField of jsonFields) {
26457
- set(parsedLocalazyContent, [...jsonField.setKey, jsonField.jsonKey], jsonField.jsonValue);
26458
- }
26527
+ languagesToParse.push({ isoStrapi, keys: keys2 });
26528
+ }
26529
+ const { parsedLocalazyContent, entryKeySourceMap } = collectDownloadedContent({
26530
+ languages: languagesToParse,
26531
+ processedKeys,
26532
+ contentTransferSetup,
26533
+ models: strapiContentTypesModels,
26534
+ parseLocalazyKey: (key) => StrapiI18nService2.parseLocalazyKey(key)
26535
+ });
26459
26536
  for (const [isoStrapi, contentTypes2] of Object.entries(parsedLocalazyContent)) {
26460
26537
  for (const [uid, models] of Object.entries(contentTypes2)) {
26461
26538
  const strapiContentTypeModel = strapiContentTypesModels.find((model) => model.uid === uid);
@@ -26639,6 +26716,15 @@ const intlDisplayName = (isoStrapi) => {
26639
26716
  }
26640
26717
  return languageNames.of(isoStrapi.toLowerCase());
26641
26718
  };
26719
+ const parseLocalazyKey = (key) => {
26720
+ const split = key.split(/\.(?![^[]*])|\[|\]/);
26721
+ const filteredSplit = split.filter((item) => item !== "");
26722
+ return {
26723
+ uid: `${filteredSplit[0]}.${filteredSplit[1]}`,
26724
+ id: filteredSplit[2],
26725
+ rest: filteredSplit.slice(3)
26726
+ };
26727
+ };
26642
26728
  const StrapiI18nService = ({ strapi: strapi2 }) => ({
26643
26729
  async getLocales() {
26644
26730
  return strapi2.plugin("i18n").service("locales").find();
@@ -26666,13 +26752,7 @@ const StrapiI18nService = ({ strapi: strapi2 }) => ({
26666
26752
  }
26667
26753
  },
26668
26754
  parseLocalazyKey(key) {
26669
- const split = key.split(/\.(?![^[]*])|\[|\]/);
26670
- const filteredSplit = split.filter((item) => item !== "");
26671
- return {
26672
- uid: `${filteredSplit[0]}.${filteredSplit[1]}`,
26673
- id: filteredSplit[2],
26674
- rest: filteredSplit.slice(3)
26675
- };
26755
+ return parseLocalazyKey(key);
26676
26756
  },
26677
26757
  async getEntryInLocale(modelUid, documentId, isoStrapi) {
26678
26758
  const entry = await strapi2.documents(modelUid).findOne({
@@ -26771,18 +26851,6 @@ const LocalazyUploadService = ({ strapi: strapi2 }) => ({
26771
26851
  return file;
26772
26852
  }
26773
26853
  });
26774
- const resetArrayKeysDeep = (object, keysToFilter) => {
26775
- const sortedKeysToFilter = keysToFilter.sort((a2, b2) => {
26776
- const aLvl = a2.match(/\./g)?.length || 0;
26777
- const bLvl = b2.match(/\./g)?.length || 0;
26778
- return bLvl - aLvl;
26779
- });
26780
- for (const key of sortedKeysToFilter) {
26781
- const part = get(object, key);
26782
- const filteredPart = part.filter((item) => item !== void 0);
26783
- set(object, key, filteredPart);
26784
- }
26785
- };
26786
26854
  const getAttribute = (model, attribute) => {
26787
26855
  if (isEmpty(model)) {
26788
26856
  return void 0;
@@ -26802,22 +26870,66 @@ const isRepeatable = (attributeObj) => {
26802
26870
  const isRelation = (attributeObj) => {
26803
26871
  return attributeObj.type === "relation" && attributeObj.target !== "plugin::upload.file";
26804
26872
  };
26873
+ const isBlocks = (attributeObj) => {
26874
+ return attributeObj.type === BLOCKS_ATTRIBUTE_TYPE;
26875
+ };
26876
+ const isJson = (attributeObj) => {
26877
+ return attributeObj.type === "json";
26878
+ };
26805
26879
  const findModel = (models, uid) => {
26806
26880
  const model = models.find((model2) => model2.uid === uid);
26807
26881
  return model;
26808
26882
  };
26883
+ const arrayItemSegment = (item, index2) => {
26884
+ if (isPlainObject(item) && item.id && item.__component) {
26885
+ return `${item.id};${item.__component}`;
26886
+ }
26887
+ return String(item?.documentId || item?.id || index2);
26888
+ };
26889
+ const objectIdSegment = (value) => {
26890
+ if (isPlainObject(value) && (value.documentId || value.id)) {
26891
+ return String(value.documentId || value.id);
26892
+ }
26893
+ return void 0;
26894
+ };
26895
+ const overlayValue = (source, translated) => {
26896
+ if (typeof source === "string") {
26897
+ return typeof translated === "string" ? translated : source;
26898
+ }
26899
+ if (Array.isArray(source)) {
26900
+ return source.map((item, index2) => overlayValue(item, get(translated, [arrayItemSegment(item, index2)])));
26901
+ }
26902
+ if (isPlainObject(source)) {
26903
+ const result = {};
26904
+ for (const [key, value] of Object.entries(source)) {
26905
+ result[key] = key === "id" || key === "documentId" ? value : overlayChild(value, get(translated, [key]));
26906
+ }
26907
+ return result;
26908
+ }
26909
+ return source;
26910
+ };
26911
+ const overlayChild = (source, translated) => {
26912
+ const idSegment = Array.isArray(source) ? void 0 : objectIdSegment(source);
26913
+ return overlayValue(source, idSegment ? get(translated, [idSegment]) : translated);
26914
+ };
26915
+ const overlayJsonTranslation = (sourceValue, translated) => {
26916
+ if (sourceValue === void 0 || sourceValue === null) {
26917
+ return void 0;
26918
+ }
26919
+ if (typeof sourceValue !== "object") {
26920
+ return typeof sourceValue === "string" && typeof translated === "string" ? translated : sourceValue;
26921
+ }
26922
+ return overlayChild(cloneDeep(sourceValue), translated);
26923
+ };
26809
26924
  const parsedLocalazyEntryToCreateEntry = (models, parsedLocalazyEntry, baseEntry, uid, locale = "") => {
26810
26925
  const createEntry = {};
26811
- const repeatableComponentsKeystoFilter = [];
26812
26926
  const dynamicZoneComponentKeys = [];
26927
+ const rebuiltFieldPaths = [];
26813
26928
  const toCreateEntry = (entry, model2, key = "", prefix = "", component = "", isRepeatableComponent = false, isDZ = false, isInsideDZ = false) => {
26814
26929
  if (Array.isArray(entry)) {
26815
26930
  Object.entries(entry).forEach(([baseEntryItemId, value]) => {
26816
26931
  if (value !== null) {
26817
26932
  if (component && isRepeatableComponent) {
26818
- if (!repeatableComponentsKeystoFilter.includes(prefix)) {
26819
- repeatableComponentsKeystoFilter.push(prefix);
26820
- }
26821
26933
  const baseEntryRepeatableItemId = parseInt(baseEntryItemId);
26822
26934
  const baseEntryRepeateableGroup = get(baseEntry, prefix);
26823
26935
  if (baseEntryRepeateableGroup !== void 0) {
@@ -26839,9 +26951,6 @@ const parsedLocalazyEntryToCreateEntry = (models, parsedLocalazyEntry, baseEntry
26839
26951
  toCreateEntry(value, model2, `${prefix}`, `${prefix}`);
26840
26952
  }
26841
26953
  if (!component && isRepeatableComponent) {
26842
- if (!repeatableComponentsKeystoFilter.includes(prefix)) {
26843
- repeatableComponentsKeystoFilter.push(prefix);
26844
- }
26845
26954
  const baseEntryRepeatableItemId = parseInt(baseEntryItemId);
26846
26955
  const baseEntryRepeateableGroup = get(baseEntry, prefix);
26847
26956
  if (baseEntryRepeateableGroup !== void 0) {
@@ -26945,7 +27054,20 @@ const parsedLocalazyEntryToCreateEntry = (models, parsedLocalazyEntry, baseEntry
26945
27054
  newPrefixBase = `${dzParamKey}.${baseEntryDZIndex}`;
26946
27055
  newPrefix = `${newPrefixBase}.${objectKey}`;
26947
27056
  }
26948
- set(createEntry, newPrefix, value);
27057
+ const isRebuiltField = isBlocks(attribute) || isJson(attribute);
27058
+ let valueToSet = value;
27059
+ if (isBlocks(attribute)) {
27060
+ valueToSet = overlayBlocksTranslation(get(baseEntry, newPrefix), value);
27061
+ } else if (isJson(attribute)) {
27062
+ valueToSet = overlayJsonTranslation(get(baseEntry, newPrefix), value);
27063
+ }
27064
+ if (valueToSet === void 0) {
27065
+ return;
27066
+ }
27067
+ set(createEntry, newPrefix, valueToSet);
27068
+ if (isRebuiltField) {
27069
+ rebuiltFieldPaths.push(newPrefix);
27070
+ }
26949
27071
  if (component) {
26950
27072
  const componentKeyToSet = `${newPrefixBase}.__component`;
26951
27073
  set(createEntry, componentKeyToSet, component);
@@ -26967,8 +27089,59 @@ const parsedLocalazyEntryToCreateEntry = (models, parsedLocalazyEntry, baseEntry
26967
27089
  if (locale) {
26968
27090
  createEntry.locale = locale;
26969
27091
  }
26970
- resetArrayKeysDeep(createEntry, repeatableComponentsKeystoFilter);
26971
- return { createEntry, dynamicZoneComponentKeys };
27092
+ return { createEntry, dynamicZoneComponentKeys, rebuiltFieldPaths };
27093
+ };
27094
+ const isMediaObject = (obj) => {
27095
+ if (typeof obj !== "object" || obj === null) return false;
27096
+ 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";
27097
+ };
27098
+ const dropPropertyDeepWithSkip = (obj, propertyName, isRoot = true, skipPredicates = []) => {
27099
+ if (Array.isArray(obj)) {
27100
+ return obj.filter((item) => {
27101
+ if (skipPredicates.length > 0) {
27102
+ return true;
27103
+ }
27104
+ return isRoot || !(typeof item === "object" && item !== null && propertyName in item);
27105
+ }).map(
27106
+ (item) => typeof item === "object" && item !== null ? dropPropertyDeepWithSkip(item, propertyName, false, skipPredicates) : item
27107
+ );
27108
+ }
27109
+ if (typeof obj === "object" && obj !== null) {
27110
+ const shouldSkip = skipPredicates.some((predicate) => predicate(obj));
27111
+ if (shouldSkip) {
27112
+ const result2 = {};
27113
+ for (const key in obj) {
27114
+ if (key === propertyName) {
27115
+ result2[key] = obj[key];
27116
+ } else {
27117
+ result2[key] = typeof obj[key] === "object" && obj[key] !== null ? dropPropertyDeepWithSkip(obj[key], propertyName, false, skipPredicates) : obj[key];
27118
+ }
27119
+ }
27120
+ return result2;
27121
+ }
27122
+ const result = {};
27123
+ for (const key in obj) {
27124
+ if (key === propertyName && !isRoot) {
27125
+ continue;
27126
+ }
27127
+ result[key] = typeof obj[key] === "object" && obj[key] !== null ? dropPropertyDeepWithSkip(obj[key], propertyName, false, skipPredicates) : obj[key];
27128
+ }
27129
+ return result;
27130
+ }
27131
+ return obj;
27132
+ };
27133
+ const dropDocumentIdExceptMedia = (obj) => {
27134
+ return dropPropertyDeepWithSkip(obj, "documentId", true, [isMediaObject]);
27135
+ };
27136
+ const OMIT_KEYS = ["locale", "localizations", "createdAt", "createdBy", "updatedAt", "updatedBy", "publishedAt"];
27137
+ const buildLocalizedCreateEntry = (models, translatedModel, baseEntry, uid, isoStrapi) => {
27138
+ const { createEntry } = parsedLocalazyEntryToCreateEntry(models, translatedModel, baseEntry, uid, isoStrapi);
27139
+ const filteredBaseEntry = dropDocumentIdExceptMedia(omitDeep(baseEntry, OMIT_KEYS));
27140
+ let mergedCreateEntry = {};
27141
+ merge(mergedCreateEntry, filteredBaseEntry, createEntry);
27142
+ mergedCreateEntry = omitDeep(mergedCreateEntry, OMIT_KEYS);
27143
+ mergedCreateEntry.locale = isoStrapi;
27144
+ return mergedCreateEntry;
26972
27145
  };
26973
27146
  const doesExistInPopulatedLocalizedEntry = (val) => {
26974
27147
  if (Array.isArray(val)) {
@@ -27007,17 +27180,17 @@ const populateCreateUpdateEntryWithBaseEntry = async (models, createUpdateEntry,
27007
27180
  }
27008
27181
  }
27009
27182
  } else if (!component && isRepeatableComponent && isDZ) {
27010
- Object.entries(partialBaseEntry).forEach(async ([partialBaseEntryItemIndex, partialBaseEntryItem]) => {
27183
+ for (const [partialBaseEntryItemIndex, partialBaseEntryItem] of Object.entries(partialBaseEntry)) {
27011
27184
  const component2 = partialBaseEntryItem.__component;
27012
27185
  const model3 = findModel(models, component2);
27013
27186
  const newPrefix = `${prefix}.${partialBaseEntryItemIndex}`;
27014
27187
  await populateEntry(partialBaseEntryItem, model3, partialBaseEntryItemIndex, newPrefix);
27015
- });
27188
+ }
27016
27189
  } else if (component && isRepeatableComponent) {
27017
- Object.entries(partialBaseEntry).forEach(async ([partialBaseEntryItemIndex, partialBaseEntryItem]) => {
27190
+ for (const [partialBaseEntryItemIndex, partialBaseEntryItem] of Object.entries(partialBaseEntry)) {
27018
27191
  const newPrefix = `${prefix}.${partialBaseEntryItemIndex}`;
27019
27192
  await populateEntry(partialBaseEntryItem, model2, partialBaseEntryItemIndex, newPrefix);
27020
- });
27193
+ }
27021
27194
  }
27022
27195
  } else if (typeof partialBaseEntry === "object") {
27023
27196
  if (partialBaseEntry === null) {
@@ -27130,7 +27303,7 @@ const populateCreateUpdateEntryWithBaseEntry = async (models, createUpdateEntry,
27130
27303
  } else {
27131
27304
  set(populatedEntry, newPrefix, value);
27132
27305
  }
27133
- } else {
27306
+ } else if (!isBlocks(attribute) && !isJson(attribute)) {
27134
27307
  await populateEntry(value, model2, objectKey2, newPrefix);
27135
27308
  }
27136
27309
  }
@@ -27152,15 +27325,80 @@ const populateCreateUpdateEntryWithBaseEntry = async (models, createUpdateEntry,
27152
27325
  await populateEntry(baseEntry, model);
27153
27326
  return populatedEntry;
27154
27327
  };
27328
+ const dropComponentIds = (models, item, model) => {
27329
+ if (!isPlainObject(item)) {
27330
+ return;
27331
+ }
27332
+ delete item.id;
27333
+ for (const [name2, attribute] of Object.entries(model?.attributes || {})) {
27334
+ const value = item[name2];
27335
+ if (attribute.type === "component") {
27336
+ const componentModel = findModel(models, attribute.component);
27337
+ (Array.isArray(value) ? value : [value]).forEach((child) => dropComponentIds(models, child, componentModel));
27338
+ } else if (attribute.type === "dynamiczone" && Array.isArray(value)) {
27339
+ value.forEach((child) => dropComponentIds(models, child, findModel(models, child?.__component)));
27340
+ }
27341
+ }
27342
+ };
27343
+ const asNewComponent = (models, sourceItem, model) => {
27344
+ const copy = cloneDeep(sourceItem);
27345
+ dropComponentIds(models, copy, model);
27346
+ return copy;
27347
+ };
27348
+ const alignLocalizedEntryToSource = (models, localizedEntry, sourceEntry, model, downloadedEntry) => {
27349
+ if (!isPlainObject(localizedEntry) || !isPlainObject(sourceEntry) || !isPlainObject(downloadedEntry)) {
27350
+ return localizedEntry;
27351
+ }
27352
+ const aligned = { ...localizedEntry };
27353
+ for (const [name2, attribute] of Object.entries(model?.attributes || {})) {
27354
+ const source = sourceEntry[name2];
27355
+ const current = localizedEntry[name2];
27356
+ const downloaded = downloadedEntry[name2];
27357
+ if (downloaded === void 0 || downloaded === null || current === void 0) {
27358
+ continue;
27359
+ }
27360
+ if (attribute.type === "component") {
27361
+ const componentModel = findModel(models, attribute.component);
27362
+ if (attribute.repeatable) {
27363
+ if (!Array.isArray(source)) continue;
27364
+ const currentItems = Array.isArray(current) ? current : [];
27365
+ aligned[name2] = currentItems.length === source.length ? currentItems.map(
27366
+ (item, index2) => alignLocalizedEntryToSource(models, item, source[index2], componentModel, downloaded[index2])
27367
+ ) : source.map((item) => asNewComponent(models, item, componentModel));
27368
+ } else if (isPlainObject(source) && isPlainObject(current)) {
27369
+ aligned[name2] = alignLocalizedEntryToSource(models, current, source, componentModel, downloaded);
27370
+ }
27371
+ } else if (attribute.type === "dynamiczone") {
27372
+ if (!Array.isArray(source)) continue;
27373
+ const currentItems = Array.isArray(current) ? current : [];
27374
+ const sameLayout = currentItems.length === source.length && currentItems.every((item, index2) => item?.__component === source[index2]?.__component);
27375
+ aligned[name2] = sameLayout ? currentItems.map(
27376
+ (item, index2) => alignLocalizedEntryToSource(
27377
+ models,
27378
+ item,
27379
+ source[index2],
27380
+ findModel(models, item.__component),
27381
+ downloaded[index2]
27382
+ )
27383
+ ) : source.map((item) => asNewComponent(models, item, findModel(models, item.__component)));
27384
+ }
27385
+ }
27386
+ return aligned;
27387
+ };
27155
27388
  const parsedLocalazyEntryToUpdateEntry = async (allModels, localazyEntry, fullyPopulatedLocalizedEntry, currentEntry, baseEntry, uid, locale) => {
27156
- const { createEntry, dynamicZoneComponentKeys } = parsedLocalazyEntryToCreateEntry(
27389
+ const { createEntry, dynamicZoneComponentKeys, rebuiltFieldPaths } = parsedLocalazyEntryToCreateEntry(
27157
27390
  allModels,
27158
27391
  localazyEntry,
27159
27392
  baseEntry,
27160
27393
  uid
27161
27394
  );
27395
+ const model = findModel(allModels, uid);
27396
+ const alignedCurrentEntry = alignLocalizedEntryToSource(allModels, currentEntry, baseEntry, model, createEntry);
27162
27397
  let updateEntry = {};
27163
- merge(updateEntry, currentEntry, createEntry);
27398
+ merge(updateEntry, alignedCurrentEntry, createEntry);
27399
+ for (const rebuiltFieldPath of rebuiltFieldPaths) {
27400
+ set(updateEntry, rebuiltFieldPath, cloneDeep(get(createEntry, rebuiltFieldPath)));
27401
+ }
27164
27402
  updateEntry = omitDeep(updateEntry, [
27165
27403
  // '__component', // do not omit the __component
27166
27404
  "locale",
@@ -27184,16 +27422,19 @@ const parsedLocalazyEntryToUpdateEntry = async (allModels, localazyEntry, fullyP
27184
27422
  "updatedBy",
27185
27423
  "publishedAt"
27186
27424
  ]);
27187
- const filteredFullyPopulatedLocalizedEntry = omitDeep(fullyPopulatedLocalizedEntry, [
27188
- // "__component", // do not omit the __component
27189
- "locale",
27190
- "localizations",
27191
- "createdAt",
27192
- "createdBy",
27193
- "updatedAt",
27194
- "updatedBy",
27195
- "publishedAt"
27196
- ]);
27425
+ const filteredFullyPopulatedLocalizedEntry = omitDeep(
27426
+ alignLocalizedEntryToSource(allModels, fullyPopulatedLocalizedEntry, baseEntry, model, createEntry),
27427
+ [
27428
+ // "__component", // do not omit the __component
27429
+ "locale",
27430
+ "localizations",
27431
+ "createdAt",
27432
+ "createdBy",
27433
+ "updatedAt",
27434
+ "updatedBy",
27435
+ "publishedAt"
27436
+ ]
27437
+ );
27197
27438
  const populatedEntry = await populateCreateUpdateEntryWithBaseEntry(
27198
27439
  allModels,
27199
27440
  updateEntry,
@@ -27204,65 +27445,16 @@ const parsedLocalazyEntryToUpdateEntry = async (allModels, localazyEntry, fullyP
27204
27445
  );
27205
27446
  return populatedEntry;
27206
27447
  };
27207
- const isMediaObject = (obj) => {
27208
- if (typeof obj !== "object" || obj === null) return false;
27209
- 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";
27210
- };
27211
- const dropPropertyDeepWithSkip = (obj, propertyName, isRoot = true, skipPredicates = []) => {
27212
- if (Array.isArray(obj)) {
27213
- return obj.filter((item) => {
27214
- if (skipPredicates.length > 0) {
27215
- return true;
27216
- }
27217
- return isRoot || !(typeof item === "object" && item !== null && propertyName in item);
27218
- }).map(
27219
- (item) => typeof item === "object" && item !== null ? dropPropertyDeepWithSkip(item, propertyName, false, skipPredicates) : item
27220
- );
27221
- }
27222
- if (typeof obj === "object" && obj !== null) {
27223
- const shouldSkip = skipPredicates.some((predicate) => predicate(obj));
27224
- if (shouldSkip) {
27225
- const result2 = {};
27226
- for (const key in obj) {
27227
- if (key === propertyName) {
27228
- result2[key] = obj[key];
27229
- } else {
27230
- result2[key] = typeof obj[key] === "object" && obj[key] !== null ? dropPropertyDeepWithSkip(obj[key], propertyName, false, skipPredicates) : obj[key];
27231
- }
27232
- }
27233
- return result2;
27234
- }
27235
- const result = {};
27236
- for (const key in obj) {
27237
- if (key === propertyName && !isRoot) {
27238
- continue;
27239
- }
27240
- result[key] = typeof obj[key] === "object" && obj[key] !== null ? dropPropertyDeepWithSkip(obj[key], propertyName, false, skipPredicates) : obj[key];
27241
- }
27242
- return result;
27243
- }
27244
- return obj;
27245
- };
27246
- const dropDocumentIdExceptMedia = (obj) => {
27247
- return dropPropertyDeepWithSkip(obj, "documentId", true, [isMediaObject]);
27248
- };
27249
27448
  const StrapiLocalazyI18nService = ({ strapi: strapi2 }) => ({
27250
27449
  async createEntry(uid, strapiContentTypesModels, translatedModel, baseEntry, isoStrapi) {
27251
27450
  const StrapiI18nService2 = getStrapiI18nService();
27252
- const { createEntry } = parsedLocalazyEntryToCreateEntry(
27451
+ const mergedCreateEntry = buildLocalizedCreateEntry(
27253
27452
  strapiContentTypesModels,
27254
27453
  translatedModel,
27255
27454
  baseEntry,
27256
27455
  uid,
27257
27456
  isoStrapi
27258
27457
  );
27259
- const omitKeys = ["locale", "localizations", "createdAt", "createdBy", "updatedAt", "updatedBy", "publishedAt"];
27260
- let filteredBaseEntry = omitDeep(baseEntry, omitKeys);
27261
- filteredBaseEntry = dropDocumentIdExceptMedia(filteredBaseEntry);
27262
- let mergedCreateEntry = {};
27263
- merge(mergedCreateEntry, filteredBaseEntry, createEntry);
27264
- mergedCreateEntry = omitDeep(mergedCreateEntry, omitKeys);
27265
- mergedCreateEntry.locale = isoStrapi;
27266
27458
  const createdEntry = await StrapiI18nService2.createLocalizationForAnExistingEntry(
27267
27459
  uid,
27268
27460
  baseEntry,