@strapi/i18n 0.0.0-experimental.bd712ad3930045f4a5d2144c119e0b7856e97fc4 → 0.0.0-experimental.bec5a58066c034a7ebf5b14df62560e68a456fa3

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 (52) hide show
  1. package/dist/_chunks/{SettingsPage-CwD3sWFS.js → SettingsPage-JyA1zd8f.js} +8 -8
  2. package/dist/_chunks/SettingsPage-JyA1zd8f.js.map +1 -0
  3. package/dist/_chunks/{SettingsPage-D7g35okk.mjs → SettingsPage-giNp3Ftr.mjs} +8 -8
  4. package/dist/_chunks/SettingsPage-giNp3Ftr.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-1KQC6aOV.mjs → index-Bt5ork2g.mjs} +400 -151
  10. package/dist/_chunks/index-Bt5ork2g.mjs.map +1 -0
  11. package/dist/_chunks/{index-5_LTJ7xw.js → index-BwAeKsym.js} +393 -144
  12. package/dist/_chunks/index-BwAeKsym.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/admin/src/utils/schemas.d.ts +1 -0
  20. package/dist/server/index.js +413 -480
  21. package/dist/server/index.js.map +1 -1
  22. package/dist/server/index.mjs +415 -482
  23. package/dist/server/index.mjs.map +1 -1
  24. package/dist/server/src/bootstrap.d.ts +1 -4
  25. package/dist/server/src/bootstrap.d.ts.map +1 -1
  26. package/dist/server/src/index.d.ts +21 -13
  27. package/dist/server/src/index.d.ts.map +1 -1
  28. package/dist/server/src/register.d.ts.map +1 -1
  29. package/dist/server/src/services/index.d.ts +20 -10
  30. package/dist/server/src/services/index.d.ts.map +1 -1
  31. package/dist/server/src/services/permissions/actions.d.ts +14 -2
  32. package/dist/server/src/services/permissions/actions.d.ts.map +1 -1
  33. package/dist/server/src/services/permissions.d.ts +14 -2
  34. package/dist/server/src/services/permissions.d.ts.map +1 -1
  35. package/dist/server/src/services/sanitize/index.d.ts +11 -0
  36. package/dist/server/src/services/sanitize/index.d.ts.map +1 -0
  37. package/dist/server/src/utils/index.d.ts +2 -2
  38. package/dist/server/src/utils/index.d.ts.map +1 -1
  39. package/package.json +12 -12
  40. package/dist/_chunks/SettingsPage-CwD3sWFS.js.map +0 -1
  41. package/dist/_chunks/SettingsPage-D7g35okk.mjs.map +0 -1
  42. package/dist/_chunks/en-BsOU9o5z.js.map +0 -1
  43. package/dist/_chunks/en-CM6Pjfyv.mjs.map +0 -1
  44. package/dist/_chunks/index-1KQC6aOV.mjs.map +0 -1
  45. package/dist/_chunks/index-5_LTJ7xw.js.map +0 -1
  46. package/dist/server/src/migrations/content-type/disable/index.d.ts +0 -3
  47. package/dist/server/src/migrations/content-type/disable/index.d.ts.map +0 -1
  48. package/dist/server/src/migrations/content-type/enable/index.d.ts +0 -3
  49. package/dist/server/src/migrations/content-type/enable/index.d.ts.map +0 -1
  50. package/dist/server/src/services/entity-service-decorator.d.ts +0 -29
  51. package/dist/server/src/services/entity-service-decorator.d.ts.map +0 -1
  52. 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,27 +440,29 @@ 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
  );
344
464
  };
345
- return /* @__PURE__ */ jsxRuntime.jsxs(React__namespace.Fragment, { children: [
465
+ return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Modal.Body, { children: [
346
466
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { children: getFormattedCountMessage() }),
347
467
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { marginTop: 5, children: /* @__PURE__ */ jsxRuntime.jsxs(strapiAdmin.Table.Content, { children: [
348
468
  /* @__PURE__ */ jsxRuntime.jsxs(strapiAdmin.Table.Head, { children: [
@@ -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,50 @@ 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
+ }
607
+ const displayedLocales = locales.filter((locale) => {
608
+ return canRead.includes(locale.code);
609
+ });
442
610
  return {
443
611
  label: formatMessage({
444
612
  id: getTranslation("Settings.locales.modal.locales.label"),
445
613
  defaultMessage: "Locales"
446
614
  }),
447
- options: locales.map((locale) => {
615
+ options: displayedLocales.map((locale) => {
616
+ const entryWithLocaleExists = allCurrentLocales.some((doc) => doc.locale === locale.code);
448
617
  const currentLocaleDoc = allCurrentLocales.find(
449
618
  (doc) => "locale" in doc ? doc.locale === locale.code : false
450
619
  );
451
- const status = currentLocaleDoc?.status ?? "draft";
452
- const permissionsToCheck = currentLocaleDoc ? canCreate : canRead;
453
- const statusVariant = status === "draft" ? "primary" : status === "published" ? "success" : "alternative";
620
+ const permissionsToCheck = currentLocaleDoc ? canRead : canCreate;
454
621
  return {
455
622
  disabled: !permissionsToCheck.includes(locale.code),
456
623
  value: locale.code,
457
- label: locale.name,
458
- startIcon: schema?.options?.draftAndPublish ? /* @__PURE__ */ jsxRuntime.jsx(
459
- designSystem.Status,
624
+ label: /* @__PURE__ */ jsxRuntime.jsx(
625
+ LocaleOption,
460
626
  {
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) })
627
+ isDraftAndPublishEnabled: !!schema?.options?.draftAndPublish,
628
+ locale,
629
+ status: currentLocaleDoc?.status,
630
+ entryExists: entryWithLocaleExists
470
631
  }
471
- ) : null
632
+ ),
633
+ startIcon: !entryWithLocaleExists ? /* @__PURE__ */ jsxRuntime.jsx(icons.Plus, {}) : null
472
634
  };
473
635
  }),
636
+ customizeContent: () => currentLocale?.name,
474
637
  onSelect: handleSelect,
475
638
  value: currentLocale
476
639
  };
@@ -486,6 +649,99 @@ const getDocumentStatus = (document, meta) => {
486
649
  }
487
650
  return docStatus;
488
651
  };
652
+ const FillFromAnotherLocaleAction = ({
653
+ documentId,
654
+ meta,
655
+ model,
656
+ collectionType
657
+ }) => {
658
+ const { formatMessage } = reactIntl.useIntl();
659
+ const [{ query: query2 }] = strapiAdmin.useQueryParams();
660
+ const { hasI18n } = useI18n();
661
+ const currentDesiredLocale = query2.plugins?.i18n?.locale;
662
+ const [localeSelected, setLocaleSelected] = React__namespace.useState(null);
663
+ const setValues = strapiAdmin.useForm("FillFromAnotherLocale", (state) => state.setValues);
664
+ const { getDocument } = strapiAdmin$1.unstable_useDocumentActions();
665
+ const { schema, components } = strapiAdmin$1.unstable_useDocument({
666
+ model,
667
+ documentId,
668
+ collectionType,
669
+ params: { locale: currentDesiredLocale }
670
+ });
671
+ const { data: locales = [] } = useGetLocalesQuery();
672
+ const availableLocales = Array.isArray(locales) ? locales.filter((locale) => meta?.availableLocales.some((l) => l.locale === locale.code)) : [];
673
+ const fillFromLocale = (onClose) => async () => {
674
+ const response = await getDocument({
675
+ collectionType,
676
+ model,
677
+ documentId,
678
+ params: { locale: localeSelected }
679
+ });
680
+ if (!response || !schema) {
681
+ return;
682
+ }
683
+ const { data } = response;
684
+ const cleanedData = cleanData(data, schema, components);
685
+ setValues(cleanedData);
686
+ onClose();
687
+ };
688
+ if (!hasI18n) {
689
+ return null;
690
+ }
691
+ return {
692
+ type: "icon",
693
+ icon: /* @__PURE__ */ jsxRuntime.jsx(icons.Download, {}),
694
+ disabled: availableLocales.length === 0,
695
+ label: formatMessage({
696
+ id: getTranslation("CMEditViewCopyLocale.copy-text"),
697
+ defaultMessage: "Fill in from another locale"
698
+ }),
699
+ dialog: {
700
+ type: "dialog",
701
+ title: formatMessage({
702
+ id: getTranslation("CMEditViewCopyLocale.dialog.title"),
703
+ defaultMessage: "Confirmation"
704
+ }),
705
+ content: ({ onClose }) => /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
706
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Body, { children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", gap: 3, children: [
707
+ /* @__PURE__ */ jsxRuntime.jsx(icons.WarningCircle, { width: "24px", height: "24px", fill: "danger600" }),
708
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { textAlign: "center", children: formatMessage({
709
+ id: getTranslation("CMEditViewCopyLocale.dialog.body"),
710
+ defaultMessage: "Your current content will be erased and filled by the content of the selected locale:"
711
+ }) }),
712
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Field.Root, { width: "100%", children: [
713
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Label, { children: formatMessage({
714
+ id: getTranslation("CMEditViewCopyLocale.dialog.field.label"),
715
+ defaultMessage: "Locale"
716
+ }) }),
717
+ /* @__PURE__ */ jsxRuntime.jsx(
718
+ designSystem.SingleSelect,
719
+ {
720
+ value: localeSelected,
721
+ placeholder: formatMessage({
722
+ id: getTranslation("CMEditViewCopyLocale.dialog.field.placeholder"),
723
+ defaultMessage: "Select one locale..."
724
+ }),
725
+ onChange: (value) => setLocaleSelected(value),
726
+ children: availableLocales.map((locale) => /* @__PURE__ */ jsxRuntime.jsx(designSystem.SingleSelectOption, { value: locale.code, children: locale.name }, locale.code))
727
+ }
728
+ )
729
+ ] })
730
+ ] }) }),
731
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Footer, { children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, width: "100%", children: [
732
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { flex: "auto", variant: "tertiary", onClick: onClose, children: formatMessage({
733
+ id: getTranslation("CMEditViewCopyLocale.cancel-text"),
734
+ defaultMessage: "No, cancel"
735
+ }) }),
736
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { flex: "auto", variant: "success", onClick: fillFromLocale(onClose), children: formatMessage({
737
+ id: getTranslation("CMEditViewCopyLocale.submit-text"),
738
+ defaultMessage: "Yes, fill in"
739
+ }) })
740
+ ] }) })
741
+ ] })
742
+ }
743
+ };
744
+ };
489
745
  const DeleteLocaleAction = ({
490
746
  document,
491
747
  documentId,
@@ -497,16 +753,23 @@ const DeleteLocaleAction = ({
497
753
  const { toggleNotification } = strapiAdmin.useNotification();
498
754
  const { delete: deleteAction } = strapiAdmin$1.unstable_useDocumentActions();
499
755
  const { hasI18n, canDelete } = useI18n();
756
+ const [{ query: query2 }] = strapiAdmin.useQueryParams();
757
+ const { data: locales = [] } = useGetLocalesQuery();
758
+ const currentDesiredLocale = query2.plugins?.i18n?.locale;
759
+ const locale = !("error" in locales) && locales.find((loc) => loc.code === currentDesiredLocale);
500
760
  if (!hasI18n) {
501
761
  return null;
502
762
  }
503
763
  return {
504
764
  disabled: document?.locale && !canDelete.includes(document.locale) || !document || !document.id,
505
765
  position: ["header", "table-row"],
506
- label: formatMessage({
507
- id: getTranslation("actions.delete.label"),
508
- defaultMessage: "Delete locale"
509
- }),
766
+ label: formatMessage(
767
+ {
768
+ id: getTranslation("actions.delete.label"),
769
+ defaultMessage: "Delete entry ({locale})"
770
+ },
771
+ { locale: locale && locale.name }
772
+ ),
510
773
  icon: /* @__PURE__ */ jsxRuntime.jsx(StyledTrash, {}),
511
774
  variant: "danger",
512
775
  dialog: {
@@ -523,7 +786,12 @@ const DeleteLocaleAction = ({
523
786
  }) })
524
787
  ] }),
525
788
  onConfirm: async () => {
526
- if (!documentId || !document?.locale) {
789
+ const unableToDelete = (
790
+ // We are unable to delete a collection type without a document ID
791
+ // & unable to delete generally if there is no document locale
792
+ collectionType !== "single-types" && !documentId || !document?.locale
793
+ );
794
+ if (unableToDelete) {
527
795
  console.error(
528
796
  "You're trying to delete a document without an id or locale, this is likely a bug with Strapi. Please open an issue."
529
797
  );
@@ -549,23 +817,24 @@ const DeleteLocaleAction = ({
549
817
  }
550
818
  };
551
819
  };
552
- const BulkLocalePublishAction = ({
820
+ const BulkLocaleAction = ({
553
821
  document: baseDocument,
554
822
  documentId,
555
823
  model,
556
- collectionType
824
+ collectionType,
825
+ action
557
826
  }) => {
558
827
  const baseLocale = baseDocument?.locale ?? null;
559
828
  const [{ query: query$1 }] = strapiAdmin.useQueryParams();
560
829
  const params = React__namespace.useMemo(() => strapiAdmin$1.buildValidParams(query$1), [query$1]);
561
- const isPublishedTab = query$1.status === "published";
830
+ const isOnPublishedTab = query$1.status === "published";
562
831
  const { formatMessage } = reactIntl.useIntl();
563
832
  const { hasI18n, canPublish } = useI18n();
564
833
  const { toggleNotification } = strapiAdmin.useNotification();
565
834
  const { _unstableFormatAPIError: formatAPIError } = strapiAdmin.useAPIErrorHandler();
566
835
  const [selectedRows, setSelectedRows] = React__namespace.useState([]);
567
836
  const [isDraftRelationConfirmationOpen, setIsDraftRelationConfirmationOpen] = React__namespace.useState(false);
568
- const { publishMany: publishManyAction } = strapiAdmin$1.unstable_useDocumentActions();
837
+ const { publishMany: publishManyAction, unpublishMany: unpublishManyAction } = strapiAdmin$1.unstable_useDocumentActions();
569
838
  const {
570
839
  document,
571
840
  meta: documentMeta,
@@ -581,7 +850,7 @@ const BulkLocalePublishAction = ({
581
850
  }
582
851
  },
583
852
  {
584
- skip: !hasI18n
853
+ skip: !hasI18n || !baseLocale
585
854
  }
586
855
  );
587
856
  const { data: localesMetadata = [] } = useGetLocalesQuery(hasI18n ? void 0 : query.skipToken);
@@ -633,12 +902,19 @@ const BulkLocalePublishAction = ({
633
902
  }, {});
634
903
  return [rowsFromMeta, errors];
635
904
  }, [document, documentMeta?.availableLocales, validate]);
636
- const localesToPublish = selectedRows.reduce((acc, selectedRow) => {
637
- if (selectedRow.status !== "published" && !Object.keys(validationErrors).includes(selectedRow.locale)) {
905
+ const isBulkPublish = action === "bulk-publish";
906
+ const localesForAction = selectedRows.reduce((acc, selectedRow) => {
907
+ const isValidLocale = (
908
+ // Validation errors are irrelevant if we are trying to unpublish
909
+ !isBulkPublish || !Object.keys(validationErrors).includes(selectedRow.locale)
910
+ );
911
+ const shouldAddLocale = isBulkPublish ? selectedRow.status !== "published" && isValidLocale : selectedRow.status !== "draft" && isValidLocale;
912
+ if (shouldAddLocale) {
638
913
  acc.push(selectedRow.locale);
639
914
  }
640
915
  return acc;
641
916
  }, []);
917
+ const enableDraftRelationsCount = false;
642
918
  const {
643
919
  data: draftRelationsCount = 0,
644
920
  isLoading: isDraftRelationsLoading,
@@ -647,10 +923,10 @@ const BulkLocalePublishAction = ({
647
923
  {
648
924
  model,
649
925
  documentIds: [documentId],
650
- locale: localesToPublish
926
+ locale: localesForAction
651
927
  },
652
928
  {
653
- skip: !documentId || localesToPublish.length === 0
929
+ skip: !enableDraftRelationsCount
654
930
  }
655
931
  );
656
932
  React__namespace.useEffect(() => {
@@ -676,7 +952,18 @@ const BulkLocalePublishAction = ({
676
952
  documentIds: [documentId],
677
953
  params: {
678
954
  ...params,
679
- locale: localesToPublish
955
+ locale: localesForAction
956
+ }
957
+ });
958
+ setSelectedRows([]);
959
+ };
960
+ const unpublish = async () => {
961
+ await unpublishManyAction({
962
+ model,
963
+ documentIds: [documentId],
964
+ params: {
965
+ ...params,
966
+ locale: localesForAction
680
967
  }
681
968
  });
682
969
  setSelectedRows([]);
@@ -684,14 +971,12 @@ const BulkLocalePublishAction = ({
684
971
  const handleAction = async () => {
685
972
  if (draftRelationsCount > 0) {
686
973
  setIsDraftRelationConfirmationOpen(true);
687
- } else {
974
+ } else if (isBulkPublish) {
688
975
  await publish();
976
+ } else {
977
+ await unpublish();
689
978
  }
690
979
  };
691
- const isUnpublish = document?.status === "published";
692
- if (isUnpublish) {
693
- console.warn(["I18N"], "Bulk locale unpublish modal not implemented");
694
- }
695
980
  if (isDraftRelationConfirmationOpen) {
696
981
  return {
697
982
  label: formatMessage({
@@ -729,18 +1014,18 @@ const BulkLocalePublishAction = ({
729
1014
  const hasPermission = selectedRows.map(({ locale }) => locale).every((locale) => canPublish.includes(locale));
730
1015
  return {
731
1016
  label: formatMessage({
732
- id: getTranslation("CMEditViewBulkLocale.publish-title"),
733
- defaultMessage: "Publish Multiple Locales"
1017
+ id: getTranslation(`CMEditViewBulkLocale.${isBulkPublish ? "publish" : "unpublish"}-title`),
1018
+ defaultMessage: `${isBulkPublish ? "Publish" : "Unpublish"} Multiple Locales`
734
1019
  }),
735
- icon: /* @__PURE__ */ jsxRuntime.jsx(icons.ListPlus, {}),
736
- disabled: isPublishedTab || canPublish.length === 0,
1020
+ variant: isBulkPublish ? "secondary" : "danger",
1021
+ icon: isBulkPublish ? /* @__PURE__ */ jsxRuntime.jsx(icons.ListPlus, {}) : /* @__PURE__ */ jsxRuntime.jsx(icons.Cross, {}),
1022
+ disabled: isOnPublishedTab || canPublish.length === 0,
737
1023
  position: ["panel"],
738
- variant: "secondary",
739
1024
  dialog: {
740
1025
  type: "modal",
741
1026
  title: formatMessage({
742
- id: getTranslation("CMEditViewBulkLocale.publish-title"),
743
- defaultMessage: "Publish Multiple Locales"
1027
+ id: getTranslation(`CMEditViewBulkLocale.${isBulkPublish ? "publish" : "unpublish"}-title`),
1028
+ defaultMessage: `${isBulkPublish ? "Publish" : "Unpublish"} Multiple Locales`
744
1029
  }),
745
1030
  content: () => {
746
1031
  return /* @__PURE__ */ jsxRuntime.jsx(
@@ -759,28 +1044,35 @@ const BulkLocalePublishAction = ({
759
1044
  validationErrors,
760
1045
  headers,
761
1046
  rows,
762
- localesMetadata
1047
+ localesMetadata,
1048
+ action: action ?? "bulk-publish"
763
1049
  }
764
1050
  )
765
1051
  }
766
1052
  );
767
1053
  },
768
- footer: () => /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { justifyContent: "flex-end", width: "100%", children: /* @__PURE__ */ jsxRuntime.jsx(
1054
+ footer: () => /* @__PURE__ */ jsxRuntime.jsx(designSystem.Modal.Footer, { justifyContent: "flex-end", children: /* @__PURE__ */ jsxRuntime.jsx(
769
1055
  designSystem.Button,
770
1056
  {
771
1057
  loading: isDraftRelationsLoading,
772
- disabled: !hasPermission || localesToPublish.length === 0,
1058
+ disabled: !hasPermission || localesForAction.length === 0,
773
1059
  variant: "default",
774
1060
  onClick: handleAction,
775
1061
  children: formatMessage({
776
- id: "app.utils.publish",
777
- defaultMessage: "Publish"
1062
+ id: isBulkPublish ? "app.utils.publish" : "app.utils.unpublish",
1063
+ defaultMessage: isBulkPublish ? "Publish" : "Unpublish"
778
1064
  })
779
1065
  }
780
1066
  ) })
781
1067
  }
782
1068
  };
783
1069
  };
1070
+ const BulkLocalePublishAction = (props) => {
1071
+ return BulkLocaleAction({ action: "bulk-publish", ...props });
1072
+ };
1073
+ const BulkLocaleUnpublishAction = (props) => {
1074
+ return BulkLocaleAction({ action: "bulk-unpublish", ...props });
1075
+ };
784
1076
  const StyledTrash = styledComponents.styled(icons.Trash)`
785
1077
  path {
786
1078
  fill: currentColor;
@@ -1000,54 +1292,13 @@ const LocaleListCell = ({
1000
1292
  return locale.name;
1001
1293
  }).toSorted((a, b) => formatter.compare(a, b));
1002
1294
  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
- ) }) }),
1295
+ /* @__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: [
1296
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { textColor: "neutral800", ellipsis: true, marginRight: 2, children: localesForDocument.join(", ") }),
1297
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { children: /* @__PURE__ */ jsxRuntime.jsx(icons.CaretDown, { width: "1.2rem", height: "1.2rem" }) })
1298
+ ] }) }) }),
1017
1299
  /* @__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
1300
  ] });
1019
1301
  };
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
1302
  const addColumnToTableHook = ({ displayedHeaders, layout }) => {
1052
1303
  const { options } = layout;
1053
1304
  const isFieldLocalized = doesPluginOptionsHaveI18nLocalized(options) ? options.i18n.localized : false;
@@ -1173,9 +1424,6 @@ const localeMiddleware = (ctx) => (next) => (permissions) => {
1173
1424
  return next(revisedPermissions);
1174
1425
  };
1175
1426
  const prefixPluginTranslations = (trad, pluginId2) => {
1176
- if (!pluginId2) {
1177
- throw new TypeError("pluginId can't be empty");
1178
- }
1179
1427
  return Object.keys(trad).reduce((acc, current) => {
1180
1428
  acc[`${pluginId2}.${current}`] = trad[current];
1181
1429
  return acc;
@@ -1245,11 +1493,11 @@ const index = {
1245
1493
  },
1246
1494
  id: "internationalization",
1247
1495
  to: "internationalization",
1248
- Component: () => Promise.resolve().then(() => require("./SettingsPage-CwD3sWFS.js")).then((mod) => ({ default: mod.ProtectedSettingsPage })),
1496
+ Component: () => Promise.resolve().then(() => require("./SettingsPage-JyA1zd8f.js")).then((mod) => ({ default: mod.ProtectedSettingsPage })),
1249
1497
  permissions: PERMISSIONS.accessMain
1250
1498
  });
1251
1499
  const contentManager = app.getPlugin("content-manager");
1252
- contentManager.apis.addDocumentHeaderAction([LocalePickerAction]);
1500
+ contentManager.apis.addDocumentHeaderAction([LocalePickerAction, FillFromAnotherLocaleAction]);
1253
1501
  contentManager.apis.addDocumentAction((actions) => {
1254
1502
  const indexOfDeleteAction = actions.findIndex((action) => action.type === "delete");
1255
1503
  actions.splice(indexOfDeleteAction, 0, DeleteLocaleAction);
@@ -1257,6 +1505,7 @@ const index = {
1257
1505
  });
1258
1506
  contentManager.apis.addDocumentAction((actions) => {
1259
1507
  actions.splice(2, 0, BulkLocalePublishAction);
1508
+ actions.splice(5, 0, BulkLocaleUnpublishAction);
1260
1509
  return actions;
1261
1510
  });
1262
1511
  contentManager.injectComponent("listView", "actions", {
@@ -1362,7 +1611,7 @@ const index = {
1362
1611
  async registerTrads({ locales }) {
1363
1612
  const importedTrads = await Promise.all(
1364
1613
  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 }) => {
1614
+ 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
1615
  return {
1367
1616
  data: prefixPluginTranslations(data, pluginId),
1368
1617
  locale
@@ -1386,4 +1635,4 @@ exports.useDeleteLocaleMutation = useDeleteLocaleMutation;
1386
1635
  exports.useGetDefaultLocalesQuery = useGetDefaultLocalesQuery;
1387
1636
  exports.useGetLocalesQuery = useGetLocalesQuery;
1388
1637
  exports.useUpdateLocaleMutation = useUpdateLocaleMutation;
1389
- //# sourceMappingURL=index-5_LTJ7xw.js.map
1638
+ //# sourceMappingURL=index-BwAeKsym.js.map