@localazy/strapi-plugin 1.6.0 → 1.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (32) 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 +266 -178
  29. package/dist/server/index.mjs +266 -178
  30. package/dist/server/src/utils/blocks-to-translatable.d.ts +34 -0
  31. package/dist/server/src/utils/model-utils.d.ts +2 -1
  32. package/package.json +1 -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.0";
20524
20524
  const description = "The official Strapi Plugin by Localazy.";
20525
20525
  const keywords = [
20526
20526
  "strapi",
@@ -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;
@@ -26101,6 +25925,263 @@ function baseSet(object, path, value, customizer) {
26101
25925
  function set(object, path, value) {
26102
25926
  return object == null ? object : baseSet(object, path, value);
26103
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");
26183
+ }
26184
+ });
26104
26185
  const hasDynamicZoneKeySegment = (parsedKey) => {
26105
26186
  return parsedKey.some((segment) => segment.includes(";"));
26106
26187
  };
@@ -26788,6 +26869,9 @@ const isRepeatable = (attributeObj) => {
26788
26869
  const isRelation = (attributeObj) => {
26789
26870
  return attributeObj.type === "relation" && attributeObj.target !== "plugin::upload.file";
26790
26871
  };
26872
+ const isBlocks = (attributeObj) => {
26873
+ return attributeObj.type === BLOCKS_ATTRIBUTE_TYPE;
26874
+ };
26791
26875
  const findModel = (models, uid) => {
26792
26876
  const model = models.find((model2) => model2.uid === uid);
26793
26877
  return model;
@@ -26931,7 +27015,11 @@ const parsedLocalazyEntryToCreateEntry = (models, parsedLocalazyEntry, baseEntry
26931
27015
  newPrefixBase = `${dzParamKey}.${baseEntryDZIndex}`;
26932
27016
  newPrefix = `${newPrefixBase}.${objectKey}`;
26933
27017
  }
26934
- set(createEntry, newPrefix, value);
27018
+ const valueToSet = isBlocks(attribute) ? overlayBlocksTranslation(get(baseEntry, newPrefix), value) : value;
27019
+ if (valueToSet === void 0) {
27020
+ return;
27021
+ }
27022
+ set(createEntry, newPrefix, valueToSet);
26935
27023
  if (component) {
26936
27024
  const componentKeyToSet = `${newPrefixBase}.__component`;
26937
27025
  set(createEntry, componentKeyToSet, component);
@@ -0,0 +1,34 @@
1
+ export declare const BLOCKS_ATTRIBUTE_TYPE = "blocks";
2
+ type GetModel = (uid: string) => {
3
+ attributes?: Record<string, any>;
4
+ } | undefined;
5
+ /**
6
+ * Upload side. A Blocks value is a rich-text AST: text lives in `text` leaves, everything else
7
+ * (block types, headings, lists, links, marks, images, quotes, code blocks) is structure. We
8
+ * project each blocks field down to a skeleton that keeps only the translatable text leaves in
9
+ * their original positions, so the transfer pipeline emits ONE segment per text node with the
10
+ * formatting carried as structure — never as literal markup inside the string. The dropped
11
+ * structure is restored from the source AST on download (see `overlayBlocksTranslation`). Blocks
12
+ * nested inside components / dynamic zones are reached by walking the schema. The source entry is
13
+ * not mutated.
14
+ */
15
+ export declare const projectBlocksFields: (entry: any, model: any, getModel: GetModel) => any;
16
+ /**
17
+ * Reduce a blocks AST to a text-only skeleton: every node keeps only its `text` leaf and/or its
18
+ * (recursively projected) `children`. Structural nodes without text (e.g. images, dividers) become
19
+ * empty and contribute no segment. Positions are preserved so download can overlay by path.
20
+ */
21
+ export declare const projectBlocksValue: (nodes: any) => any;
22
+ /**
23
+ * Download side. Rebuild a full blocks AST for the target locale by cloning the source-locale AST
24
+ * and overlaying the translated text onto each text leaf at the matching position. All structure
25
+ * and formatting come from the source, so the result is always a document Strapi accepts, a
26
+ * translation identical to the source round-trips byte-identically, and text nodes left
27
+ * untranslated fall back to the source text. `translated` is the per-node text skeleton
28
+ * reconstructed from the downloaded keys (an array, or an object keyed by numeric position).
29
+ *
30
+ * Returns `undefined` when there is no source AST to overlay onto (nothing safe to write), so the
31
+ * caller can skip the field instead of corrupting it.
32
+ */
33
+ export declare const overlayBlocksTranslation: (sourceAst: any, translated: any) => any[] | undefined;
34
+ export {};
@@ -3,5 +3,6 @@ declare const isComponent: (attributeObj: any) => boolean;
3
3
  declare const isDynamicZone: (attributeObj: any) => boolean;
4
4
  declare const isRepeatable: (attributeObj: any) => boolean;
5
5
  declare const isRelation: (attributeObj: any) => boolean;
6
+ declare const isBlocks: (attributeObj: any) => boolean;
6
7
  declare const findModel: (models: any, uid: any) => any;
7
- export { getAttribute, isComponent, isDynamicZone, isRepeatable, isRelation, findModel };
8
+ export { getAttribute, isComponent, isDynamicZone, isRepeatable, isRelation, isBlocks, findModel };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@localazy/strapi-plugin",
3
- "version": "1.6.0",
3
+ "version": "1.7.0",
4
4
  "description": "The official Strapi Plugin by Localazy.",
5
5
  "keywords": [
6
6
  "strapi",