@strapi/i18n 0.0.0-experimental.f31889311d753b5f7d95198ae84d8fce1d156cd6 → 0.0.0-experimental.f49f46a1c17445a39e8af3f63124bcccf73842e6

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 (51) hide show
  1. package/dist/_chunks/{SettingsPage-DA9haizZ.js → SettingsPage-D0hqaut-.js} +8 -8
  2. package/dist/_chunks/SettingsPage-D0hqaut-.js.map +1 -0
  3. package/dist/_chunks/{SettingsPage-CsGvujny.mjs → SettingsPage-D67CaQAB.mjs} +8 -8
  4. package/dist/_chunks/SettingsPage-D67CaQAB.mjs.map +1 -0
  5. package/dist/_chunks/{en-BsOU9o5z.js → en-BKBz3tro.js} +10 -3
  6. package/dist/_chunks/en-BKBz3tro.js.map +1 -0
  7. package/dist/_chunks/{en-CM6Pjfyv.mjs → en-DlXfy6Gy.mjs} +10 -3
  8. package/dist/_chunks/en-DlXfy6Gy.mjs.map +1 -0
  9. package/dist/_chunks/{index-DIzVXZoE.js → index-46DNtLCn.js} +387 -141
  10. package/dist/_chunks/index-46DNtLCn.js.map +1 -0
  11. package/dist/_chunks/{index-CCZJF_EJ.mjs → index-CNR8i3KM.mjs} +394 -148
  12. package/dist/_chunks/index-CNR8i3KM.mjs.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 +29 -3
  17. package/dist/admin/src/components/CreateLocale.d.ts +6 -6
  18. package/dist/admin/src/utils/clean.d.ts +4 -0
  19. package/dist/server/index.js +413 -480
  20. package/dist/server/index.js.map +1 -1
  21. package/dist/server/index.mjs +415 -482
  22. package/dist/server/index.mjs.map +1 -1
  23. package/dist/server/src/bootstrap.d.ts +1 -4
  24. package/dist/server/src/bootstrap.d.ts.map +1 -1
  25. package/dist/server/src/index.d.ts +21 -13
  26. package/dist/server/src/index.d.ts.map +1 -1
  27. package/dist/server/src/register.d.ts.map +1 -1
  28. package/dist/server/src/services/index.d.ts +20 -10
  29. package/dist/server/src/services/index.d.ts.map +1 -1
  30. package/dist/server/src/services/permissions/actions.d.ts +14 -2
  31. package/dist/server/src/services/permissions/actions.d.ts.map +1 -1
  32. package/dist/server/src/services/permissions.d.ts +14 -2
  33. package/dist/server/src/services/permissions.d.ts.map +1 -1
  34. package/dist/server/src/services/sanitize/index.d.ts +11 -0
  35. package/dist/server/src/services/sanitize/index.d.ts.map +1 -0
  36. package/dist/server/src/utils/index.d.ts +2 -2
  37. package/dist/server/src/utils/index.d.ts.map +1 -1
  38. package/package.json +12 -12
  39. package/dist/_chunks/SettingsPage-CsGvujny.mjs.map +0 -1
  40. package/dist/_chunks/SettingsPage-DA9haizZ.js.map +0 -1
  41. package/dist/_chunks/en-BsOU9o5z.js.map +0 -1
  42. package/dist/_chunks/en-CM6Pjfyv.mjs.map +0 -1
  43. package/dist/_chunks/index-CCZJF_EJ.mjs.map +0 -1
  44. package/dist/_chunks/index-DIzVXZoE.js.map +0 -1
  45. package/dist/server/src/migrations/content-type/disable/index.d.ts +0 -3
  46. package/dist/server/src/migrations/content-type/disable/index.d.ts.map +0 -1
  47. package/dist/server/src/migrations/content-type/enable/index.d.ts +0 -3
  48. package/dist/server/src/migrations/content-type/enable/index.d.ts.map +0 -1
  49. package/dist/server/src/services/entity-service-decorator.d.ts +0 -29
  50. package/dist/server/src/services/entity-service-decorator.d.ts.map +0 -1
  51. 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
  );
@@ -363,13 +483,12 @@ const BulkLocaleActionModal = ({
363
483
  paddingRight: "6px",
364
484
  paddingTop: "2px",
365
485
  paddingBottom: "2px",
366
- showBullet: false,
367
486
  size: "S",
368
487
  variant: statusVariant,
369
488
  children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { tag: "span", variant: "pi", fontWeight: "bold", children: capitalize(status) })
370
489
  }
371
490
  ) }) }),
372
- /* @__PURE__ */ jsxRuntime.jsx(strapiAdmin.Table.Cell, { children: /* @__PURE__ */ jsxRuntime.jsx(EntryValidationText, { validationErrors: error, status }) }),
491
+ /* @__PURE__ */ jsxRuntime.jsx(strapiAdmin.Table.Cell, { children: /* @__PURE__ */ jsxRuntime.jsx(EntryValidationText, { validationErrors: error, status, action }) }),
373
492
  /* @__PURE__ */ jsxRuntime.jsx(strapiAdmin.Table.Cell, { children: /* @__PURE__ */ jsxRuntime.jsx(
374
493
  designSystem.IconButton,
375
494
  {
@@ -386,7 +505,7 @@ const BulkLocaleActionModal = ({
386
505
  name: locale
387
506
  }
388
507
  ),
389
- borderWidth: 0,
508
+ variant: "ghost",
390
509
  children: /* @__PURE__ */ jsxRuntime.jsx(icons.Pencil, {})
391
510
  }
392
511
  ) })
@@ -395,6 +514,47 @@ const BulkLocaleActionModal = ({
395
514
  ] }) })
396
515
  ] });
397
516
  };
517
+ const statusVariants = {
518
+ draft: "secondary",
519
+ published: "success",
520
+ modified: "alternative"
521
+ };
522
+ const LocaleOption = ({
523
+ isDraftAndPublishEnabled,
524
+ locale,
525
+ status,
526
+ entryExists
527
+ }) => {
528
+ const { formatMessage } = reactIntl.useIntl();
529
+ if (!entryExists) {
530
+ return formatMessage(
531
+ {
532
+ id: getTranslation("CMEditViewLocalePicker.locale.create"),
533
+ defaultMessage: "Create <bold>{locale}</bold> locale"
534
+ },
535
+ {
536
+ bold: (locale2) => /* @__PURE__ */ jsxRuntime.jsx("b", { children: locale2 }),
537
+ locale: locale.name
538
+ }
539
+ );
540
+ }
541
+ return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { width: "100%", gap: 1, justifyContent: "space-between", children: [
542
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { children: locale.name }),
543
+ isDraftAndPublishEnabled ? /* @__PURE__ */ jsxRuntime.jsx(
544
+ designSystem.Status,
545
+ {
546
+ display: "flex",
547
+ paddingLeft: "6px",
548
+ paddingRight: "6px",
549
+ paddingTop: "2px",
550
+ paddingBottom: "2px",
551
+ size: "S",
552
+ variant: statusVariants[status],
553
+ children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { tag: "span", variant: "pi", fontWeight: "bold", children: capitalize(status) })
554
+ }
555
+ ) : null
556
+ ] });
557
+ };
398
558
  const LocalePickerAction = ({
399
559
  document,
400
560
  meta,
@@ -406,7 +566,13 @@ const LocalePickerAction = ({
406
566
  const [{ query: query2 }, setQuery] = strapiAdmin.useQueryParams();
407
567
  const { hasI18n, canCreate, canRead } = useI18n();
408
568
  const { data: locales = [] } = useGetLocalesQuery();
409
- const { schema } = strapiAdmin$1.unstable_useDocument({ model, collectionType, documentId });
569
+ const currentDesiredLocale = query2.plugins?.i18n?.locale;
570
+ const { schema } = strapiAdmin$1.unstable_useDocument({
571
+ model,
572
+ collectionType,
573
+ documentId,
574
+ params: { locale: currentDesiredLocale }
575
+ });
410
576
  const handleSelect = React__namespace.useCallback(
411
577
  (value) => {
412
578
  setQuery({
@@ -424,53 +590,47 @@ const LocalePickerAction = ({
424
590
  if (!Array.isArray(locales) || !hasI18n) {
425
591
  return;
426
592
  }
427
- const currentDesiredLocale = query2.plugins?.i18n?.locale;
428
593
  const doesLocaleExist = locales.find((loc) => loc.code === currentDesiredLocale);
429
594
  const defaultLocale = locales.find((locale) => locale.isDefault);
430
595
  if (!doesLocaleExist && defaultLocale?.code) {
431
596
  handleSelect(defaultLocale.code);
432
597
  }
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;
598
+ }, [handleSelect, hasI18n, locales, currentDesiredLocale]);
599
+ const currentLocale = Array.isArray(locales) ? locales.find((locale) => locale.code === currentDesiredLocale) : void 0;
438
600
  const allCurrentLocales = [
439
- { status: getDocumentStatus(document, meta), locale: currentLocale },
601
+ { status: getDocumentStatus(document, meta), locale: currentLocale?.code },
440
602
  ...meta?.availableLocales ?? []
441
603
  ];
604
+ if (!hasI18n || !Array.isArray(locales) || locales.length === 0) {
605
+ return null;
606
+ }
442
607
  return {
443
608
  label: formatMessage({
444
609
  id: getTranslation("Settings.locales.modal.locales.label"),
445
610
  defaultMessage: "Locales"
446
611
  }),
447
612
  options: locales.map((locale) => {
613
+ const entryWithLocaleExists = allCurrentLocales.some((doc) => doc.locale === locale.code);
448
614
  const currentLocaleDoc = allCurrentLocales.find(
449
615
  (doc) => "locale" in doc ? doc.locale === locale.code : false
450
616
  );
451
- const status = currentLocaleDoc?.status ?? "draft";
452
- const permissionsToCheck = currentLocaleDoc ? canCreate : canRead;
453
- const statusVariant = status === "draft" ? "primary" : status === "published" ? "success" : "alternative";
617
+ const permissionsToCheck = currentLocaleDoc ? canRead : canCreate;
454
618
  return {
455
619
  disabled: !permissionsToCheck.includes(locale.code),
456
620
  value: locale.code,
457
- label: locale.name,
458
- startIcon: schema?.options?.draftAndPublish ? /* @__PURE__ */ jsxRuntime.jsx(
459
- designSystem.Status,
621
+ label: /* @__PURE__ */ jsxRuntime.jsx(
622
+ LocaleOption,
460
623
  {
461
- display: "flex",
462
- paddingLeft: "6px",
463
- paddingRight: "6px",
464
- paddingTop: "2px",
465
- paddingBottom: "2px",
466
- showBullet: false,
467
- size: "S",
468
- variant: statusVariant,
469
- children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { tag: "span", variant: "pi", fontWeight: "bold", children: capitalize(status) })
624
+ isDraftAndPublishEnabled: !!schema?.options?.draftAndPublish,
625
+ locale,
626
+ status: currentLocaleDoc?.status,
627
+ entryExists: entryWithLocaleExists
470
628
  }
471
- ) : null
629
+ ),
630
+ startIcon: !entryWithLocaleExists ? /* @__PURE__ */ jsxRuntime.jsx(icons.Plus, {}) : null
472
631
  };
473
632
  }),
633
+ customizeContent: () => currentLocale?.name,
474
634
  onSelect: handleSelect,
475
635
  value: currentLocale
476
636
  };
@@ -486,6 +646,99 @@ const getDocumentStatus = (document, meta) => {
486
646
  }
487
647
  return docStatus;
488
648
  };
649
+ const FillFromAnotherLocaleAction = ({
650
+ documentId,
651
+ meta,
652
+ model,
653
+ collectionType
654
+ }) => {
655
+ const { formatMessage } = reactIntl.useIntl();
656
+ const [{ query: query2 }] = strapiAdmin.useQueryParams();
657
+ const { hasI18n } = useI18n();
658
+ const currentDesiredLocale = query2.plugins?.i18n?.locale;
659
+ const [localeSelected, setLocaleSelected] = React__namespace.useState(null);
660
+ const setValues = strapiAdmin.useForm("FillFromAnotherLocale", (state) => state.setValues);
661
+ const { getDocument } = strapiAdmin$1.unstable_useDocumentActions();
662
+ const { schema, components } = strapiAdmin$1.unstable_useDocument({
663
+ model,
664
+ documentId,
665
+ collectionType,
666
+ params: { locale: currentDesiredLocale }
667
+ });
668
+ const { data: locales = [] } = useGetLocalesQuery();
669
+ const availableLocales = Array.isArray(locales) ? locales.filter((locale) => meta?.availableLocales.some((l) => l.locale === locale.code)) : [];
670
+ const fillFromLocale = (onClose) => async () => {
671
+ const response = await getDocument({
672
+ collectionType,
673
+ model,
674
+ documentId,
675
+ params: { locale: localeSelected }
676
+ });
677
+ if (!response || !schema) {
678
+ return;
679
+ }
680
+ const { data } = response;
681
+ const cleanedData = cleanData(data, schema, components);
682
+ setValues(cleanedData);
683
+ onClose();
684
+ };
685
+ if (!hasI18n) {
686
+ return null;
687
+ }
688
+ return {
689
+ type: "icon",
690
+ icon: /* @__PURE__ */ jsxRuntime.jsx(icons.Download, {}),
691
+ disabled: availableLocales.length === 0,
692
+ label: formatMessage({
693
+ id: getTranslation("CMEditViewCopyLocale.copy-text"),
694
+ defaultMessage: "Fill in from another locale"
695
+ }),
696
+ dialog: {
697
+ type: "dialog",
698
+ title: formatMessage({
699
+ id: getTranslation("CMEditViewCopyLocale.dialog.title"),
700
+ defaultMessage: "Confirmation"
701
+ }),
702
+ content: ({ onClose }) => /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
703
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Body, { children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", gap: 3, children: [
704
+ /* @__PURE__ */ jsxRuntime.jsx(icons.WarningCircle, { width: "24px", height: "24px", fill: "danger600" }),
705
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { textAlign: "center", children: formatMessage({
706
+ id: getTranslation("CMEditViewCopyLocale.dialog.body"),
707
+ defaultMessage: "Your current content will be erased and filled by the content of the selected locale:"
708
+ }) }),
709
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Field.Root, { width: "100%", children: [
710
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Label, { children: formatMessage({
711
+ id: getTranslation("CMEditViewCopyLocale.dialog.field.label"),
712
+ defaultMessage: "Locale"
713
+ }) }),
714
+ /* @__PURE__ */ jsxRuntime.jsx(
715
+ designSystem.SingleSelect,
716
+ {
717
+ value: localeSelected,
718
+ placeholder: formatMessage({
719
+ id: getTranslation("CMEditViewCopyLocale.dialog.field.placeholder"),
720
+ defaultMessage: "Select one locale..."
721
+ }),
722
+ onChange: (value) => setLocaleSelected(value),
723
+ children: availableLocales.map((locale) => /* @__PURE__ */ jsxRuntime.jsx(designSystem.SingleSelectOption, { value: locale.code, children: locale.name }, locale.code))
724
+ }
725
+ )
726
+ ] })
727
+ ] }) }),
728
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Footer, { children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, width: "100%", children: [
729
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { flex: "auto", variant: "tertiary", onClick: onClose, children: formatMessage({
730
+ id: getTranslation("CMEditViewCopyLocale.cancel-text"),
731
+ defaultMessage: "No, cancel"
732
+ }) }),
733
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { flex: "auto", variant: "success", onClick: fillFromLocale(onClose), children: formatMessage({
734
+ id: getTranslation("CMEditViewCopyLocale.submit-text"),
735
+ defaultMessage: "Yes, fill in"
736
+ }) })
737
+ ] }) })
738
+ ] })
739
+ }
740
+ };
741
+ };
489
742
  const DeleteLocaleAction = ({
490
743
  document,
491
744
  documentId,
@@ -497,16 +750,23 @@ const DeleteLocaleAction = ({
497
750
  const { toggleNotification } = strapiAdmin.useNotification();
498
751
  const { delete: deleteAction } = strapiAdmin$1.unstable_useDocumentActions();
499
752
  const { hasI18n, canDelete } = useI18n();
753
+ const [{ query: query2 }] = strapiAdmin.useQueryParams();
754
+ const { data: locales = [] } = useGetLocalesQuery();
755
+ const currentDesiredLocale = query2.plugins?.i18n?.locale;
756
+ const locale = !("error" in locales) && locales.find((loc) => loc.code === currentDesiredLocale);
500
757
  if (!hasI18n) {
501
758
  return null;
502
759
  }
503
760
  return {
504
761
  disabled: document?.locale && !canDelete.includes(document.locale) || !document || !document.id,
505
762
  position: ["header", "table-row"],
506
- label: formatMessage({
507
- id: getTranslation("actions.delete.label"),
508
- defaultMessage: "Delete locale"
509
- }),
763
+ label: formatMessage(
764
+ {
765
+ id: getTranslation("actions.delete.label"),
766
+ defaultMessage: "Delete entry ({locale})"
767
+ },
768
+ { locale: locale && locale.name }
769
+ ),
510
770
  icon: /* @__PURE__ */ jsxRuntime.jsx(StyledTrash, {}),
511
771
  variant: "danger",
512
772
  dialog: {
@@ -523,7 +783,12 @@ const DeleteLocaleAction = ({
523
783
  }) })
524
784
  ] }),
525
785
  onConfirm: async () => {
526
- if (!documentId || !document?.locale) {
786
+ const unableToDelete = (
787
+ // We are unable to delete a collection type without a document ID
788
+ // & unable to delete generally if there is no document locale
789
+ collectionType !== "single-types" && !documentId || !document?.locale
790
+ );
791
+ if (unableToDelete) {
527
792
  console.error(
528
793
  "You're trying to delete a document without an id or locale, this is likely a bug with Strapi. Please open an issue."
529
794
  );
@@ -549,23 +814,24 @@ const DeleteLocaleAction = ({
549
814
  }
550
815
  };
551
816
  };
552
- const BulkLocalePublishAction = ({
817
+ const BulkLocaleAction = ({
553
818
  document: baseDocument,
554
819
  documentId,
555
820
  model,
556
- collectionType
821
+ collectionType,
822
+ action
557
823
  }) => {
558
824
  const baseLocale = baseDocument?.locale ?? null;
559
825
  const [{ query: query$1 }] = strapiAdmin.useQueryParams();
560
826
  const params = React__namespace.useMemo(() => strapiAdmin$1.buildValidParams(query$1), [query$1]);
561
- const isPublishedTab = query$1.status === "published";
827
+ const isOnPublishedTab = query$1.status === "published";
562
828
  const { formatMessage } = reactIntl.useIntl();
563
829
  const { hasI18n, canPublish } = useI18n();
564
830
  const { toggleNotification } = strapiAdmin.useNotification();
565
831
  const { _unstableFormatAPIError: formatAPIError } = strapiAdmin.useAPIErrorHandler();
566
832
  const [selectedRows, setSelectedRows] = React__namespace.useState([]);
567
833
  const [isDraftRelationConfirmationOpen, setIsDraftRelationConfirmationOpen] = React__namespace.useState(false);
568
- const { publishMany: publishManyAction } = strapiAdmin$1.unstable_useDocumentActions();
834
+ const { publishMany: publishManyAction, unpublishMany: unpublishManyAction } = strapiAdmin$1.unstable_useDocumentActions();
569
835
  const {
570
836
  document,
571
837
  meta: documentMeta,
@@ -581,7 +847,7 @@ const BulkLocalePublishAction = ({
581
847
  }
582
848
  },
583
849
  {
584
- skip: !hasI18n
850
+ skip: !hasI18n || !baseLocale
585
851
  }
586
852
  );
587
853
  const { data: localesMetadata = [] } = useGetLocalesQuery(hasI18n ? void 0 : query.skipToken);
@@ -633,12 +899,19 @@ const BulkLocalePublishAction = ({
633
899
  }, {});
634
900
  return [rowsFromMeta, errors];
635
901
  }, [document, documentMeta?.availableLocales, validate]);
636
- const localesToPublish = selectedRows.reduce((acc, selectedRow) => {
637
- if (selectedRow.status !== "published" && !Object.keys(validationErrors).includes(selectedRow.locale)) {
902
+ const isBulkPublish = action === "bulk-publish";
903
+ const localesForAction = selectedRows.reduce((acc, selectedRow) => {
904
+ const isValidLocale = (
905
+ // Validation errors are irrelevant if we are trying to unpublish
906
+ !isBulkPublish || !Object.keys(validationErrors).includes(selectedRow.locale)
907
+ );
908
+ const shouldAddLocale = isBulkPublish ? selectedRow.status !== "published" && isValidLocale : selectedRow.status !== "draft" && isValidLocale;
909
+ if (shouldAddLocale) {
638
910
  acc.push(selectedRow.locale);
639
911
  }
640
912
  return acc;
641
913
  }, []);
914
+ const enableDraftRelationsCount = false;
642
915
  const {
643
916
  data: draftRelationsCount = 0,
644
917
  isLoading: isDraftRelationsLoading,
@@ -647,10 +920,10 @@ const BulkLocalePublishAction = ({
647
920
  {
648
921
  model,
649
922
  documentIds: [documentId],
650
- locale: localesToPublish
923
+ locale: localesForAction
651
924
  },
652
925
  {
653
- skip: !documentId || localesToPublish.length === 0
926
+ skip: !enableDraftRelationsCount
654
927
  }
655
928
  );
656
929
  React__namespace.useEffect(() => {
@@ -676,7 +949,18 @@ const BulkLocalePublishAction = ({
676
949
  documentIds: [documentId],
677
950
  params: {
678
951
  ...params,
679
- locale: localesToPublish
952
+ locale: localesForAction
953
+ }
954
+ });
955
+ setSelectedRows([]);
956
+ };
957
+ const unpublish = async () => {
958
+ await unpublishManyAction({
959
+ model,
960
+ documentIds: [documentId],
961
+ params: {
962
+ ...params,
963
+ locale: localesForAction
680
964
  }
681
965
  });
682
966
  setSelectedRows([]);
@@ -684,14 +968,12 @@ const BulkLocalePublishAction = ({
684
968
  const handleAction = async () => {
685
969
  if (draftRelationsCount > 0) {
686
970
  setIsDraftRelationConfirmationOpen(true);
687
- } else {
971
+ } else if (isBulkPublish) {
688
972
  await publish();
973
+ } else {
974
+ await unpublish();
689
975
  }
690
976
  };
691
- const isUnpublish = document?.status === "published";
692
- if (isUnpublish) {
693
- console.warn(["I18N"], "Bulk locale unpublish modal not implemented");
694
- }
695
977
  if (isDraftRelationConfirmationOpen) {
696
978
  return {
697
979
  label: formatMessage({
@@ -729,18 +1011,18 @@ const BulkLocalePublishAction = ({
729
1011
  const hasPermission = selectedRows.map(({ locale }) => locale).every((locale) => canPublish.includes(locale));
730
1012
  return {
731
1013
  label: formatMessage({
732
- id: getTranslation("CMEditViewBulkLocale.publish-title"),
733
- defaultMessage: "Publish Multiple Locales"
1014
+ id: getTranslation(`CMEditViewBulkLocale.${isBulkPublish ? "publish" : "unpublish"}-title`),
1015
+ defaultMessage: `${isBulkPublish ? "Publish" : "Unpublish"} Multiple Locales`
734
1016
  }),
735
- icon: /* @__PURE__ */ jsxRuntime.jsx(icons.ListPlus, {}),
736
- disabled: isPublishedTab || canPublish.length === 0,
1017
+ variant: isBulkPublish ? "secondary" : "danger",
1018
+ icon: isBulkPublish ? /* @__PURE__ */ jsxRuntime.jsx(icons.ListPlus, {}) : /* @__PURE__ */ jsxRuntime.jsx(icons.Cross, {}),
1019
+ disabled: isOnPublishedTab || canPublish.length === 0,
737
1020
  position: ["panel"],
738
- variant: "secondary",
739
1021
  dialog: {
740
1022
  type: "modal",
741
1023
  title: formatMessage({
742
- id: getTranslation("CMEditViewBulkLocale.publish-title"),
743
- defaultMessage: "Publish Multiple Locales"
1024
+ id: getTranslation(`CMEditViewBulkLocale.${isBulkPublish ? "publish" : "unpublish"}-title`),
1025
+ defaultMessage: `${isBulkPublish ? "Publish" : "Unpublish"} Multiple Locales`
744
1026
  }),
745
1027
  content: () => {
746
1028
  return /* @__PURE__ */ jsxRuntime.jsx(
@@ -759,7 +1041,8 @@ const BulkLocalePublishAction = ({
759
1041
  validationErrors,
760
1042
  headers,
761
1043
  rows,
762
- localesMetadata
1044
+ localesMetadata,
1045
+ action: action ?? "bulk-publish"
763
1046
  }
764
1047
  )
765
1048
  }
@@ -769,18 +1052,24 @@ const BulkLocalePublishAction = ({
769
1052
  designSystem.Button,
770
1053
  {
771
1054
  loading: isDraftRelationsLoading,
772
- disabled: !hasPermission || localesToPublish.length === 0,
1055
+ disabled: !hasPermission || localesForAction.length === 0,
773
1056
  variant: "default",
774
1057
  onClick: handleAction,
775
1058
  children: formatMessage({
776
- id: "app.utils.publish",
777
- defaultMessage: "Publish"
1059
+ id: isBulkPublish ? "app.utils.publish" : "app.utils.unpublish",
1060
+ defaultMessage: isBulkPublish ? "Publish" : "Unpublish"
778
1061
  })
779
1062
  }
780
1063
  ) })
781
1064
  }
782
1065
  };
783
1066
  };
1067
+ const BulkLocalePublishAction = (props) => {
1068
+ return BulkLocaleAction({ action: "bulk-publish", ...props });
1069
+ };
1070
+ const BulkLocaleUnpublishAction = (props) => {
1071
+ return BulkLocaleAction({ action: "bulk-unpublish", ...props });
1072
+ };
784
1073
  const StyledTrash = styledComponents.styled(icons.Trash)`
785
1074
  path {
786
1075
  fill: currentColor;
@@ -1000,54 +1289,13 @@ const LocaleListCell = ({
1000
1289
  return locale.name;
1001
1290
  }).toSorted((a, b) => formatter.compare(a, b));
1002
1291
  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
- ) }) }),
1292
+ /* @__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: [
1293
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { textColor: "neutral800", ellipsis: true, marginRight: 2, children: localesForDocument.join(", ") }),
1294
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { children: /* @__PURE__ */ jsxRuntime.jsx(icons.CaretDown, { width: "1.2rem", height: "1.2rem" }) })
1295
+ ] }) }) }),
1017
1296
  /* @__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
1297
  ] });
1019
1298
  };
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
1299
  const addColumnToTableHook = ({ displayedHeaders, layout }) => {
1052
1300
  const { options } = layout;
1053
1301
  const isFieldLocalized = doesPluginOptionsHaveI18nLocalized(options) ? options.i18n.localized : false;
@@ -1173,9 +1421,6 @@ const localeMiddleware = (ctx) => (next) => (permissions) => {
1173
1421
  return next(revisedPermissions);
1174
1422
  };
1175
1423
  const prefixPluginTranslations = (trad, pluginId2) => {
1176
- if (!pluginId2) {
1177
- throw new TypeError("pluginId can't be empty");
1178
- }
1179
1424
  return Object.keys(trad).reduce((acc, current) => {
1180
1425
  acc[`${pluginId2}.${current}`] = trad[current];
1181
1426
  return acc;
@@ -1245,11 +1490,11 @@ const index = {
1245
1490
  },
1246
1491
  id: "internationalization",
1247
1492
  to: "internationalization",
1248
- Component: () => Promise.resolve().then(() => require("./SettingsPage-DA9haizZ.js")).then((mod) => ({ default: mod.ProtectedSettingsPage })),
1493
+ Component: () => Promise.resolve().then(() => require("./SettingsPage-D0hqaut-.js")).then((mod) => ({ default: mod.ProtectedSettingsPage })),
1249
1494
  permissions: PERMISSIONS.accessMain
1250
1495
  });
1251
1496
  const contentManager = app.getPlugin("content-manager");
1252
- contentManager.apis.addDocumentHeaderAction([LocalePickerAction]);
1497
+ contentManager.apis.addDocumentHeaderAction([LocalePickerAction, FillFromAnotherLocaleAction]);
1253
1498
  contentManager.apis.addDocumentAction((actions) => {
1254
1499
  const indexOfDeleteAction = actions.findIndex((action) => action.type === "delete");
1255
1500
  actions.splice(indexOfDeleteAction, 0, DeleteLocaleAction);
@@ -1257,6 +1502,7 @@ const index = {
1257
1502
  });
1258
1503
  contentManager.apis.addDocumentAction((actions) => {
1259
1504
  actions.splice(2, 0, BulkLocalePublishAction);
1505
+ actions.splice(5, 0, BulkLocaleUnpublishAction);
1260
1506
  return actions;
1261
1507
  });
1262
1508
  contentManager.injectComponent("listView", "actions", {
@@ -1362,7 +1608,7 @@ const index = {
1362
1608
  async registerTrads({ locales }) {
1363
1609
  const importedTrads = await Promise.all(
1364
1610
  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 }) => {
1611
+ 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-BKBz3tro.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
1612
  return {
1367
1613
  data: prefixPluginTranslations(data, pluginId),
1368
1614
  locale
@@ -1386,4 +1632,4 @@ exports.useDeleteLocaleMutation = useDeleteLocaleMutation;
1386
1632
  exports.useGetDefaultLocalesQuery = useGetDefaultLocalesQuery;
1387
1633
  exports.useGetLocalesQuery = useGetLocalesQuery;
1388
1634
  exports.useUpdateLocaleMutation = useUpdateLocaleMutation;
1389
- //# sourceMappingURL=index-DIzVXZoE.js.map
1635
+ //# sourceMappingURL=index-46DNtLCn.js.map