@strapi/i18n 5.0.0-rc.2 → 5.0.0-rc.21

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 (43) hide show
  1. package/dist/_chunks/{SettingsPage-CsGvujny.mjs → SettingsPage-4-K93FBe.mjs} +6 -6
  2. package/dist/_chunks/SettingsPage-4-K93FBe.mjs.map +1 -0
  3. package/dist/_chunks/{SettingsPage-DA9haizZ.js → SettingsPage-Cfi_zf_I.js} +6 -6
  4. package/dist/_chunks/SettingsPage-Cfi_zf_I.js.map +1 -0
  5. package/dist/_chunks/{en-BsOU9o5z.js → en-B6327hMz.js} +8 -2
  6. package/dist/_chunks/en-B6327hMz.js.map +1 -0
  7. package/dist/_chunks/{en-CM6Pjfyv.mjs → en-DZXpOMHo.mjs} +8 -2
  8. package/dist/_chunks/en-DZXpOMHo.mjs.map +1 -0
  9. package/dist/_chunks/{index-CCZJF_EJ.mjs → index-B2uG3lvD.mjs} +332 -127
  10. package/dist/_chunks/index-B2uG3lvD.mjs.map +1 -0
  11. package/dist/_chunks/{index-DIzVXZoE.js → index-DpT683lz.js} +325 -120
  12. package/dist/_chunks/index-DpT683lz.js.map +1 -0
  13. package/dist/admin/index.js +1 -1
  14. package/dist/admin/index.mjs +1 -1
  15. package/dist/admin/src/components/BulkLocaleActionModal.d.ts +2 -1
  16. package/dist/admin/src/components/CMHeaderActions.d.ts +27 -3
  17. package/dist/admin/src/utils/clean.d.ts +4 -0
  18. package/dist/server/index.js +61 -98
  19. package/dist/server/index.js.map +1 -1
  20. package/dist/server/index.mjs +62 -99
  21. package/dist/server/index.mjs.map +1 -1
  22. package/dist/server/src/bootstrap.d.ts +1 -4
  23. package/dist/server/src/bootstrap.d.ts.map +1 -1
  24. package/dist/server/src/index.d.ts +15 -13
  25. package/dist/server/src/index.d.ts.map +1 -1
  26. package/dist/server/src/services/index.d.ts +14 -10
  27. package/dist/server/src/services/index.d.ts.map +1 -1
  28. package/dist/server/src/services/permissions/actions.d.ts +14 -2
  29. package/dist/server/src/services/permissions/actions.d.ts.map +1 -1
  30. package/dist/server/src/services/permissions.d.ts +14 -2
  31. package/dist/server/src/services/permissions.d.ts.map +1 -1
  32. package/dist/server/src/utils/index.d.ts +0 -2
  33. package/dist/server/src/utils/index.d.ts.map +1 -1
  34. package/package.json +9 -9
  35. package/dist/_chunks/SettingsPage-CsGvujny.mjs.map +0 -1
  36. package/dist/_chunks/SettingsPage-DA9haizZ.js.map +0 -1
  37. package/dist/_chunks/en-BsOU9o5z.js.map +0 -1
  38. package/dist/_chunks/en-CM6Pjfyv.mjs.map +0 -1
  39. package/dist/_chunks/index-CCZJF_EJ.mjs.map +0 -1
  40. package/dist/_chunks/index-DIzVXZoE.js.map +0 -1
  41. package/dist/server/src/services/entity-service-decorator.d.ts +0 -29
  42. package/dist/server/src/services/entity-service-decorator.d.ts.map +0 -1
  43. package/strapi-server.js +0 -3
@@ -241,10 +241,94 @@ const relationsApi = i18nApi.injectEndpoints({
241
241
  })
242
242
  });
243
243
  const { useGetManyDraftRelationCountQuery } = relationsApi;
244
+ const cleanData = (data, schema, components) => {
245
+ const cleanedData = removeFields(data, [
246
+ "createdAt",
247
+ "createdBy",
248
+ "updatedAt",
249
+ "updatedBy",
250
+ "id",
251
+ "documentId",
252
+ "publishedAt",
253
+ "strapi_stage",
254
+ "strapi_assignee",
255
+ "locale",
256
+ "status"
257
+ ]);
258
+ const cleanedDataWithoutPasswordAndRelation = recursiveRemoveFieldTypes(
259
+ cleanedData,
260
+ schema,
261
+ components,
262
+ ["relation", "password"]
263
+ );
264
+ return cleanedDataWithoutPasswordAndRelation;
265
+ };
266
+ const removeFields = (data, fields) => {
267
+ return Object.keys(data).reduce((acc, current) => {
268
+ if (fields.includes(current)) {
269
+ return acc;
270
+ }
271
+ acc[current] = data[current];
272
+ return acc;
273
+ }, {});
274
+ };
275
+ const recursiveRemoveFieldTypes = (data, schema, components, fields) => {
276
+ return Object.keys(data).reduce((acc, current) => {
277
+ const attribute = schema.attributes[current] ?? { type: void 0 };
278
+ if (fields.includes(attribute.type)) {
279
+ return acc;
280
+ }
281
+ if (attribute.type === "dynamiczone") {
282
+ acc[current] = data[current].map((componentValue, index2) => {
283
+ const { id: _, ...rest } = recursiveRemoveFieldTypes(
284
+ componentValue,
285
+ components[componentValue.__component],
286
+ components,
287
+ fields
288
+ );
289
+ return {
290
+ ...rest,
291
+ __temp_key__: index2 + 1
292
+ };
293
+ });
294
+ } else if (attribute.type === "component") {
295
+ const { repeatable, component } = attribute;
296
+ if (repeatable) {
297
+ acc[current] = (data[current] ?? []).map((compoData, index2) => {
298
+ const { id: _, ...rest } = recursiveRemoveFieldTypes(
299
+ compoData,
300
+ components[component],
301
+ components,
302
+ fields
303
+ );
304
+ return {
305
+ ...rest,
306
+ __temp_key__: index2 + 1
307
+ };
308
+ });
309
+ } else {
310
+ const { id: _, ...rest } = recursiveRemoveFieldTypes(
311
+ data[current] ?? {},
312
+ components[component],
313
+ components,
314
+ fields
315
+ );
316
+ acc[current] = rest;
317
+ }
318
+ } else {
319
+ acc[current] = data[current];
320
+ }
321
+ return acc;
322
+ }, {});
323
+ };
244
324
  const isErrorMessageDescriptor = (object) => {
245
325
  return typeof object === "object" && object !== null && "id" in object && "defaultMessage" in object;
246
326
  };
247
- const EntryValidationText = ({ status = "draft", validationErrors }) => {
327
+ const EntryValidationText = ({
328
+ status = "draft",
329
+ validationErrors,
330
+ action
331
+ }) => {
248
332
  const { formatMessage } = reactIntl.useIntl();
249
333
  const getErrorStr = (key, value) => {
250
334
  if (typeof value === "string") {
@@ -278,30 +362,63 @@ const EntryValidationText = ({ status = "draft", validationErrors }) => {
278
362
  ) })
279
363
  ] });
280
364
  }
281
- if (status === "published") {
282
- return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, children: [
283
- /* @__PURE__ */ jsxRuntime.jsx(icons.CheckCircle, { fill: "success600" }),
284
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { textColor: "success600", fontWeight: "bold", children: formatMessage({
285
- id: "content-manager.bulk-publish.already-published",
286
- defaultMessage: "Already Published"
287
- }) })
288
- ] });
289
- }
290
- if (status === "modified") {
291
- return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, children: [
292
- /* @__PURE__ */ jsxRuntime.jsx(icons.ArrowsCounterClockwise, { fill: "alternative600" }),
293
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { children: formatMessage({
294
- id: "app.utils.ready-to-publish-changes",
295
- defaultMessage: "Ready to publish changes"
296
- }) })
297
- ] });
298
- }
365
+ const getStatusMessage = () => {
366
+ if (action === "bulk-publish") {
367
+ if (status === "published") {
368
+ return {
369
+ icon: /* @__PURE__ */ jsxRuntime.jsx(icons.CheckCircle, { fill: "success600" }),
370
+ text: formatMessage({
371
+ id: "content-manager.bulk-publish.already-published",
372
+ defaultMessage: "Already Published"
373
+ }),
374
+ textColor: "success600",
375
+ fontWeight: "bold"
376
+ };
377
+ } else if (status === "modified") {
378
+ return {
379
+ icon: /* @__PURE__ */ jsxRuntime.jsx(icons.ArrowsCounterClockwise, { fill: "alternative600" }),
380
+ text: formatMessage({
381
+ id: "app.utils.ready-to-publish-changes",
382
+ defaultMessage: "Ready to publish changes"
383
+ })
384
+ };
385
+ } else {
386
+ return {
387
+ icon: /* @__PURE__ */ jsxRuntime.jsx(icons.CheckCircle, { fill: "success600" }),
388
+ text: formatMessage({
389
+ id: "app.utils.ready-to-publish",
390
+ defaultMessage: "Ready to publish"
391
+ })
392
+ };
393
+ }
394
+ } else {
395
+ if (status === "draft") {
396
+ return {
397
+ icon: /* @__PURE__ */ jsxRuntime.jsx(icons.CheckCircle, { fill: "success600" }),
398
+ text: formatMessage({
399
+ id: "content-manager.bulk-unpublish.already-unpublished",
400
+ defaultMessage: "Already Unpublished"
401
+ }),
402
+ textColor: "success600",
403
+ fontWeight: "bold"
404
+ };
405
+ } else {
406
+ return {
407
+ icon: /* @__PURE__ */ jsxRuntime.jsx(icons.CheckCircle, { fill: "success600" }),
408
+ text: formatMessage({
409
+ id: "app.utils.ready-to-unpublish-changes",
410
+ defaultMessage: "Ready to unpublish"
411
+ }),
412
+ textColor: "success600",
413
+ fontWeight: "bold"
414
+ };
415
+ }
416
+ }
417
+ };
418
+ const { icon, text, textColor = "success600", fontWeight = "normal" } = getStatusMessage();
299
419
  return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, children: [
300
- /* @__PURE__ */ jsxRuntime.jsx(icons.CheckCircle, { fill: "success600" }),
301
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { children: formatMessage({
302
- id: "app.utils.ready-to-publish",
303
- defaultMessage: "Ready to publish"
304
- }) })
420
+ icon,
421
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { textColor, fontWeight, children: text })
305
422
  ] });
306
423
  };
307
424
  const BoldChunk = (chunks) => /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { fontWeight: "bold", children: chunks });
@@ -309,7 +426,8 @@ const BulkLocaleActionModal = ({
309
426
  headers,
310
427
  rows,
311
428
  localesMetadata,
312
- validationErrors = {}
429
+ validationErrors = {},
430
+ action
313
431
  }) => {
314
432
  const { formatMessage } = reactIntl.useIntl();
315
433
  const selectedRows = strapiAdmin.useTable(
@@ -322,22 +440,24 @@ const BulkLocaleActionModal = ({
322
440
  return acc;
323
441
  }, {});
324
442
  const localesWithErrors = Object.keys(validationErrors);
325
- const alreadyPublishedCount = selectedRows.filter(
443
+ const publishedCount = selectedRows.filter(
326
444
  ({ locale }) => currentStatusByLocale[locale] === "published"
327
445
  ).length;
328
- const readyToPublishCount = selectedRows.filter(
446
+ const draftCount = selectedRows.filter(
329
447
  ({ locale }) => (currentStatusByLocale[locale] === "draft" || currentStatusByLocale[locale] === "modified") && !localesWithErrors.includes(locale)
330
448
  ).length;
331
449
  const withErrorsCount = localesWithErrors.length;
450
+ const messageId = action === "bulk-publish" ? "content-manager.containers.list.selectedEntriesModal.selectedCount.publish" : "content-manager.containers.list.selectedEntriesModal.selectedCount.unpublish";
451
+ const defaultMessage = action === "bulk-publish" ? "<b>{publishedCount}</b> {publishedCount, plural, =0 {entries} one {entry} other {entries}} already published. <b>{draftCount}</b> {draftCount, plural, =0 {entries} one {entry} other {entries}} ready to publish. <b>{withErrorsCount}</b> {withErrorsCount, plural, =0 {entries} one {entry} other {entries}} waiting for action." : "<b>{draftCount}</b> {draftCount, plural, =0 {entries} one {entry} other {entries}} already unpublished. <b>{publishedCount}</b> {publishedCount, plural, =0 {entries} one {entry} other {entries}} ready to unpublish.";
332
452
  return formatMessage(
333
453
  {
334
- id: "content-manager.containers.list.selectedEntriesModal.selectedCount",
335
- defaultMessage: "<b>{alreadyPublishedCount}</b> {alreadyPublishedCount, plural, =0 {entries} one {entry} other {entries}} already published. <b>{readyToPublishCount}</b> {readyToPublishCount, plural, =0 {entries} one {entry} other {entries}} ready to publish. <b>{withErrorsCount}</b> {withErrorsCount, plural, =0 {entries} one {entry} other {entries}} waiting for action."
454
+ id: messageId,
455
+ defaultMessage
336
456
  },
337
457
  {
338
458
  withErrorsCount,
339
- readyToPublishCount,
340
- alreadyPublishedCount,
459
+ draftCount,
460
+ publishedCount,
341
461
  b: BoldChunk
342
462
  }
343
463
  );
@@ -369,7 +489,7 @@ const BulkLocaleActionModal = ({
369
489
  children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { tag: "span", variant: "pi", fontWeight: "bold", children: capitalize(status) })
370
490
  }
371
491
  ) }) }),
372
- /* @__PURE__ */ jsxRuntime.jsx(strapiAdmin.Table.Cell, { children: /* @__PURE__ */ jsxRuntime.jsx(EntryValidationText, { validationErrors: error, status }) }),
492
+ /* @__PURE__ */ jsxRuntime.jsx(strapiAdmin.Table.Cell, { children: /* @__PURE__ */ jsxRuntime.jsx(EntryValidationText, { validationErrors: error, status, action }) }),
373
493
  /* @__PURE__ */ jsxRuntime.jsx(strapiAdmin.Table.Cell, { children: /* @__PURE__ */ jsxRuntime.jsx(
374
494
  designSystem.IconButton,
375
495
  {
@@ -386,7 +506,7 @@ const BulkLocaleActionModal = ({
386
506
  name: locale
387
507
  }
388
508
  ),
389
- borderWidth: 0,
509
+ variant: "ghost",
390
510
  children: /* @__PURE__ */ jsxRuntime.jsx(icons.Pencil, {})
391
511
  }
392
512
  ) })
@@ -406,7 +526,13 @@ const LocalePickerAction = ({
406
526
  const [{ query: query2 }, setQuery] = strapiAdmin.useQueryParams();
407
527
  const { hasI18n, canCreate, canRead } = useI18n();
408
528
  const { data: locales = [] } = useGetLocalesQuery();
409
- const { schema } = strapiAdmin$1.unstable_useDocument({ model, collectionType, documentId });
529
+ const currentDesiredLocale = query2.plugins?.i18n?.locale;
530
+ const { schema } = strapiAdmin$1.unstable_useDocument({
531
+ model,
532
+ collectionType,
533
+ documentId,
534
+ params: { locale: currentDesiredLocale }
535
+ });
410
536
  const handleSelect = React__namespace.useCallback(
411
537
  (value) => {
412
538
  setQuery({
@@ -424,21 +550,20 @@ const LocalePickerAction = ({
424
550
  if (!Array.isArray(locales) || !hasI18n) {
425
551
  return;
426
552
  }
427
- const currentDesiredLocale = query2.plugins?.i18n?.locale;
428
553
  const doesLocaleExist = locales.find((loc) => loc.code === currentDesiredLocale);
429
554
  const defaultLocale = locales.find((locale) => locale.isDefault);
430
555
  if (!doesLocaleExist && defaultLocale?.code) {
431
556
  handleSelect(defaultLocale.code);
432
557
  }
433
- }, [handleSelect, hasI18n, locales, query2.plugins?.i18n?.locale]);
434
- if (!hasI18n || !Array.isArray(locales) || locales.length === 0) {
435
- return null;
436
- }
437
- const currentLocale = query2.plugins?.i18n?.locale || locales.find((loc) => loc.isDefault)?.code;
558
+ }, [handleSelect, hasI18n, locales, currentDesiredLocale]);
559
+ const currentLocale = Array.isArray(locales) ? locales.find((locale) => locale.code === currentDesiredLocale)?.code : void 0;
438
560
  const allCurrentLocales = [
439
561
  { status: getDocumentStatus(document, meta), locale: currentLocale },
440
562
  ...meta?.availableLocales ?? []
441
563
  ];
564
+ if (!hasI18n || !Array.isArray(locales) || locales.length === 0) {
565
+ return null;
566
+ }
442
567
  return {
443
568
  label: formatMessage({
444
569
  id: getTranslation("Settings.locales.modal.locales.label"),
@@ -450,7 +575,7 @@ const LocalePickerAction = ({
450
575
  );
451
576
  const status = currentLocaleDoc?.status ?? "draft";
452
577
  const permissionsToCheck = currentLocaleDoc ? canCreate : canRead;
453
- const statusVariant = status === "draft" ? "primary" : status === "published" ? "success" : "alternative";
578
+ const statusVariant = status === "draft" ? "secondary" : status === "published" ? "success" : "alternative";
454
579
  return {
455
580
  disabled: !permissionsToCheck.includes(locale.code),
456
581
  value: locale.code,
@@ -486,6 +611,95 @@ const getDocumentStatus = (document, meta) => {
486
611
  }
487
612
  return docStatus;
488
613
  };
614
+ const FillFromAnotherLocaleAction = ({
615
+ documentId,
616
+ meta,
617
+ model,
618
+ collectionType
619
+ }) => {
620
+ const { formatMessage } = reactIntl.useIntl();
621
+ const [{ query: query2 }] = strapiAdmin.useQueryParams();
622
+ const currentDesiredLocale = query2.plugins?.i18n?.locale;
623
+ const [localeSelected, setLocaleSelected] = React__namespace.useState(null);
624
+ const setValues = strapiAdmin.useForm("FillFromAnotherLocale", (state) => state.setValues);
625
+ const { getDocument } = strapiAdmin$1.unstable_useDocumentActions();
626
+ const { schema, components } = strapiAdmin$1.unstable_useDocument({
627
+ model,
628
+ documentId,
629
+ collectionType,
630
+ params: { locale: currentDesiredLocale }
631
+ });
632
+ const { data: locales = [] } = useGetLocalesQuery();
633
+ const availableLocales = Array.isArray(locales) ? locales.filter((locale) => meta?.availableLocales.some((l) => l.locale === locale.code)) : [];
634
+ const fillFromLocale = (onClose) => async () => {
635
+ const response = await getDocument({
636
+ collectionType,
637
+ model,
638
+ documentId,
639
+ params: { locale: localeSelected }
640
+ });
641
+ if (!response || !schema) {
642
+ return;
643
+ }
644
+ const { data } = response;
645
+ const cleanedData = cleanData(data, schema, components);
646
+ setValues(cleanedData);
647
+ onClose();
648
+ };
649
+ return {
650
+ type: "icon",
651
+ icon: /* @__PURE__ */ jsxRuntime.jsx(icons.Download, {}),
652
+ disabled: availableLocales.length === 0,
653
+ label: formatMessage({
654
+ id: getTranslation("CMEditViewCopyLocale.copy-text"),
655
+ defaultMessage: "Fill in from another locale"
656
+ }),
657
+ dialog: {
658
+ type: "dialog",
659
+ title: formatMessage({
660
+ id: getTranslation("CMEditViewCopyLocale.dialog.title"),
661
+ defaultMessage: "Confirmation"
662
+ }),
663
+ content: ({ onClose }) => /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
664
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Body, { children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", gap: 3, children: [
665
+ /* @__PURE__ */ jsxRuntime.jsx(icons.WarningCircle, { width: "24px", height: "24px", fill: "danger600" }),
666
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { textAlign: "center", children: formatMessage({
667
+ id: getTranslation("CMEditViewCopyLocale.dialog.body"),
668
+ defaultMessage: "Your current content will be erased and filled by the content of the selected locale:"
669
+ }) }),
670
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Field.Root, { width: "100%", children: [
671
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Label, { children: formatMessage({
672
+ id: getTranslation("CMEditViewCopyLocale.dialog.field.label"),
673
+ defaultMessage: "Locale"
674
+ }) }),
675
+ /* @__PURE__ */ jsxRuntime.jsx(
676
+ designSystem.SingleSelect,
677
+ {
678
+ value: localeSelected,
679
+ placeholder: formatMessage({
680
+ id: getTranslation("CMEditViewCopyLocale.dialog.field.placeholder"),
681
+ defaultMessage: "Select one locale..."
682
+ }),
683
+ onChange: (value) => setLocaleSelected(value),
684
+ children: availableLocales.map((locale) => /* @__PURE__ */ jsxRuntime.jsx(designSystem.SingleSelectOption, { value: locale.code, children: locale.name }, locale.code))
685
+ }
686
+ )
687
+ ] })
688
+ ] }) }),
689
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Footer, { children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, width: "100%", children: [
690
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { flex: "auto", variant: "tertiary", onClick: onClose, children: formatMessage({
691
+ id: getTranslation("CMEditViewCopyLocale.cancel-text"),
692
+ defaultMessage: "No, cancel"
693
+ }) }),
694
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { flex: "auto", variant: "success", onClick: fillFromLocale(onClose), children: formatMessage({
695
+ id: getTranslation("CMEditViewCopyLocale.submit-text"),
696
+ defaultMessage: "Yes, fill in"
697
+ }) })
698
+ ] }) })
699
+ ] })
700
+ }
701
+ };
702
+ };
489
703
  const DeleteLocaleAction = ({
490
704
  document,
491
705
  documentId,
@@ -497,16 +711,23 @@ const DeleteLocaleAction = ({
497
711
  const { toggleNotification } = strapiAdmin.useNotification();
498
712
  const { delete: deleteAction } = strapiAdmin$1.unstable_useDocumentActions();
499
713
  const { hasI18n, canDelete } = useI18n();
714
+ const [{ query: query2 }] = strapiAdmin.useQueryParams();
715
+ const { data: locales = [] } = useGetLocalesQuery();
716
+ const currentDesiredLocale = query2.plugins?.i18n?.locale;
717
+ const locale = !("error" in locales) && locales.find((loc) => loc.code === currentDesiredLocale);
500
718
  if (!hasI18n) {
501
719
  return null;
502
720
  }
503
721
  return {
504
722
  disabled: document?.locale && !canDelete.includes(document.locale) || !document || !document.id,
505
723
  position: ["header", "table-row"],
506
- label: formatMessage({
507
- id: getTranslation("actions.delete.label"),
508
- defaultMessage: "Delete locale"
509
- }),
724
+ label: formatMessage(
725
+ {
726
+ id: getTranslation("actions.delete.label"),
727
+ defaultMessage: "Delete entry ({locale})"
728
+ },
729
+ { locale: locale && locale.name }
730
+ ),
510
731
  icon: /* @__PURE__ */ jsxRuntime.jsx(StyledTrash, {}),
511
732
  variant: "danger",
512
733
  dialog: {
@@ -549,23 +770,24 @@ const DeleteLocaleAction = ({
549
770
  }
550
771
  };
551
772
  };
552
- const BulkLocalePublishAction = ({
773
+ const BulkLocaleAction = ({
553
774
  document: baseDocument,
554
775
  documentId,
555
776
  model,
556
- collectionType
777
+ collectionType,
778
+ action
557
779
  }) => {
558
780
  const baseLocale = baseDocument?.locale ?? null;
559
781
  const [{ query: query$1 }] = strapiAdmin.useQueryParams();
560
782
  const params = React__namespace.useMemo(() => strapiAdmin$1.buildValidParams(query$1), [query$1]);
561
- const isPublishedTab = query$1.status === "published";
783
+ const isOnPublishedTab = query$1.status === "published";
562
784
  const { formatMessage } = reactIntl.useIntl();
563
785
  const { hasI18n, canPublish } = useI18n();
564
786
  const { toggleNotification } = strapiAdmin.useNotification();
565
787
  const { _unstableFormatAPIError: formatAPIError } = strapiAdmin.useAPIErrorHandler();
566
788
  const [selectedRows, setSelectedRows] = React__namespace.useState([]);
567
789
  const [isDraftRelationConfirmationOpen, setIsDraftRelationConfirmationOpen] = React__namespace.useState(false);
568
- const { publishMany: publishManyAction } = strapiAdmin$1.unstable_useDocumentActions();
790
+ const { publishMany: publishManyAction, unpublishMany: unpublishManyAction } = strapiAdmin$1.unstable_useDocumentActions();
569
791
  const {
570
792
  document,
571
793
  meta: documentMeta,
@@ -581,7 +803,7 @@ const BulkLocalePublishAction = ({
581
803
  }
582
804
  },
583
805
  {
584
- skip: !hasI18n
806
+ skip: !hasI18n || !baseLocale
585
807
  }
586
808
  );
587
809
  const { data: localesMetadata = [] } = useGetLocalesQuery(hasI18n ? void 0 : query.skipToken);
@@ -633,12 +855,19 @@ const BulkLocalePublishAction = ({
633
855
  }, {});
634
856
  return [rowsFromMeta, errors];
635
857
  }, [document, documentMeta?.availableLocales, validate]);
636
- const localesToPublish = selectedRows.reduce((acc, selectedRow) => {
637
- if (selectedRow.status !== "published" && !Object.keys(validationErrors).includes(selectedRow.locale)) {
858
+ const isBulkPublish = action === "bulk-publish";
859
+ const localesForAction = selectedRows.reduce((acc, selectedRow) => {
860
+ const isValidLocale = (
861
+ // Validation errors are irrelevant if we are trying to unpublish
862
+ !isBulkPublish || !Object.keys(validationErrors).includes(selectedRow.locale)
863
+ );
864
+ const shouldAddLocale = isBulkPublish ? selectedRow.status !== "published" && isValidLocale : selectedRow.status !== "draft" && isValidLocale;
865
+ if (shouldAddLocale) {
638
866
  acc.push(selectedRow.locale);
639
867
  }
640
868
  return acc;
641
869
  }, []);
870
+ const enableDraftRelationsCount = false;
642
871
  const {
643
872
  data: draftRelationsCount = 0,
644
873
  isLoading: isDraftRelationsLoading,
@@ -647,10 +876,10 @@ const BulkLocalePublishAction = ({
647
876
  {
648
877
  model,
649
878
  documentIds: [documentId],
650
- locale: localesToPublish
879
+ locale: localesForAction
651
880
  },
652
881
  {
653
- skip: !documentId || localesToPublish.length === 0
882
+ skip: !enableDraftRelationsCount
654
883
  }
655
884
  );
656
885
  React__namespace.useEffect(() => {
@@ -676,7 +905,18 @@ const BulkLocalePublishAction = ({
676
905
  documentIds: [documentId],
677
906
  params: {
678
907
  ...params,
679
- locale: localesToPublish
908
+ locale: localesForAction
909
+ }
910
+ });
911
+ setSelectedRows([]);
912
+ };
913
+ const unpublish = async () => {
914
+ await unpublishManyAction({
915
+ model,
916
+ documentIds: [documentId],
917
+ params: {
918
+ ...params,
919
+ locale: localesForAction
680
920
  }
681
921
  });
682
922
  setSelectedRows([]);
@@ -684,14 +924,12 @@ const BulkLocalePublishAction = ({
684
924
  const handleAction = async () => {
685
925
  if (draftRelationsCount > 0) {
686
926
  setIsDraftRelationConfirmationOpen(true);
687
- } else {
927
+ } else if (isBulkPublish) {
688
928
  await publish();
929
+ } else {
930
+ await unpublish();
689
931
  }
690
932
  };
691
- const isUnpublish = document?.status === "published";
692
- if (isUnpublish) {
693
- console.warn(["I18N"], "Bulk locale unpublish modal not implemented");
694
- }
695
933
  if (isDraftRelationConfirmationOpen) {
696
934
  return {
697
935
  label: formatMessage({
@@ -729,18 +967,18 @@ const BulkLocalePublishAction = ({
729
967
  const hasPermission = selectedRows.map(({ locale }) => locale).every((locale) => canPublish.includes(locale));
730
968
  return {
731
969
  label: formatMessage({
732
- id: getTranslation("CMEditViewBulkLocale.publish-title"),
733
- defaultMessage: "Publish Multiple Locales"
970
+ id: getTranslation(`CMEditViewBulkLocale.${isBulkPublish ? "publish" : "unpublish"}-title`),
971
+ defaultMessage: `${isBulkPublish ? "Publish" : "Unpublish"} Multiple Locales`
734
972
  }),
735
- icon: /* @__PURE__ */ jsxRuntime.jsx(icons.ListPlus, {}),
736
- disabled: isPublishedTab || canPublish.length === 0,
973
+ variant: isBulkPublish ? "secondary" : "danger",
974
+ icon: isBulkPublish ? /* @__PURE__ */ jsxRuntime.jsx(icons.ListPlus, {}) : /* @__PURE__ */ jsxRuntime.jsx(icons.Cross, {}),
975
+ disabled: isOnPublishedTab || canPublish.length === 0,
737
976
  position: ["panel"],
738
- variant: "secondary",
739
977
  dialog: {
740
978
  type: "modal",
741
979
  title: formatMessage({
742
- id: getTranslation("CMEditViewBulkLocale.publish-title"),
743
- defaultMessage: "Publish Multiple Locales"
980
+ id: getTranslation(`CMEditViewBulkLocale.${isBulkPublish ? "publish" : "unpublish"}-title`),
981
+ defaultMessage: `${isBulkPublish ? "Publish" : "Unpublish"} Multiple Locales`
744
982
  }),
745
983
  content: () => {
746
984
  return /* @__PURE__ */ jsxRuntime.jsx(
@@ -759,7 +997,8 @@ const BulkLocalePublishAction = ({
759
997
  validationErrors,
760
998
  headers,
761
999
  rows,
762
- localesMetadata
1000
+ localesMetadata,
1001
+ action: action ?? "bulk-publish"
763
1002
  }
764
1003
  )
765
1004
  }
@@ -769,18 +1008,24 @@ const BulkLocalePublishAction = ({
769
1008
  designSystem.Button,
770
1009
  {
771
1010
  loading: isDraftRelationsLoading,
772
- disabled: !hasPermission || localesToPublish.length === 0,
1011
+ disabled: !hasPermission || localesForAction.length === 0,
773
1012
  variant: "default",
774
1013
  onClick: handleAction,
775
1014
  children: formatMessage({
776
- id: "app.utils.publish",
777
- defaultMessage: "Publish"
1015
+ id: isBulkPublish ? "app.utils.publish" : "app.utils.unpublish",
1016
+ defaultMessage: isBulkPublish ? "Publish" : "Unpublish"
778
1017
  })
779
1018
  }
780
1019
  ) })
781
1020
  }
782
1021
  };
783
1022
  };
1023
+ const BulkLocalePublishAction = (props) => {
1024
+ return BulkLocaleAction({ action: "bulk-publish", ...props });
1025
+ };
1026
+ const BulkLocaleUnpublishAction = (props) => {
1027
+ return BulkLocaleAction({ action: "bulk-unpublish", ...props });
1028
+ };
784
1029
  const StyledTrash = styledComponents.styled(icons.Trash)`
785
1030
  path {
786
1031
  fill: currentColor;
@@ -1000,54 +1245,13 @@ const LocaleListCell = ({
1000
1245
  return locale.name;
1001
1246
  }).toSorted((a, b) => formatter.compare(a, b));
1002
1247
  return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Popover.Root, { children: [
1003
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Popover.Trigger, { children: /* @__PURE__ */ jsxRuntime.jsx(Button, { type: "button", onClick: (e) => e.stopPropagation(), children: /* @__PURE__ */ jsxRuntime.jsxs(
1004
- ActionWrapper,
1005
- {
1006
- minWidth: "100%",
1007
- alignItems: "center",
1008
- justifyContent: "center",
1009
- height: "3.2rem",
1010
- width: "3.2rem",
1011
- children: [
1012
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { textColor: "neutral800", ellipsis: true, children: localesForDocument.join(", ") }),
1013
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { children: /* @__PURE__ */ jsxRuntime.jsx(icons.CaretDown, {}) })
1014
- ]
1015
- }
1016
- ) }) }),
1248
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Popover.Trigger, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { variant: "ghost", type: "button", onClick: (e) => e.stopPropagation(), children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { minWidth: "100%", alignItems: "center", justifyContent: "center", fontWeight: "regular", children: [
1249
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { textColor: "neutral800", ellipsis: true, marginRight: 2, children: localesForDocument.join(", ") }),
1250
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { children: /* @__PURE__ */ jsxRuntime.jsx(icons.CaretDown, { width: "1.2rem", height: "1.2rem" }) })
1251
+ ] }) }) }),
1017
1252
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.Popover.Content, { sideOffset: 16, children: /* @__PURE__ */ jsxRuntime.jsx("ul", { children: localesForDocument.map((name) => /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { padding: 3, tag: "li", children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { children: name }) }, name)) }) })
1018
1253
  ] });
1019
1254
  };
1020
- const Button = styledComponents.styled.button`
1021
- width: 100%;
1022
-
1023
- svg {
1024
- > g,
1025
- path {
1026
- fill: ${({ theme }) => theme.colors.neutral500};
1027
- }
1028
- }
1029
- &:hover {
1030
- svg {
1031
- > g,
1032
- path {
1033
- fill: ${({ theme }) => theme.colors.neutral600};
1034
- }
1035
- }
1036
- }
1037
- &:active {
1038
- svg {
1039
- > g,
1040
- path {
1041
- fill: ${({ theme }) => theme.colors.neutral400};
1042
- }
1043
- }
1044
- }
1045
- `;
1046
- const ActionWrapper = styledComponents.styled(designSystem.Flex)`
1047
- svg {
1048
- height: 0.4rem;
1049
- }
1050
- `;
1051
1255
  const addColumnToTableHook = ({ displayedHeaders, layout }) => {
1052
1256
  const { options } = layout;
1053
1257
  const isFieldLocalized = doesPluginOptionsHaveI18nLocalized(options) ? options.i18n.localized : false;
@@ -1245,11 +1449,11 @@ const index = {
1245
1449
  },
1246
1450
  id: "internationalization",
1247
1451
  to: "internationalization",
1248
- Component: () => Promise.resolve().then(() => require("./SettingsPage-DA9haizZ.js")).then((mod) => ({ default: mod.ProtectedSettingsPage })),
1452
+ Component: () => Promise.resolve().then(() => require("./SettingsPage-Cfi_zf_I.js")).then((mod) => ({ default: mod.ProtectedSettingsPage })),
1249
1453
  permissions: PERMISSIONS.accessMain
1250
1454
  });
1251
1455
  const contentManager = app.getPlugin("content-manager");
1252
- contentManager.apis.addDocumentHeaderAction([LocalePickerAction]);
1456
+ contentManager.apis.addDocumentHeaderAction([LocalePickerAction, FillFromAnotherLocaleAction]);
1253
1457
  contentManager.apis.addDocumentAction((actions) => {
1254
1458
  const indexOfDeleteAction = actions.findIndex((action) => action.type === "delete");
1255
1459
  actions.splice(indexOfDeleteAction, 0, DeleteLocaleAction);
@@ -1257,6 +1461,7 @@ const index = {
1257
1461
  });
1258
1462
  contentManager.apis.addDocumentAction((actions) => {
1259
1463
  actions.splice(2, 0, BulkLocalePublishAction);
1464
+ actions.splice(5, 0, BulkLocaleUnpublishAction);
1260
1465
  return actions;
1261
1466
  });
1262
1467
  contentManager.injectComponent("listView", "actions", {
@@ -1362,7 +1567,7 @@ const index = {
1362
1567
  async registerTrads({ locales }) {
1363
1568
  const importedTrads = await Promise.all(
1364
1569
  locales.map((locale) => {
1365
- return __variableDynamicImportRuntimeHelper(/* @__PURE__ */ Object.assign({ "./translations/de.json": () => Promise.resolve().then(() => require("./de-DtWiGdHl.js")), "./translations/dk.json": () => Promise.resolve().then(() => require("./dk-D8C-casx.js")), "./translations/en.json": () => Promise.resolve().then(() => require("./en-BsOU9o5z.js")), "./translations/es.json": () => Promise.resolve().then(() => require("./es-DS-XFGSw.js")), "./translations/fr.json": () => Promise.resolve().then(() => require("./fr-BTjekDpq.js")), "./translations/ko.json": () => Promise.resolve().then(() => require("./ko-DmcGUBQ3.js")), "./translations/pl.json": () => Promise.resolve().then(() => require("./pl-Cn5RYonZ.js")), "./translations/ru.json": () => Promise.resolve().then(() => require("./ru-BMBgVL3s.js")), "./translations/tr.json": () => Promise.resolve().then(() => require("./tr-CarUU76c.js")), "./translations/zh-Hans.json": () => Promise.resolve().then(() => require("./zh-Hans-DSHIXAa3.js")), "./translations/zh.json": () => Promise.resolve().then(() => require("./zh-CukOviB0.js")) }), `./translations/${locale}.json`).then(({ default: data }) => {
1570
+ return __variableDynamicImportRuntimeHelper(/* @__PURE__ */ Object.assign({ "./translations/de.json": () => Promise.resolve().then(() => require("./de-DtWiGdHl.js")), "./translations/dk.json": () => Promise.resolve().then(() => require("./dk-D8C-casx.js")), "./translations/en.json": () => Promise.resolve().then(() => require("./en-B6327hMz.js")), "./translations/es.json": () => Promise.resolve().then(() => require("./es-DS-XFGSw.js")), "./translations/fr.json": () => Promise.resolve().then(() => require("./fr-BTjekDpq.js")), "./translations/ko.json": () => Promise.resolve().then(() => require("./ko-DmcGUBQ3.js")), "./translations/pl.json": () => Promise.resolve().then(() => require("./pl-Cn5RYonZ.js")), "./translations/ru.json": () => Promise.resolve().then(() => require("./ru-BMBgVL3s.js")), "./translations/tr.json": () => Promise.resolve().then(() => require("./tr-CarUU76c.js")), "./translations/zh-Hans.json": () => Promise.resolve().then(() => require("./zh-Hans-DSHIXAa3.js")), "./translations/zh.json": () => Promise.resolve().then(() => require("./zh-CukOviB0.js")) }), `./translations/${locale}.json`).then(({ default: data }) => {
1366
1571
  return {
1367
1572
  data: prefixPluginTranslations(data, pluginId),
1368
1573
  locale
@@ -1386,4 +1591,4 @@ exports.useDeleteLocaleMutation = useDeleteLocaleMutation;
1386
1591
  exports.useGetDefaultLocalesQuery = useGetDefaultLocalesQuery;
1387
1592
  exports.useGetLocalesQuery = useGetLocalesQuery;
1388
1593
  exports.useUpdateLocaleMutation = useUpdateLocaleMutation;
1389
- //# sourceMappingURL=index-DIzVXZoE.js.map
1594
+ //# sourceMappingURL=index-DpT683lz.js.map