@strapi/i18n 5.0.0-rc.9 → 5.0.1

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