@strapi/i18n 0.0.0-experimental.826f263c58b6886b849d3f03b81f7a530bc51c91 → 0.0.0-experimental.8c83c87960f2f5ddf95ae2f0acf849052f4a9ab4

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 (56) hide show
  1. package/LICENSE +18 -3
  2. package/dist/_chunks/{SettingsPage-0FFSTUW2.mjs → SettingsPage-BAx9nmep.mjs} +95 -108
  3. package/dist/_chunks/SettingsPage-BAx9nmep.mjs.map +1 -0
  4. package/dist/_chunks/{SettingsPage-DnLLGeBa.js → SettingsPage-BTgjb2KS.js} +94 -108
  5. package/dist/_chunks/SettingsPage-BTgjb2KS.js.map +1 -0
  6. package/dist/_chunks/{en-Kv6y9zPQ.js → en-BKBz3tro.js} +12 -3
  7. package/dist/_chunks/en-BKBz3tro.js.map +1 -0
  8. package/dist/_chunks/{en-18tWw4P6.mjs → en-DlXfy6Gy.mjs} +12 -3
  9. package/dist/_chunks/en-DlXfy6Gy.mjs.map +1 -0
  10. package/dist/_chunks/{index-DtEKsPcR.js → index-3yyF237r.js} +468 -234
  11. package/dist/_chunks/index-3yyF237r.js.map +1 -0
  12. package/dist/_chunks/{index-BddUXwss.mjs → index-B0NijiBB.mjs} +461 -226
  13. package/dist/_chunks/index-B0NijiBB.mjs.map +1 -0
  14. package/dist/admin/index.js +1 -1
  15. package/dist/admin/index.mjs +1 -1
  16. package/dist/admin/src/components/BulkLocaleActionModal.d.ts +2 -1
  17. package/dist/admin/src/components/CMHeaderActions.d.ts +29 -3
  18. package/dist/admin/src/components/CreateLocale.d.ts +6 -6
  19. package/dist/admin/src/components/EditLocale.d.ts +5 -4
  20. package/dist/admin/src/contentReleasesHooks/releaseDetailsView.d.ts +9 -5
  21. package/dist/admin/src/utils/clean.d.ts +4 -0
  22. package/dist/admin/src/utils/schemas.d.ts +1 -0
  23. package/dist/server/index.js +414 -482
  24. package/dist/server/index.js.map +1 -1
  25. package/dist/server/index.mjs +415 -482
  26. package/dist/server/index.mjs.map +1 -1
  27. package/dist/server/src/bootstrap.d.ts +1 -4
  28. package/dist/server/src/bootstrap.d.ts.map +1 -1
  29. package/dist/server/src/index.d.ts +21 -13
  30. package/dist/server/src/index.d.ts.map +1 -1
  31. package/dist/server/src/register.d.ts.map +1 -1
  32. package/dist/server/src/services/index.d.ts +20 -10
  33. package/dist/server/src/services/index.d.ts.map +1 -1
  34. package/dist/server/src/services/permissions/actions.d.ts +14 -2
  35. package/dist/server/src/services/permissions/actions.d.ts.map +1 -1
  36. package/dist/server/src/services/permissions.d.ts +14 -2
  37. package/dist/server/src/services/permissions.d.ts.map +1 -1
  38. package/dist/server/src/services/sanitize/index.d.ts +11 -0
  39. package/dist/server/src/services/sanitize/index.d.ts.map +1 -0
  40. package/dist/server/src/utils/index.d.ts +2 -2
  41. package/dist/server/src/utils/index.d.ts.map +1 -1
  42. package/package.json +13 -13
  43. package/dist/_chunks/SettingsPage-0FFSTUW2.mjs.map +0 -1
  44. package/dist/_chunks/SettingsPage-DnLLGeBa.js.map +0 -1
  45. package/dist/_chunks/en-18tWw4P6.mjs.map +0 -1
  46. package/dist/_chunks/en-Kv6y9zPQ.js.map +0 -1
  47. package/dist/_chunks/index-BddUXwss.mjs.map +0 -1
  48. package/dist/_chunks/index-DtEKsPcR.js.map +0 -1
  49. package/dist/admin/src/components/Initializer.d.ts +0 -5
  50. package/dist/server/src/migrations/content-type/disable/index.d.ts +0 -3
  51. package/dist/server/src/migrations/content-type/disable/index.d.ts.map +0 -1
  52. package/dist/server/src/migrations/content-type/enable/index.d.ts +0 -3
  53. package/dist/server/src/migrations/content-type/enable/index.d.ts.map +0 -1
  54. package/dist/server/src/services/entity-service-decorator.d.ts +0 -29
  55. package/dist/server/src/services/entity-service-decorator.d.ts.map +0 -1
  56. package/strapi-server.js +0 -3
@@ -1,24 +1,32 @@
1
1
  import get from "lodash/get";
2
2
  import * as yup from "yup";
3
- import { jsxs, Fragment, jsx } from "react/jsx-runtime";
3
+ import { jsxs, jsx, Fragment } from "react/jsx-runtime";
4
4
  import * as React from "react";
5
- import { Typography, Field, Checkbox, Dialog, DialogBody, Flex, DialogFooter, Button as Button$1, Box, Status, IconButton, Tooltip, SingleSelect, SingleSelectOption, VisuallyHidden, useCollator, Popover } from "@strapi/design-system";
6
- import { WarningCircle, Pencil, CrossCircle, CheckCircle, ArrowsCounterClockwise, Trash, ListPlus, Earth, EarthStriked, CaretDown } from "@strapi/icons";
5
+ import { Typography, Dialog, Field, Checkbox, Flex, Button, Modal, Box, Status, IconButton, Tooltip, SingleSelect, SingleSelectOption, VisuallyHidden, useCollator, Popover } from "@strapi/design-system";
6
+ import { WarningCircle, Pencil, CrossCircle, CheckCircle, ArrowsCounterClockwise, Trash, Plus, Download, ListPlus, Cross, Earth, EarthStriked, CaretDown } from "@strapi/icons";
7
7
  import { useIntl } from "react-intl";
8
8
  import { styled } from "styled-components";
9
- import { useAuth, adminApi, useTable, Table, useQueryParams, useNotification, useAPIErrorHandler } from "@strapi/admin/strapi-admin";
9
+ import { skipToken } from "@reduxjs/toolkit/query";
10
+ import { useAuth, adminApi, useTable, Table, useQueryParams, useForm, useNotification, useAPIErrorHandler } from "@strapi/admin/strapi-admin";
10
11
  import { unstable_useDocument, unstable_useDocumentActions, buildValidParams } from "@strapi/content-manager/strapi-admin";
11
12
  import { useParams, Link, useNavigate, matchPath } from "react-router-dom";
12
13
  import * as qs from "qs";
13
14
  import { stringify } from "qs";
14
15
  import omit from "lodash/omit";
15
- const __variableDynamicImportRuntimeHelper = (glob, path) => {
16
+ const __variableDynamicImportRuntimeHelper = (glob, path, segs) => {
16
17
  const v = glob[path];
17
18
  if (v) {
18
19
  return typeof v === "function" ? v() : Promise.resolve(v);
19
20
  }
20
21
  return new Promise((_, reject) => {
21
- (typeof queueMicrotask === "function" ? queueMicrotask : setTimeout)(reject.bind(null, new Error("Unknown variable dynamic import: " + path)));
22
+ (typeof queueMicrotask === "function" ? queueMicrotask : setTimeout)(
23
+ reject.bind(
24
+ null,
25
+ new Error(
26
+ "Unknown variable dynamic import: " + path + (path.split("/").length !== segs ? ". Note that variables only represent file names one level deep." : "")
27
+ )
28
+ )
29
+ );
22
30
  });
23
31
  };
24
32
  const pluginId = "i18n";
@@ -47,9 +55,7 @@ const CheckboxConfirmation = ({
47
55
  };
48
56
  const handleConfirm = () => {
49
57
  onChange({ target: { name, value: false, type: "checkbox" } });
50
- setIsOpen(false);
51
58
  };
52
- const handleToggle = () => setIsOpen((prev) => !prev);
53
59
  const label = intlLabel.id ? formatMessage(
54
60
  { id: intlLabel.id, defaultMessage: intlLabel.defaultMessage },
55
61
  { ...intlLabel.values }
@@ -58,35 +64,36 @@ const CheckboxConfirmation = ({
58
64
  { id: description.id, defaultMessage: description.defaultMessage },
59
65
  { ...description.values }
60
66
  ) : "";
61
- return /* @__PURE__ */ jsxs(Fragment, { children: [
67
+ return /* @__PURE__ */ jsxs(Dialog.Root, { open: isOpen, onOpenChange: setIsOpen, children: [
62
68
  /* @__PURE__ */ jsxs(Field.Root, { hint, name, children: [
63
- /* @__PURE__ */ jsx(Checkbox, { onValueChange: handleChange, value, type: "checkbox", children: label }),
69
+ /* @__PURE__ */ jsx(Checkbox, { onCheckedChange: handleChange, checked: value, children: label }),
64
70
  /* @__PURE__ */ jsx(Field.Hint, {})
65
71
  ] }),
66
- isOpen && /* @__PURE__ */ jsxs(Dialog, { onClose: handleToggle, title: "Confirmation", isOpen, children: [
67
- /* @__PURE__ */ jsx(DialogBody, { icon: /* @__PURE__ */ jsx(WarningCircle, {}), children: /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "stretch", gap: 2, children: [
68
- /* @__PURE__ */ jsx(Flex, { justifyContent: "center", children: /* @__PURE__ */ jsx(TextAlignTypography, { id: "confirm-description", children: formatMessage({
72
+ /* @__PURE__ */ jsxs(Dialog.Content, { children: [
73
+ /* @__PURE__ */ jsx(Dialog.Header, { children: formatMessage({
74
+ id: getTranslation("CheckboxConfirmation.Modal.title"),
75
+ defaultMessage: "Disable localization"
76
+ }) }),
77
+ /* @__PURE__ */ jsx(Dialog.Body, { icon: /* @__PURE__ */ jsx(WarningCircle, {}), children: /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "stretch", gap: 2, children: [
78
+ /* @__PURE__ */ jsx(Flex, { justifyContent: "center", children: /* @__PURE__ */ jsx(TextAlignTypography, { children: formatMessage({
69
79
  id: getTranslation("CheckboxConfirmation.Modal.content"),
70
80
  defaultMessage: "Disabling localization will engender the deletion of all your content but the one associated to your default locale (if existing)."
71
81
  }) }) }),
72
- /* @__PURE__ */ jsx(Flex, { justifyContent: "center", children: /* @__PURE__ */ jsx(Typography, { fontWeight: "semiBold", id: "confirm-description", children: formatMessage({
82
+ /* @__PURE__ */ jsx(Flex, { justifyContent: "center", children: /* @__PURE__ */ jsx(Typography, { fontWeight: "semiBold", children: formatMessage({
73
83
  id: getTranslation("CheckboxConfirmation.Modal.body"),
74
84
  defaultMessage: "Do you want to disable it?"
75
85
  }) }) })
76
86
  ] }) }),
77
- /* @__PURE__ */ jsx(
78
- DialogFooter,
79
- {
80
- startAction: /* @__PURE__ */ jsx(Button$1, { onClick: handleToggle, variant: "tertiary", children: formatMessage({
81
- id: "components.popUpWarning.button.cancel",
82
- defaultMessage: "No, cancel"
83
- }) }),
84
- endAction: /* @__PURE__ */ jsx(Button$1, { variant: "danger-light", onClick: handleConfirm, children: formatMessage({
85
- id: getTranslation("CheckboxConfirmation.Modal.button-confirm"),
86
- defaultMessage: "Yes, disable"
87
- }) })
88
- }
89
- )
87
+ /* @__PURE__ */ jsxs(Dialog.Footer, { children: [
88
+ /* @__PURE__ */ jsx(Dialog.Cancel, { children: /* @__PURE__ */ jsx(Button, { variant: "tertiary", children: formatMessage({
89
+ id: "components.popUpWarning.button.cancel",
90
+ defaultMessage: "No, cancel"
91
+ }) }) }),
92
+ /* @__PURE__ */ jsx(Dialog.Action, { children: /* @__PURE__ */ jsx(Button, { variant: "danger-light", onClick: handleConfirm, children: formatMessage({
93
+ id: getTranslation("CheckboxConfirmation.Modal.button-confirm"),
94
+ defaultMessage: "Yes, disable"
95
+ }) }) })
96
+ ] })
90
97
  ] })
91
98
  ] });
92
99
  };
@@ -137,7 +144,7 @@ const useI18n = () => {
137
144
  model: params.slug
138
145
  },
139
146
  {
140
- skip: !params.slug || !params.collectionType
147
+ skip: true
141
148
  }
142
149
  );
143
150
  if (doesPluginOptionsHaveI18nLocalized(schema?.pluginOptions)) {
@@ -217,10 +224,94 @@ const relationsApi = i18nApi.injectEndpoints({
217
224
  })
218
225
  });
219
226
  const { useGetManyDraftRelationCountQuery } = relationsApi;
227
+ const cleanData = (data, schema, components) => {
228
+ const cleanedData = removeFields(data, [
229
+ "createdAt",
230
+ "createdBy",
231
+ "updatedAt",
232
+ "updatedBy",
233
+ "id",
234
+ "documentId",
235
+ "publishedAt",
236
+ "strapi_stage",
237
+ "strapi_assignee",
238
+ "locale",
239
+ "status"
240
+ ]);
241
+ const cleanedDataWithoutPasswordAndRelation = recursiveRemoveFieldTypes(
242
+ cleanedData,
243
+ schema,
244
+ components,
245
+ ["relation", "password"]
246
+ );
247
+ return cleanedDataWithoutPasswordAndRelation;
248
+ };
249
+ const removeFields = (data, fields) => {
250
+ return Object.keys(data).reduce((acc, current) => {
251
+ if (fields.includes(current)) {
252
+ return acc;
253
+ }
254
+ acc[current] = data[current];
255
+ return acc;
256
+ }, {});
257
+ };
258
+ const recursiveRemoveFieldTypes = (data, schema, components, fields) => {
259
+ return Object.keys(data).reduce((acc, current) => {
260
+ const attribute = schema.attributes[current] ?? { type: void 0 };
261
+ if (fields.includes(attribute.type)) {
262
+ return acc;
263
+ }
264
+ if (attribute.type === "dynamiczone") {
265
+ acc[current] = data[current].map((componentValue, index2) => {
266
+ const { id: _, ...rest } = recursiveRemoveFieldTypes(
267
+ componentValue,
268
+ components[componentValue.__component],
269
+ components,
270
+ fields
271
+ );
272
+ return {
273
+ ...rest,
274
+ __temp_key__: index2 + 1
275
+ };
276
+ });
277
+ } else if (attribute.type === "component") {
278
+ const { repeatable, component } = attribute;
279
+ if (repeatable) {
280
+ acc[current] = (data[current] ?? []).map((compoData, index2) => {
281
+ const { id: _, ...rest } = recursiveRemoveFieldTypes(
282
+ compoData,
283
+ components[component],
284
+ components,
285
+ fields
286
+ );
287
+ return {
288
+ ...rest,
289
+ __temp_key__: index2 + 1
290
+ };
291
+ });
292
+ } else {
293
+ const { id: _, ...rest } = recursiveRemoveFieldTypes(
294
+ data[current] ?? {},
295
+ components[component],
296
+ components,
297
+ fields
298
+ );
299
+ acc[current] = rest;
300
+ }
301
+ } else {
302
+ acc[current] = data[current];
303
+ }
304
+ return acc;
305
+ }, {});
306
+ };
220
307
  const isErrorMessageDescriptor = (object) => {
221
308
  return typeof object === "object" && object !== null && "id" in object && "defaultMessage" in object;
222
309
  };
223
- const EntryValidationText = ({ status = "draft", validationErrors }) => {
310
+ const EntryValidationText = ({
311
+ status = "draft",
312
+ validationErrors,
313
+ action
314
+ }) => {
224
315
  const { formatMessage } = useIntl();
225
316
  const getErrorStr = (key, value) => {
226
317
  if (typeof value === "string") {
@@ -254,30 +345,63 @@ const EntryValidationText = ({ status = "draft", validationErrors }) => {
254
345
  ) })
255
346
  ] });
256
347
  }
257
- if (status === "published") {
258
- return /* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
259
- /* @__PURE__ */ jsx(CheckCircle, { fill: "success600" }),
260
- /* @__PURE__ */ jsx(Typography, { textColor: "success600", fontWeight: "bold", children: formatMessage({
261
- id: "content-manager.bulk-publish.already-published",
262
- defaultMessage: "Already Published"
263
- }) })
264
- ] });
265
- }
266
- if (status === "modified") {
267
- return /* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
268
- /* @__PURE__ */ jsx(ArrowsCounterClockwise, { fill: "alternative600" }),
269
- /* @__PURE__ */ jsx(Typography, { children: formatMessage({
270
- id: "app.utils.ready-to-publish-changes",
271
- defaultMessage: "Ready to publish changes"
272
- }) })
273
- ] });
274
- }
348
+ const getStatusMessage = () => {
349
+ if (action === "bulk-publish") {
350
+ if (status === "published") {
351
+ return {
352
+ icon: /* @__PURE__ */ jsx(CheckCircle, { fill: "success600" }),
353
+ text: formatMessage({
354
+ id: "content-manager.bulk-publish.already-published",
355
+ defaultMessage: "Already Published"
356
+ }),
357
+ textColor: "success600",
358
+ fontWeight: "bold"
359
+ };
360
+ } else if (status === "modified") {
361
+ return {
362
+ icon: /* @__PURE__ */ jsx(ArrowsCounterClockwise, { fill: "alternative600" }),
363
+ text: formatMessage({
364
+ id: "app.utils.ready-to-publish-changes",
365
+ defaultMessage: "Ready to publish changes"
366
+ })
367
+ };
368
+ } else {
369
+ return {
370
+ icon: /* @__PURE__ */ jsx(CheckCircle, { fill: "success600" }),
371
+ text: formatMessage({
372
+ id: "app.utils.ready-to-publish",
373
+ defaultMessage: "Ready to publish"
374
+ })
375
+ };
376
+ }
377
+ } else {
378
+ if (status === "draft") {
379
+ return {
380
+ icon: /* @__PURE__ */ jsx(CheckCircle, { fill: "success600" }),
381
+ text: formatMessage({
382
+ id: "content-manager.bulk-unpublish.already-unpublished",
383
+ defaultMessage: "Already Unpublished"
384
+ }),
385
+ textColor: "success600",
386
+ fontWeight: "bold"
387
+ };
388
+ } else {
389
+ return {
390
+ icon: /* @__PURE__ */ jsx(CheckCircle, { fill: "success600" }),
391
+ text: formatMessage({
392
+ id: "app.utils.ready-to-unpublish-changes",
393
+ defaultMessage: "Ready to unpublish"
394
+ }),
395
+ textColor: "success600",
396
+ fontWeight: "bold"
397
+ };
398
+ }
399
+ }
400
+ };
401
+ const { icon, text, textColor = "success600", fontWeight = "normal" } = getStatusMessage();
275
402
  return /* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
276
- /* @__PURE__ */ jsx(CheckCircle, { fill: "success600" }),
277
- /* @__PURE__ */ jsx(Typography, { children: formatMessage({
278
- id: "app.utils.ready-to-publish",
279
- defaultMessage: "Ready to publish"
280
- }) })
403
+ icon,
404
+ /* @__PURE__ */ jsx(Typography, { textColor, fontWeight, children: text })
281
405
  ] });
282
406
  };
283
407
  const BoldChunk = (chunks) => /* @__PURE__ */ jsx(Typography, { fontWeight: "bold", children: chunks });
@@ -285,7 +409,8 @@ const BulkLocaleActionModal = ({
285
409
  headers,
286
410
  rows,
287
411
  localesMetadata,
288
- validationErrors = {}
412
+ validationErrors = {},
413
+ action
289
414
  }) => {
290
415
  const { formatMessage } = useIntl();
291
416
  const selectedRows = useTable(
@@ -298,27 +423,29 @@ const BulkLocaleActionModal = ({
298
423
  return acc;
299
424
  }, {});
300
425
  const localesWithErrors = Object.keys(validationErrors);
301
- const alreadyPublishedCount = selectedRows.filter(
426
+ const publishedCount = selectedRows.filter(
302
427
  ({ locale }) => currentStatusByLocale[locale] === "published"
303
428
  ).length;
304
- const readyToPublishCount = selectedRows.filter(
429
+ const draftCount = selectedRows.filter(
305
430
  ({ locale }) => (currentStatusByLocale[locale] === "draft" || currentStatusByLocale[locale] === "modified") && !localesWithErrors.includes(locale)
306
431
  ).length;
307
432
  const withErrorsCount = localesWithErrors.length;
433
+ const messageId = action === "bulk-publish" ? "content-manager.containers.list.selectedEntriesModal.selectedCount.publish" : "content-manager.containers.list.selectedEntriesModal.selectedCount.unpublish";
434
+ 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.";
308
435
  return formatMessage(
309
436
  {
310
- id: "content-manager.containers.list.selectedEntriesModal.selectedCount",
311
- 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."
437
+ id: messageId,
438
+ defaultMessage
312
439
  },
313
440
  {
314
441
  withErrorsCount,
315
- readyToPublishCount,
316
- alreadyPublishedCount,
442
+ draftCount,
443
+ publishedCount,
317
444
  b: BoldChunk
318
445
  }
319
446
  );
320
447
  };
321
- return /* @__PURE__ */ jsxs(React.Fragment, { children: [
448
+ return /* @__PURE__ */ jsxs(Modal.Body, { children: [
322
449
  /* @__PURE__ */ jsx(Typography, { children: getFormattedCountMessage() }),
323
450
  /* @__PURE__ */ jsx(Box, { marginTop: 5, children: /* @__PURE__ */ jsxs(Table.Content, { children: [
324
451
  /* @__PURE__ */ jsxs(Table.Head, { children: [
@@ -339,13 +466,12 @@ const BulkLocaleActionModal = ({
339
466
  paddingRight: "6px",
340
467
  paddingTop: "2px",
341
468
  paddingBottom: "2px",
342
- showBullet: false,
343
469
  size: "S",
344
470
  variant: statusVariant,
345
471
  children: /* @__PURE__ */ jsx(Typography, { tag: "span", variant: "pi", fontWeight: "bold", children: capitalize(status) })
346
472
  }
347
473
  ) }) }),
348
- /* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsx(EntryValidationText, { validationErrors: error, status }) }),
474
+ /* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsx(EntryValidationText, { validationErrors: error, status, action }) }),
349
475
  /* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsx(
350
476
  IconButton,
351
477
  {
@@ -362,7 +488,7 @@ const BulkLocaleActionModal = ({
362
488
  name: locale
363
489
  }
364
490
  ),
365
- borderWidth: 0,
491
+ variant: "ghost",
366
492
  children: /* @__PURE__ */ jsx(Pencil, {})
367
493
  }
368
494
  ) })
@@ -371,6 +497,47 @@ const BulkLocaleActionModal = ({
371
497
  ] }) })
372
498
  ] });
373
499
  };
500
+ const statusVariants = {
501
+ draft: "secondary",
502
+ published: "success",
503
+ modified: "alternative"
504
+ };
505
+ const LocaleOption = ({
506
+ isDraftAndPublishEnabled,
507
+ locale,
508
+ status,
509
+ entryExists
510
+ }) => {
511
+ const { formatMessage } = useIntl();
512
+ if (!entryExists) {
513
+ return formatMessage(
514
+ {
515
+ id: getTranslation("CMEditViewLocalePicker.locale.create"),
516
+ defaultMessage: "Create <bold>{locale}</bold> locale"
517
+ },
518
+ {
519
+ bold: (locale2) => /* @__PURE__ */ jsx("b", { children: locale2 }),
520
+ locale: locale.name
521
+ }
522
+ );
523
+ }
524
+ return /* @__PURE__ */ jsxs(Flex, { width: "100%", gap: 1, justifyContent: "space-between", children: [
525
+ /* @__PURE__ */ jsx(Typography, { children: locale.name }),
526
+ isDraftAndPublishEnabled ? /* @__PURE__ */ jsx(
527
+ Status,
528
+ {
529
+ display: "flex",
530
+ paddingLeft: "6px",
531
+ paddingRight: "6px",
532
+ paddingTop: "2px",
533
+ paddingBottom: "2px",
534
+ size: "S",
535
+ variant: statusVariants[status],
536
+ children: /* @__PURE__ */ jsx(Typography, { tag: "span", variant: "pi", fontWeight: "bold", children: capitalize(status) })
537
+ }
538
+ ) : null
539
+ ] });
540
+ };
374
541
  const LocalePickerAction = ({
375
542
  document,
376
543
  meta,
@@ -382,7 +549,13 @@ const LocalePickerAction = ({
382
549
  const [{ query }, setQuery] = useQueryParams();
383
550
  const { hasI18n, canCreate, canRead } = useI18n();
384
551
  const { data: locales = [] } = useGetLocalesQuery();
385
- const { schema } = unstable_useDocument({ model, collectionType, documentId });
552
+ const currentDesiredLocale = query.plugins?.i18n?.locale;
553
+ const { schema } = unstable_useDocument({
554
+ model,
555
+ collectionType,
556
+ documentId,
557
+ params: { locale: currentDesiredLocale }
558
+ });
386
559
  const handleSelect = React.useCallback(
387
560
  (value) => {
388
561
  setQuery({
@@ -400,53 +573,50 @@ const LocalePickerAction = ({
400
573
  if (!Array.isArray(locales) || !hasI18n) {
401
574
  return;
402
575
  }
403
- const currentDesiredLocale = query.plugins?.i18n?.locale;
404
576
  const doesLocaleExist = locales.find((loc) => loc.code === currentDesiredLocale);
405
577
  const defaultLocale = locales.find((locale) => locale.isDefault);
406
578
  if (!doesLocaleExist && defaultLocale?.code) {
407
579
  handleSelect(defaultLocale.code);
408
580
  }
409
- }, [handleSelect, hasI18n, locales, query.plugins?.i18n?.locale]);
410
- if (!hasI18n || !Array.isArray(locales) || locales.length === 0) {
411
- return null;
412
- }
413
- const currentLocale = query.plugins?.i18n?.locale || locales.find((loc) => loc.isDefault)?.code;
581
+ }, [handleSelect, hasI18n, locales, currentDesiredLocale]);
582
+ const currentLocale = Array.isArray(locales) ? locales.find((locale) => locale.code === currentDesiredLocale) : void 0;
414
583
  const allCurrentLocales = [
415
- { status: getDocumentStatus(document, meta), locale: currentLocale },
584
+ { status: getDocumentStatus(document, meta), locale: currentLocale?.code },
416
585
  ...meta?.availableLocales ?? []
417
586
  ];
587
+ if (!hasI18n || !Array.isArray(locales) || locales.length === 0) {
588
+ return null;
589
+ }
590
+ const displayedLocales = locales.filter((locale) => {
591
+ return canRead.includes(locale.code);
592
+ });
418
593
  return {
419
594
  label: formatMessage({
420
595
  id: getTranslation("Settings.locales.modal.locales.label"),
421
596
  defaultMessage: "Locales"
422
597
  }),
423
- options: locales.map((locale) => {
598
+ options: displayedLocales.map((locale) => {
599
+ const entryWithLocaleExists = allCurrentLocales.some((doc) => doc.locale === locale.code);
424
600
  const currentLocaleDoc = allCurrentLocales.find(
425
601
  (doc) => "locale" in doc ? doc.locale === locale.code : false
426
602
  );
427
- const status = currentLocaleDoc?.status ?? "draft";
428
- const permissionsToCheck = currentLocaleDoc ? canCreate : canRead;
429
- const statusVariant = status === "draft" ? "primary" : status === "published" ? "success" : "alternative";
603
+ const permissionsToCheck = currentLocaleDoc ? canRead : canCreate;
430
604
  return {
431
605
  disabled: !permissionsToCheck.includes(locale.code),
432
606
  value: locale.code,
433
- label: locale.name,
434
- startIcon: schema?.options?.draftAndPublish ? /* @__PURE__ */ jsx(
435
- Status,
607
+ label: /* @__PURE__ */ jsx(
608
+ LocaleOption,
436
609
  {
437
- display: "flex",
438
- paddingLeft: "6px",
439
- paddingRight: "6px",
440
- paddingTop: "2px",
441
- paddingBottom: "2px",
442
- showBullet: false,
443
- size: "S",
444
- variant: statusVariant,
445
- children: /* @__PURE__ */ jsx(Typography, { tag: "span", variant: "pi", fontWeight: "bold", children: capitalize(status) })
610
+ isDraftAndPublishEnabled: !!schema?.options?.draftAndPublish,
611
+ locale,
612
+ status: currentLocaleDoc?.status,
613
+ entryExists: entryWithLocaleExists
446
614
  }
447
- ) : null
615
+ ),
616
+ startIcon: !entryWithLocaleExists ? /* @__PURE__ */ jsx(Plus, {}) : null
448
617
  };
449
618
  }),
619
+ customizeContent: () => currentLocale?.name,
450
620
  onSelect: handleSelect,
451
621
  value: currentLocale
452
622
  };
@@ -462,6 +632,99 @@ const getDocumentStatus = (document, meta) => {
462
632
  }
463
633
  return docStatus;
464
634
  };
635
+ const FillFromAnotherLocaleAction = ({
636
+ documentId,
637
+ meta,
638
+ model,
639
+ collectionType
640
+ }) => {
641
+ const { formatMessage } = useIntl();
642
+ const [{ query }] = useQueryParams();
643
+ const { hasI18n } = useI18n();
644
+ const currentDesiredLocale = query.plugins?.i18n?.locale;
645
+ const [localeSelected, setLocaleSelected] = React.useState(null);
646
+ const setValues = useForm("FillFromAnotherLocale", (state) => state.setValues);
647
+ const { getDocument } = unstable_useDocumentActions();
648
+ const { schema, components } = unstable_useDocument({
649
+ model,
650
+ documentId,
651
+ collectionType,
652
+ params: { locale: currentDesiredLocale }
653
+ });
654
+ const { data: locales = [] } = useGetLocalesQuery();
655
+ const availableLocales = Array.isArray(locales) ? locales.filter((locale) => meta?.availableLocales.some((l) => l.locale === locale.code)) : [];
656
+ const fillFromLocale = (onClose) => async () => {
657
+ const response = await getDocument({
658
+ collectionType,
659
+ model,
660
+ documentId,
661
+ params: { locale: localeSelected }
662
+ });
663
+ if (!response || !schema) {
664
+ return;
665
+ }
666
+ const { data } = response;
667
+ const cleanedData = cleanData(data, schema, components);
668
+ setValues(cleanedData);
669
+ onClose();
670
+ };
671
+ if (!hasI18n) {
672
+ return null;
673
+ }
674
+ return {
675
+ type: "icon",
676
+ icon: /* @__PURE__ */ jsx(Download, {}),
677
+ disabled: availableLocales.length === 0,
678
+ label: formatMessage({
679
+ id: getTranslation("CMEditViewCopyLocale.copy-text"),
680
+ defaultMessage: "Fill in from another locale"
681
+ }),
682
+ dialog: {
683
+ type: "dialog",
684
+ title: formatMessage({
685
+ id: getTranslation("CMEditViewCopyLocale.dialog.title"),
686
+ defaultMessage: "Confirmation"
687
+ }),
688
+ content: ({ onClose }) => /* @__PURE__ */ jsxs(Fragment, { children: [
689
+ /* @__PURE__ */ jsx(Dialog.Body, { children: /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: 3, children: [
690
+ /* @__PURE__ */ jsx(WarningCircle, { width: "24px", height: "24px", fill: "danger600" }),
691
+ /* @__PURE__ */ jsx(Typography, { textAlign: "center", children: formatMessage({
692
+ id: getTranslation("CMEditViewCopyLocale.dialog.body"),
693
+ defaultMessage: "Your current content will be erased and filled by the content of the selected locale:"
694
+ }) }),
695
+ /* @__PURE__ */ jsxs(Field.Root, { width: "100%", children: [
696
+ /* @__PURE__ */ jsx(Field.Label, { children: formatMessage({
697
+ id: getTranslation("CMEditViewCopyLocale.dialog.field.label"),
698
+ defaultMessage: "Locale"
699
+ }) }),
700
+ /* @__PURE__ */ jsx(
701
+ SingleSelect,
702
+ {
703
+ value: localeSelected,
704
+ placeholder: formatMessage({
705
+ id: getTranslation("CMEditViewCopyLocale.dialog.field.placeholder"),
706
+ defaultMessage: "Select one locale..."
707
+ }),
708
+ onChange: (value) => setLocaleSelected(value),
709
+ children: availableLocales.map((locale) => /* @__PURE__ */ jsx(SingleSelectOption, { value: locale.code, children: locale.name }, locale.code))
710
+ }
711
+ )
712
+ ] })
713
+ ] }) }),
714
+ /* @__PURE__ */ jsx(Dialog.Footer, { children: /* @__PURE__ */ jsxs(Flex, { gap: 2, width: "100%", children: [
715
+ /* @__PURE__ */ jsx(Button, { flex: "auto", variant: "tertiary", onClick: onClose, children: formatMessage({
716
+ id: getTranslation("CMEditViewCopyLocale.cancel-text"),
717
+ defaultMessage: "No, cancel"
718
+ }) }),
719
+ /* @__PURE__ */ jsx(Button, { flex: "auto", variant: "success", onClick: fillFromLocale(onClose), children: formatMessage({
720
+ id: getTranslation("CMEditViewCopyLocale.submit-text"),
721
+ defaultMessage: "Yes, fill in"
722
+ }) })
723
+ ] }) })
724
+ ] })
725
+ }
726
+ };
727
+ };
465
728
  const DeleteLocaleAction = ({
466
729
  document,
467
730
  documentId,
@@ -473,16 +736,23 @@ const DeleteLocaleAction = ({
473
736
  const { toggleNotification } = useNotification();
474
737
  const { delete: deleteAction } = unstable_useDocumentActions();
475
738
  const { hasI18n, canDelete } = useI18n();
739
+ const [{ query }] = useQueryParams();
740
+ const { data: locales = [] } = useGetLocalesQuery();
741
+ const currentDesiredLocale = query.plugins?.i18n?.locale;
742
+ const locale = !("error" in locales) && locales.find((loc) => loc.code === currentDesiredLocale);
476
743
  if (!hasI18n) {
477
744
  return null;
478
745
  }
479
746
  return {
480
747
  disabled: document?.locale && !canDelete.includes(document.locale) || !document || !document.id,
481
748
  position: ["header", "table-row"],
482
- label: formatMessage({
483
- id: getTranslation("actions.delete.label"),
484
- defaultMessage: "Delete locale"
485
- }),
749
+ label: formatMessage(
750
+ {
751
+ id: getTranslation("actions.delete.label"),
752
+ defaultMessage: "Delete entry ({locale})"
753
+ },
754
+ { locale: locale && locale.name }
755
+ ),
486
756
  icon: /* @__PURE__ */ jsx(StyledTrash, {}),
487
757
  variant: "danger",
488
758
  dialog: {
@@ -499,7 +769,12 @@ const DeleteLocaleAction = ({
499
769
  }) })
500
770
  ] }),
501
771
  onConfirm: async () => {
502
- if (!documentId || !document?.locale) {
772
+ const unableToDelete = (
773
+ // We are unable to delete a collection type without a document ID
774
+ // & unable to delete generally if there is no document locale
775
+ collectionType !== "single-types" && !documentId || !document?.locale
776
+ );
777
+ if (unableToDelete) {
503
778
  console.error(
504
779
  "You're trying to delete a document without an id or locale, this is likely a bug with Strapi. Please open an issue."
505
780
  );
@@ -525,37 +800,43 @@ const DeleteLocaleAction = ({
525
800
  }
526
801
  };
527
802
  };
528
- const BulkLocalePublishAction = ({
803
+ const BulkLocaleAction = ({
529
804
  document: baseDocument,
530
805
  documentId,
531
806
  model,
532
- collectionType
807
+ collectionType,
808
+ action
533
809
  }) => {
534
810
  const baseLocale = baseDocument?.locale ?? null;
535
811
  const [{ query }] = useQueryParams();
536
812
  const params = React.useMemo(() => buildValidParams(query), [query]);
537
- const isPublishedTab = query.status === "published";
813
+ const isOnPublishedTab = query.status === "published";
538
814
  const { formatMessage } = useIntl();
539
815
  const { hasI18n, canPublish } = useI18n();
540
816
  const { toggleNotification } = useNotification();
541
817
  const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler();
542
818
  const [selectedRows, setSelectedRows] = React.useState([]);
543
- const [isConfirmationOpen, setIsConfirmationOpen] = React.useState(false);
544
- const { publishMany: publishManyAction } = unstable_useDocumentActions();
819
+ const [isDraftRelationConfirmationOpen, setIsDraftRelationConfirmationOpen] = React.useState(false);
820
+ const { publishMany: publishManyAction, unpublishMany: unpublishManyAction } = unstable_useDocumentActions();
545
821
  const {
546
822
  document,
547
823
  meta: documentMeta,
548
824
  schema,
549
825
  validate
550
- } = unstable_useDocument({
551
- model,
552
- collectionType,
553
- documentId,
554
- params: {
555
- locale: baseLocale
826
+ } = unstable_useDocument(
827
+ {
828
+ model,
829
+ collectionType,
830
+ documentId,
831
+ params: {
832
+ locale: baseLocale
833
+ }
834
+ },
835
+ {
836
+ skip: !hasI18n || !baseLocale
556
837
  }
557
- });
558
- const { data: localesMetadata = [] } = useGetLocalesQuery();
838
+ );
839
+ const { data: localesMetadata = [] } = useGetLocalesQuery(hasI18n ? void 0 : skipToken);
559
840
  const headers = [
560
841
  {
561
842
  label: formatMessage({
@@ -604,12 +885,19 @@ const BulkLocalePublishAction = ({
604
885
  }, {});
605
886
  return [rowsFromMeta, errors];
606
887
  }, [document, documentMeta?.availableLocales, validate]);
607
- const localesToPublish = selectedRows.reduce((acc, selectedRow) => {
608
- if (selectedRow.status !== "published" && !Object.keys(validationErrors).includes(selectedRow.locale)) {
888
+ const isBulkPublish = action === "bulk-publish";
889
+ const localesForAction = selectedRows.reduce((acc, selectedRow) => {
890
+ const isValidLocale = (
891
+ // Validation errors are irrelevant if we are trying to unpublish
892
+ !isBulkPublish || !Object.keys(validationErrors).includes(selectedRow.locale)
893
+ );
894
+ const shouldAddLocale = isBulkPublish ? selectedRow.status !== "published" && isValidLocale : selectedRow.status !== "draft" && isValidLocale;
895
+ if (shouldAddLocale) {
609
896
  acc.push(selectedRow.locale);
610
897
  }
611
898
  return acc;
612
899
  }, []);
900
+ const enableDraftRelationsCount = false;
613
901
  const {
614
902
  data: draftRelationsCount = 0,
615
903
  isLoading: isDraftRelationsLoading,
@@ -618,10 +906,10 @@ const BulkLocalePublishAction = ({
618
906
  {
619
907
  model,
620
908
  documentIds: [documentId],
621
- locale: localesToPublish
909
+ locale: localesForAction
622
910
  },
623
911
  {
624
- skip: !documentId || localesToPublish.length === 0
912
+ skip: !enableDraftRelationsCount
625
913
  }
626
914
  );
627
915
  React.useEffect(() => {
@@ -647,23 +935,32 @@ const BulkLocalePublishAction = ({
647
935
  documentIds: [documentId],
648
936
  params: {
649
937
  ...params,
650
- locale: localesToPublish
938
+ locale: localesForAction
939
+ }
940
+ });
941
+ setSelectedRows([]);
942
+ };
943
+ const unpublish = async () => {
944
+ await unpublishManyAction({
945
+ model,
946
+ documentIds: [documentId],
947
+ params: {
948
+ ...params,
949
+ locale: localesForAction
651
950
  }
652
951
  });
653
952
  setSelectedRows([]);
654
953
  };
655
954
  const handleAction = async () => {
656
955
  if (draftRelationsCount > 0) {
657
- setIsConfirmationOpen(true);
658
- } else {
956
+ setIsDraftRelationConfirmationOpen(true);
957
+ } else if (isBulkPublish) {
659
958
  await publish();
959
+ } else {
960
+ await unpublish();
660
961
  }
661
962
  };
662
- const isUnpublish = document?.status === "published";
663
- if (isUnpublish) {
664
- console.warn(["I18N"], "Bulk locale unpublish modal not implemented");
665
- }
666
- if (isConfirmationOpen) {
963
+ if (isDraftRelationConfirmationOpen) {
667
964
  return {
668
965
  label: formatMessage({
669
966
  id: "app.components.ConfirmDialog.title",
@@ -672,11 +969,11 @@ const BulkLocalePublishAction = ({
672
969
  variant: "danger",
673
970
  dialog: {
674
971
  onCancel: () => {
675
- setIsConfirmationOpen(false);
972
+ setIsDraftRelationConfirmationOpen(false);
676
973
  },
677
974
  onConfirm: async () => {
678
975
  await publish();
679
- setIsConfirmationOpen(false);
976
+ setIsDraftRelationConfirmationOpen(false);
680
977
  },
681
978
  type: "dialog",
682
979
  title: formatMessage({
@@ -686,27 +983,32 @@ const BulkLocalePublishAction = ({
686
983
  content: /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "center", gap: 2, children: [
687
984
  /* @__PURE__ */ jsx(WarningCircle, { width: "2.4rem", height: "2.4rem", fill: "danger600" }),
688
985
  /* @__PURE__ */ jsx(Typography, { textAlign: "center", children: formatMessage({
689
- id: "content-manager.actions.discard.dialog.body",
690
- defaultMessage: "Are you sure you want to discard the changes? This action is irreversible."
986
+ id: getTranslation("CMEditViewBulkLocale.draft-relation-warning"),
987
+ defaultMessage: "Some locales are related to draft entries. Publishing them could leave broken links in your app."
988
+ }) }),
989
+ /* @__PURE__ */ jsx(Typography, { textAlign: "center", children: formatMessage({
990
+ id: getTranslation("CMEditViewBulkLocale.continue-confirmation"),
991
+ defaultMessage: "Are you sure you want to continue?"
691
992
  }) })
692
993
  ] })
693
994
  }
694
995
  };
695
996
  }
997
+ const hasPermission = selectedRows.map(({ locale }) => locale).every((locale) => canPublish.includes(locale));
696
998
  return {
697
999
  label: formatMessage({
698
- id: getTranslation("CMEditViewBulkLocale.publish-title"),
699
- defaultMessage: "Publish Multiple Locales"
1000
+ id: getTranslation(`CMEditViewBulkLocale.${isBulkPublish ? "publish" : "unpublish"}-title`),
1001
+ defaultMessage: `${isBulkPublish ? "Publish" : "Unpublish"} Multiple Locales`
700
1002
  }),
701
- icon: /* @__PURE__ */ jsx(ListPlus, {}),
702
- disabled: isPublishedTab || !canPublish,
1003
+ variant: isBulkPublish ? "secondary" : "danger",
1004
+ icon: isBulkPublish ? /* @__PURE__ */ jsx(ListPlus, {}) : /* @__PURE__ */ jsx(Cross, {}),
1005
+ disabled: isOnPublishedTab || canPublish.length === 0,
703
1006
  position: ["panel"],
704
- variant: "secondary",
705
1007
  dialog: {
706
1008
  type: "modal",
707
1009
  title: formatMessage({
708
- id: getTranslation("CMEditViewBulkLocale.publish-title"),
709
- defaultMessage: "Publish Multiple Locales"
1010
+ id: getTranslation(`CMEditViewBulkLocale.${isBulkPublish ? "publish" : "unpublish"}-title`),
1011
+ defaultMessage: `${isBulkPublish ? "Publish" : "Unpublish"} Multiple Locales`
710
1012
  }),
711
1013
  content: () => {
712
1014
  return /* @__PURE__ */ jsx(
@@ -725,28 +1027,35 @@ const BulkLocalePublishAction = ({
725
1027
  validationErrors,
726
1028
  headers,
727
1029
  rows,
728
- localesMetadata
1030
+ localesMetadata,
1031
+ action: action ?? "bulk-publish"
729
1032
  }
730
1033
  )
731
1034
  }
732
1035
  );
733
1036
  },
734
- footer: () => /* @__PURE__ */ jsx(Flex, { justifyContent: "flex-end", children: /* @__PURE__ */ jsx(
735
- Button$1,
1037
+ footer: () => /* @__PURE__ */ jsx(Modal.Footer, { justifyContent: "flex-end", children: /* @__PURE__ */ jsx(
1038
+ Button,
736
1039
  {
737
1040
  loading: isDraftRelationsLoading,
738
- disabled: localesToPublish.length === 0,
1041
+ disabled: !hasPermission || localesForAction.length === 0,
739
1042
  variant: "default",
740
1043
  onClick: handleAction,
741
1044
  children: formatMessage({
742
- id: "app.utils.publish",
743
- defaultMessage: "Publish"
1045
+ id: isBulkPublish ? "app.utils.publish" : "app.utils.unpublish",
1046
+ defaultMessage: isBulkPublish ? "Publish" : "Unpublish"
744
1047
  })
745
1048
  }
746
1049
  ) })
747
1050
  }
748
1051
  };
749
1052
  };
1053
+ const BulkLocalePublishAction = (props) => {
1054
+ return BulkLocaleAction({ action: "bulk-publish", ...props });
1055
+ };
1056
+ const BulkLocaleUnpublishAction = (props) => {
1057
+ return BulkLocaleAction({ action: "bulk-unpublish", ...props });
1058
+ };
750
1059
  const StyledTrash = styled(Trash)`
751
1060
  path {
752
1061
  fill: currentColor;
@@ -803,13 +1112,6 @@ const UnpublishModalAdditionalInfo = () => {
803
1112
  }
804
1113
  ) });
805
1114
  };
806
- const Initializer = ({ setPlugin }) => {
807
- const setPluginRef = React.useRef(setPlugin);
808
- React.useEffect(() => {
809
- setPluginRef.current(pluginId);
810
- }, []);
811
- return null;
812
- };
813
1115
  const LocalePicker = () => {
814
1116
  const { formatMessage } = useIntl();
815
1117
  const [{ query }, setQuery] = useQueryParams();
@@ -869,7 +1171,7 @@ const PERMISSIONS = {
869
1171
  read: [{ action: "plugin::i18n.locale.read", subject: null }]
870
1172
  };
871
1173
  const mutateEditViewHook = ({ layout }) => {
872
- if ("i18n" in layout.options && typeof layout.options.i18n === "object" && layout.options.i18n !== null && "localized" in layout.options.i18n && !layout.options.i18n.localized) {
1174
+ if (!("i18n" in layout.options) || typeof layout.options.i18n === "object" && layout.options.i18n !== null && "localized" in layout.options.i18n && !layout.options.i18n.localized) {
873
1175
  return { layout };
874
1176
  }
875
1177
  const components = Object.entries(layout.components).reduce(
@@ -915,7 +1217,7 @@ const doesFieldHaveI18nPluginOpt = (pluginOpts) => {
915
1217
  const LabelAction = ({ title, icon }) => {
916
1218
  const { formatMessage } = useIntl();
917
1219
  return /* @__PURE__ */ jsxs(Span, { tag: "span", children: [
918
- /* @__PURE__ */ jsx(VisuallyHidden, { tag: "span", children: `(${formatMessage(title)})` }),
1220
+ /* @__PURE__ */ jsx(VisuallyHidden, { tag: "span", children: formatMessage(title) }),
919
1221
  React.cloneElement(icon, {
920
1222
  "aria-hidden": true,
921
1223
  focusable: false
@@ -950,13 +1252,7 @@ const LocaleListCell = ({
950
1252
  }
951
1253
  });
952
1254
  const { locale: language } = useIntl();
953
- const [visible, setVisible] = React.useState(false);
954
- const buttonRef = React.useRef(null);
955
1255
  const { data: locales = [] } = useGetLocalesQuery();
956
- const handleTogglePopover = (e) => {
957
- e.stopPropagation();
958
- setVisible((prev) => !prev);
959
- };
960
1256
  const formatter = useCollator(language, {
961
1257
  sensitivity: "base"
962
1258
  });
@@ -978,64 +1274,14 @@ const LocaleListCell = ({
978
1274
  }
979
1275
  return locale.name;
980
1276
  }).toSorted((a, b) => formatter.compare(a, b));
981
- return /* @__PURE__ */ jsxs(Button, { type: "button", onClick: handleTogglePopover, ref: buttonRef, children: [
982
- /* @__PURE__ */ jsxs(
983
- ActionWrapper,
984
- {
985
- minWidth: "100%",
986
- alignItems: "center",
987
- justifyContent: "center",
988
- height: "3.2rem",
989
- width: "3.2rem",
990
- children: [
991
- /* @__PURE__ */ jsx(Typography, { textColor: "neutral800", ellipsis: true, children: localesForDocument.join(", ") }),
992
- /* @__PURE__ */ jsx(Flex, { children: /* @__PURE__ */ jsx(CaretDown, {}) })
993
- ]
994
- }
995
- ),
996
- visible && /* @__PURE__ */ jsx(
997
- Popover,
998
- {
999
- onDismiss: () => setVisible(false),
1000
- source: buttonRef,
1001
- spacing: 16,
1002
- centered: true,
1003
- children: /* @__PURE__ */ jsx("ul", { children: localesForDocument.map((name) => /* @__PURE__ */ jsx(Box, { padding: 3, tag: "li", children: /* @__PURE__ */ jsx(Typography, { children: name }) }, name)) })
1004
- }
1005
- )
1277
+ return /* @__PURE__ */ jsxs(Popover.Root, { children: [
1278
+ /* @__PURE__ */ jsx(Popover.Trigger, { children: /* @__PURE__ */ jsx(Button, { variant: "ghost", type: "button", onClick: (e) => e.stopPropagation(), children: /* @__PURE__ */ jsxs(Flex, { minWidth: "100%", alignItems: "center", justifyContent: "center", fontWeight: "regular", children: [
1279
+ /* @__PURE__ */ jsx(Typography, { textColor: "neutral800", ellipsis: true, marginRight: 2, children: localesForDocument.join(", ") }),
1280
+ /* @__PURE__ */ jsx(Flex, { children: /* @__PURE__ */ jsx(CaretDown, { width: "1.2rem", height: "1.2rem" }) })
1281
+ ] }) }) }),
1282
+ /* @__PURE__ */ jsx(Popover.Content, { sideOffset: 16, children: /* @__PURE__ */ jsx("ul", { children: localesForDocument.map((name) => /* @__PURE__ */ jsx(Box, { padding: 3, tag: "li", children: /* @__PURE__ */ jsx(Typography, { children: name }) }, name)) }) })
1006
1283
  ] });
1007
1284
  };
1008
- const Button = styled.button`
1009
- width: 100%;
1010
-
1011
- svg {
1012
- > g,
1013
- path {
1014
- fill: ${({ theme }) => theme.colors.neutral500};
1015
- }
1016
- }
1017
- &:hover {
1018
- svg {
1019
- > g,
1020
- path {
1021
- fill: ${({ theme }) => theme.colors.neutral600};
1022
- }
1023
- }
1024
- }
1025
- &:active {
1026
- svg {
1027
- > g,
1028
- path {
1029
- fill: ${({ theme }) => theme.colors.neutral400};
1030
- }
1031
- }
1032
- }
1033
- `;
1034
- const ActionWrapper = styled(Flex)`
1035
- svg {
1036
- height: 0.4rem;
1037
- }
1038
- `;
1039
1285
  const addColumnToTableHook = ({ displayedHeaders, layout }) => {
1040
1286
  const { options } = layout;
1041
1287
  const isFieldLocalized = doesPluginOptionsHaveI18nLocalized(options) ? options.i18n.localized : false;
@@ -1064,18 +1310,11 @@ const addColumnToTableHook = ({ displayedHeaders, layout }) => {
1064
1310
  const addLocaleToReleasesHook = ({ displayedHeaders = [] }) => {
1065
1311
  return {
1066
1312
  displayedHeaders: [
1067
- // TODO: Fix when migrating to v5
1068
- // ...displayedHeaders,
1313
+ ...displayedHeaders,
1069
1314
  {
1070
- key: "__locale__",
1071
- fieldSchema: { type: "string" },
1072
- metadatas: {
1073
- label: {
1074
- id: "content-releases.page.ReleaseDetails.table.header.label.locale",
1075
- defaultMessage: "locale"
1076
- },
1077
- searchable: false,
1078
- sortable: false
1315
+ label: {
1316
+ id: "content-releases.page.ReleaseDetails.table.header.label.locale",
1317
+ defaultMessage: "locale"
1079
1318
  },
1080
1319
  name: "locale"
1081
1320
  }
@@ -1168,9 +1407,6 @@ const localeMiddleware = (ctx) => (next) => (permissions) => {
1168
1407
  return next(revisedPermissions);
1169
1408
  };
1170
1409
  const prefixPluginTranslations = (trad, pluginId2) => {
1171
- if (!pluginId2) {
1172
- throw new TypeError("pluginId can't be empty");
1173
- }
1174
1410
  return Object.keys(trad).reduce((acc, current) => {
1175
1411
  acc[`${pluginId2}.${current}`] = trad[current];
1176
1412
  return acc;
@@ -1223,8 +1459,6 @@ const index = {
1223
1459
  app.addRBACMiddleware([localeMiddleware]);
1224
1460
  app.registerPlugin({
1225
1461
  id: pluginId,
1226
- initializer: Initializer,
1227
- isReady: false,
1228
1462
  name: pluginId
1229
1463
  });
1230
1464
  },
@@ -1242,11 +1476,11 @@ const index = {
1242
1476
  },
1243
1477
  id: "internationalization",
1244
1478
  to: "internationalization",
1245
- Component: () => import("./SettingsPage-0FFSTUW2.mjs").then((mod) => ({ default: mod.ProtectedSettingsPage })),
1479
+ Component: () => import("./SettingsPage-BAx9nmep.mjs").then((mod) => ({ default: mod.ProtectedSettingsPage })),
1246
1480
  permissions: PERMISSIONS.accessMain
1247
1481
  });
1248
1482
  const contentManager = app.getPlugin("content-manager");
1249
- contentManager.apis.addDocumentHeaderAction([LocalePickerAction]);
1483
+ contentManager.apis.addDocumentHeaderAction([LocalePickerAction, FillFromAnotherLocaleAction]);
1250
1484
  contentManager.apis.addDocumentAction((actions) => {
1251
1485
  const indexOfDeleteAction = actions.findIndex((action) => action.type === "delete");
1252
1486
  actions.splice(indexOfDeleteAction, 0, DeleteLocaleAction);
@@ -1254,6 +1488,7 @@ const index = {
1254
1488
  });
1255
1489
  contentManager.apis.addDocumentAction((actions) => {
1256
1490
  actions.splice(2, 0, BulkLocalePublishAction);
1491
+ actions.splice(5, 0, BulkLocaleUnpublishAction);
1257
1492
  return actions;
1258
1493
  });
1259
1494
  contentManager.injectComponent("listView", "actions", {
@@ -1359,7 +1594,7 @@ const index = {
1359
1594
  async registerTrads({ locales }) {
1360
1595
  const importedTrads = await Promise.all(
1361
1596
  locales.map((locale) => {
1362
- return __variableDynamicImportRuntimeHelper(/* @__PURE__ */ Object.assign({ "./translations/de.json": () => import("./de-9eCAqqrB.mjs"), "./translations/dk.json": () => import("./dk-2qBjxt-P.mjs"), "./translations/en.json": () => import("./en-18tWw4P6.mjs"), "./translations/es.json": () => import("./es-DlmMVaBG.mjs"), "./translations/fr.json": () => import("./fr-3S6ke71d.mjs"), "./translations/ko.json": () => import("./ko-qTjQ8IMw.mjs"), "./translations/pl.json": () => import("./pl-B67TSHqT.mjs"), "./translations/ru.json": () => import("./ru-hagMa57T.mjs"), "./translations/tr.json": () => import("./tr-Dw_jmkG-.mjs"), "./translations/zh-Hans.json": () => import("./zh-Hans-Dyc-aR-h.mjs"), "./translations/zh.json": () => import("./zh-57YM4amO.mjs") }), `./translations/${locale}.json`).then(({ default: data }) => {
1597
+ return __variableDynamicImportRuntimeHelper(/* @__PURE__ */ Object.assign({ "./translations/de.json": () => import("./de-9eCAqqrB.mjs"), "./translations/dk.json": () => import("./dk-2qBjxt-P.mjs"), "./translations/en.json": () => import("./en-DlXfy6Gy.mjs"), "./translations/es.json": () => import("./es-DlmMVaBG.mjs"), "./translations/fr.json": () => import("./fr-3S6ke71d.mjs"), "./translations/ko.json": () => import("./ko-qTjQ8IMw.mjs"), "./translations/pl.json": () => import("./pl-B67TSHqT.mjs"), "./translations/ru.json": () => import("./ru-hagMa57T.mjs"), "./translations/tr.json": () => import("./tr-Dw_jmkG-.mjs"), "./translations/zh-Hans.json": () => import("./zh-Hans-Dyc-aR-h.mjs"), "./translations/zh.json": () => import("./zh-57YM4amO.mjs") }), `./translations/${locale}.json`, 3).then(({ default: data }) => {
1363
1598
  return {
1364
1599
  data: prefixPluginTranslations(data, pluginId),
1365
1600
  locale
@@ -1385,4 +1620,4 @@ export {
1385
1620
  index as i,
1386
1621
  useCreateLocaleMutation as u
1387
1622
  };
1388
- //# sourceMappingURL=index-BddUXwss.mjs.map
1623
+ //# sourceMappingURL=index-B0NijiBB.mjs.map