@strapi/i18n 0.0.0-experimental.25e22c6cc9bc6b35392bb55d09f641a0a65e7403 → 0.0.0-experimental.31a5317d54179a9ce6225bf1b6e1f9fb6c372fa9

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 (41) hide show
  1. package/LICENSE +18 -3
  2. package/dist/_chunks/{SettingsPage-Dsi2qGtq.mjs → SettingsPage-BjxjwEOb.mjs} +15 -10
  3. package/dist/_chunks/SettingsPage-BjxjwEOb.mjs.map +1 -0
  4. package/dist/_chunks/{SettingsPage-VN7sTzkb.js → SettingsPage-CfTmCkup.js} +15 -10
  5. package/dist/_chunks/SettingsPage-CfTmCkup.js.map +1 -0
  6. package/dist/_chunks/{en-18tWw4P6.mjs → en-2xztdZE1.mjs} +9 -1
  7. package/dist/_chunks/en-2xztdZE1.mjs.map +1 -0
  8. package/dist/_chunks/{en-Kv6y9zPQ.js → en-DWpfm8h5.js} +9 -1
  9. package/dist/_chunks/en-DWpfm8h5.js.map +1 -0
  10. package/dist/_chunks/{index-kedPlCo6.js → index-5XLZwzwx.js} +356 -164
  11. package/dist/_chunks/index-5XLZwzwx.js.map +1 -0
  12. package/dist/_chunks/{index-DhtjJYrx.mjs → index-D-qx3tz4.mjs} +352 -160
  13. package/dist/_chunks/index-D-qx3tz4.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 +27 -3
  18. package/dist/admin/src/contentReleasesHooks/releaseDetailsView.d.ts +9 -5
  19. package/dist/admin/src/utils/clean.d.ts +4 -0
  20. package/dist/admin/src/utils/schemas.d.ts +1 -0
  21. package/dist/server/index.js +60 -9
  22. package/dist/server/index.js.map +1 -1
  23. package/dist/server/index.mjs +61 -10
  24. package/dist/server/index.mjs.map +1 -1
  25. package/dist/server/src/bootstrap.d.ts.map +1 -1
  26. package/dist/server/src/index.d.ts +14 -2
  27. package/dist/server/src/index.d.ts.map +1 -1
  28. package/dist/server/src/services/index.d.ts +14 -2
  29. package/dist/server/src/services/index.d.ts.map +1 -1
  30. package/dist/server/src/services/permissions/actions.d.ts +14 -2
  31. package/dist/server/src/services/permissions/actions.d.ts.map +1 -1
  32. package/dist/server/src/services/permissions.d.ts +14 -2
  33. package/dist/server/src/services/permissions.d.ts.map +1 -1
  34. package/package.json +9 -9
  35. package/dist/_chunks/SettingsPage-Dsi2qGtq.mjs.map +0 -1
  36. package/dist/_chunks/SettingsPage-VN7sTzkb.js.map +0 -1
  37. package/dist/_chunks/en-18tWw4P6.mjs.map +0 -1
  38. package/dist/_chunks/en-Kv6y9zPQ.js.map +0 -1
  39. package/dist/_chunks/index-DhtjJYrx.mjs.map +0 -1
  40. package/dist/_chunks/index-kedPlCo6.js.map +0 -1
  41. package/dist/admin/src/components/Initializer.d.ts +0 -5
@@ -7,6 +7,7 @@ const designSystem = require("@strapi/design-system");
7
7
  const icons = require("@strapi/icons");
8
8
  const reactIntl = require("react-intl");
9
9
  const styledComponents = require("styled-components");
10
+ const query = require("@reduxjs/toolkit/query");
10
11
  const strapiAdmin = require("@strapi/admin/strapi-admin");
11
12
  const strapiAdmin$1 = require("@strapi/content-manager/strapi-admin");
12
13
  const reactRouterDom = require("react-router-dom");
@@ -160,7 +161,7 @@ const useI18n = () => {
160
161
  model: params.slug
161
162
  },
162
163
  {
163
- skip: !params.slug || !params.collectionType
164
+ skip: true
164
165
  }
165
166
  );
166
167
  if (doesPluginOptionsHaveI18nLocalized(schema?.pluginOptions)) {
@@ -240,10 +241,93 @@ const relationsApi = i18nApi.injectEndpoints({
240
241
  })
241
242
  });
242
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
+ ]);
257
+ const cleanedDataWithoutPasswordAndRelation = recursiveRemoveFieldTypes(
258
+ cleanedData,
259
+ schema,
260
+ components,
261
+ ["relation", "password"]
262
+ );
263
+ return cleanedDataWithoutPasswordAndRelation;
264
+ };
265
+ const removeFields = (data, fields) => {
266
+ return Object.keys(data).reduce((acc, current) => {
267
+ if (fields.includes(current)) {
268
+ return acc;
269
+ }
270
+ acc[current] = data[current];
271
+ return acc;
272
+ }, {});
273
+ };
274
+ const recursiveRemoveFieldTypes = (data, schema, components, fields) => {
275
+ return Object.keys(data).reduce((acc, current) => {
276
+ const attribute = schema.attributes[current] ?? { type: void 0 };
277
+ if (fields.includes(attribute.type)) {
278
+ return acc;
279
+ }
280
+ if (attribute.type === "dynamiczone") {
281
+ acc[current] = data[current].map((componentValue, index2) => {
282
+ const { id: _, ...rest } = recursiveRemoveFieldTypes(
283
+ componentValue,
284
+ components[componentValue.__component],
285
+ components,
286
+ fields
287
+ );
288
+ return {
289
+ ...rest,
290
+ __temp_key__: index2 + 1
291
+ };
292
+ });
293
+ } else if (attribute.type === "component") {
294
+ const { repeatable, component } = attribute;
295
+ if (repeatable) {
296
+ acc[current] = (data[current] ?? []).map((compoData, index2) => {
297
+ const { id: _, ...rest } = recursiveRemoveFieldTypes(
298
+ compoData,
299
+ components[component],
300
+ components,
301
+ fields
302
+ );
303
+ return {
304
+ ...rest,
305
+ __temp_key__: index2 + 1
306
+ };
307
+ });
308
+ } else {
309
+ const { id: _, ...rest } = recursiveRemoveFieldTypes(
310
+ data[current] ?? {},
311
+ components[component],
312
+ components,
313
+ fields
314
+ );
315
+ acc[current] = rest;
316
+ }
317
+ } else {
318
+ acc[current] = data[current];
319
+ }
320
+ return acc;
321
+ }, {});
322
+ };
243
323
  const isErrorMessageDescriptor = (object) => {
244
324
  return typeof object === "object" && object !== null && "id" in object && "defaultMessage" in object;
245
325
  };
246
- const EntryValidationText = ({ status = "draft", validationErrors }) => {
326
+ const EntryValidationText = ({
327
+ status = "draft",
328
+ validationErrors,
329
+ action
330
+ }) => {
247
331
  const { formatMessage } = reactIntl.useIntl();
248
332
  const getErrorStr = (key, value) => {
249
333
  if (typeof value === "string") {
@@ -277,30 +361,63 @@ const EntryValidationText = ({ status = "draft", validationErrors }) => {
277
361
  ) })
278
362
  ] });
279
363
  }
280
- if (status === "published") {
281
- return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, children: [
282
- /* @__PURE__ */ jsxRuntime.jsx(icons.CheckCircle, { fill: "success600" }),
283
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { textColor: "success600", fontWeight: "bold", children: formatMessage({
284
- id: "content-manager.bulk-publish.already-published",
285
- defaultMessage: "Already Published"
286
- }) })
287
- ] });
288
- }
289
- if (status === "modified") {
290
- return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, children: [
291
- /* @__PURE__ */ jsxRuntime.jsx(icons.ArrowsCounterClockwise, { fill: "alternative600" }),
292
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { children: formatMessage({
293
- id: "app.utils.ready-to-publish-changes",
294
- defaultMessage: "Ready to publish changes"
295
- }) })
296
- ] });
297
- }
364
+ const getStatusMessage = () => {
365
+ if (action === "bulk-publish") {
366
+ if (status === "published") {
367
+ return {
368
+ icon: /* @__PURE__ */ jsxRuntime.jsx(icons.CheckCircle, { fill: "success600" }),
369
+ text: formatMessage({
370
+ id: "content-manager.bulk-publish.already-published",
371
+ defaultMessage: "Already Published"
372
+ }),
373
+ textColor: "success600",
374
+ fontWeight: "bold"
375
+ };
376
+ } else if (status === "modified") {
377
+ return {
378
+ icon: /* @__PURE__ */ jsxRuntime.jsx(icons.ArrowsCounterClockwise, { fill: "alternative600" }),
379
+ text: formatMessage({
380
+ id: "app.utils.ready-to-publish-changes",
381
+ defaultMessage: "Ready to publish changes"
382
+ })
383
+ };
384
+ } else {
385
+ return {
386
+ icon: /* @__PURE__ */ jsxRuntime.jsx(icons.CheckCircle, { fill: "success600" }),
387
+ text: formatMessage({
388
+ id: "app.utils.ready-to-publish",
389
+ defaultMessage: "Ready to publish"
390
+ })
391
+ };
392
+ }
393
+ } else {
394
+ if (status === "draft") {
395
+ return {
396
+ icon: /* @__PURE__ */ jsxRuntime.jsx(icons.CheckCircle, { fill: "success600" }),
397
+ text: formatMessage({
398
+ id: "content-manager.bulk-unpublish.already-unpublished",
399
+ defaultMessage: "Already Unpublished"
400
+ }),
401
+ textColor: "success600",
402
+ fontWeight: "bold"
403
+ };
404
+ } else {
405
+ return {
406
+ icon: /* @__PURE__ */ jsxRuntime.jsx(icons.CheckCircle, { fill: "success600" }),
407
+ text: formatMessage({
408
+ id: "app.utils.ready-to-unpublish-changes",
409
+ defaultMessage: "Ready to unpublish"
410
+ }),
411
+ textColor: "success600",
412
+ fontWeight: "bold"
413
+ };
414
+ }
415
+ }
416
+ };
417
+ const { icon, text, textColor = "success600", fontWeight = "normal" } = getStatusMessage();
298
418
  return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, children: [
299
- /* @__PURE__ */ jsxRuntime.jsx(icons.CheckCircle, { fill: "success600" }),
300
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { children: formatMessage({
301
- id: "app.utils.ready-to-publish",
302
- defaultMessage: "Ready to publish"
303
- }) })
419
+ icon,
420
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { textColor, fontWeight, children: text })
304
421
  ] });
305
422
  };
306
423
  const BoldChunk = (chunks) => /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { fontWeight: "bold", children: chunks });
@@ -308,7 +425,8 @@ const BulkLocaleActionModal = ({
308
425
  headers,
309
426
  rows,
310
427
  localesMetadata,
311
- validationErrors = {}
428
+ validationErrors = {},
429
+ action
312
430
  }) => {
313
431
  const { formatMessage } = reactIntl.useIntl();
314
432
  const selectedRows = strapiAdmin.useTable(
@@ -321,27 +439,29 @@ const BulkLocaleActionModal = ({
321
439
  return acc;
322
440
  }, {});
323
441
  const localesWithErrors = Object.keys(validationErrors);
324
- const alreadyPublishedCount = selectedRows.filter(
442
+ const publishedCount = selectedRows.filter(
325
443
  ({ locale }) => currentStatusByLocale[locale] === "published"
326
444
  ).length;
327
- const readyToPublishCount = selectedRows.filter(
445
+ const draftCount = selectedRows.filter(
328
446
  ({ locale }) => (currentStatusByLocale[locale] === "draft" || currentStatusByLocale[locale] === "modified") && !localesWithErrors.includes(locale)
329
447
  ).length;
330
448
  const withErrorsCount = localesWithErrors.length;
449
+ const messageId = action === "bulk-publish" ? "content-manager.containers.list.selectedEntriesModal.selectedCount.publish" : "content-manager.containers.list.selectedEntriesModal.selectedCount.unpublish";
450
+ 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.";
331
451
  return formatMessage(
332
452
  {
333
- id: "content-manager.containers.list.selectedEntriesModal.selectedCount",
334
- 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."
453
+ id: messageId,
454
+ defaultMessage
335
455
  },
336
456
  {
337
457
  withErrorsCount,
338
- readyToPublishCount,
339
- alreadyPublishedCount,
458
+ draftCount,
459
+ publishedCount,
340
460
  b: BoldChunk
341
461
  }
342
462
  );
343
463
  };
344
- return /* @__PURE__ */ jsxRuntime.jsxs(React__namespace.Fragment, { children: [
464
+ return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Modal.Body, { children: [
345
465
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { children: getFormattedCountMessage() }),
346
466
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { marginTop: 5, children: /* @__PURE__ */ jsxRuntime.jsxs(strapiAdmin.Table.Content, { children: [
347
467
  /* @__PURE__ */ jsxRuntime.jsxs(strapiAdmin.Table.Head, { children: [
@@ -368,7 +488,7 @@ const BulkLocaleActionModal = ({
368
488
  children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { tag: "span", variant: "pi", fontWeight: "bold", children: capitalize(status) })
369
489
  }
370
490
  ) }) }),
371
- /* @__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 }) }),
372
492
  /* @__PURE__ */ jsxRuntime.jsx(strapiAdmin.Table.Cell, { children: /* @__PURE__ */ jsxRuntime.jsx(
373
493
  designSystem.IconButton,
374
494
  {
@@ -385,7 +505,7 @@ const BulkLocaleActionModal = ({
385
505
  name: locale
386
506
  }
387
507
  ),
388
- borderWidth: 0,
508
+ variant: "ghost",
389
509
  children: /* @__PURE__ */ jsxRuntime.jsx(icons.Pencil, {})
390
510
  }
391
511
  ) })
@@ -402,42 +522,47 @@ const LocalePickerAction = ({
402
522
  documentId
403
523
  }) => {
404
524
  const { formatMessage } = reactIntl.useIntl();
405
- const [{ query }, setQuery] = strapiAdmin.useQueryParams();
525
+ const [{ query: query2 }, setQuery] = strapiAdmin.useQueryParams();
406
526
  const { hasI18n, canCreate, canRead } = useI18n();
407
527
  const { data: locales = [] } = useGetLocalesQuery();
408
- const { schema } = strapiAdmin$1.unstable_useDocument({ model, collectionType, documentId });
528
+ const currentDesiredLocale = query2.plugins?.i18n?.locale;
529
+ const { schema } = strapiAdmin$1.unstable_useDocument({
530
+ model,
531
+ collectionType,
532
+ documentId,
533
+ params: { locale: currentDesiredLocale }
534
+ });
409
535
  const handleSelect = React__namespace.useCallback(
410
536
  (value) => {
411
537
  setQuery({
412
538
  plugins: {
413
- ...query.plugins,
539
+ ...query2.plugins,
414
540
  i18n: {
415
541
  locale: value
416
542
  }
417
543
  }
418
544
  });
419
545
  },
420
- [query.plugins, setQuery]
546
+ [query2.plugins, setQuery]
421
547
  );
422
548
  React__namespace.useEffect(() => {
423
549
  if (!Array.isArray(locales) || !hasI18n) {
424
550
  return;
425
551
  }
426
- const currentDesiredLocale = query.plugins?.i18n?.locale;
427
552
  const doesLocaleExist = locales.find((loc) => loc.code === currentDesiredLocale);
428
553
  const defaultLocale = locales.find((locale) => locale.isDefault);
429
554
  if (!doesLocaleExist && defaultLocale?.code) {
430
555
  handleSelect(defaultLocale.code);
431
556
  }
432
- }, [handleSelect, hasI18n, locales, query.plugins?.i18n?.locale]);
433
- if (!hasI18n || !Array.isArray(locales) || locales.length === 0) {
434
- return null;
435
- }
436
- const currentLocale = query.plugins?.i18n?.locale || locales.find((loc) => loc.isDefault)?.code;
557
+ }, [handleSelect, hasI18n, locales, currentDesiredLocale]);
558
+ const currentLocale = Array.isArray(locales) ? locales.find((locale) => locale.code === currentDesiredLocale)?.code : void 0;
437
559
  const allCurrentLocales = [
438
560
  { status: getDocumentStatus(document, meta), locale: currentLocale },
439
561
  ...meta?.availableLocales ?? []
440
562
  ];
563
+ if (!hasI18n || !Array.isArray(locales) || locales.length === 0) {
564
+ return null;
565
+ }
441
566
  return {
442
567
  label: formatMessage({
443
568
  id: getTranslation("Settings.locales.modal.locales.label"),
@@ -449,7 +574,7 @@ const LocalePickerAction = ({
449
574
  );
450
575
  const status = currentLocaleDoc?.status ?? "draft";
451
576
  const permissionsToCheck = currentLocaleDoc ? canCreate : canRead;
452
- const statusVariant = status === "draft" ? "primary" : status === "published" ? "success" : "alternative";
577
+ const statusVariant = status === "draft" ? "secondary" : status === "published" ? "success" : "alternative";
453
578
  return {
454
579
  disabled: !permissionsToCheck.includes(locale.code),
455
580
  value: locale.code,
@@ -485,6 +610,95 @@ const getDocumentStatus = (document, meta) => {
485
610
  }
486
611
  return docStatus;
487
612
  };
613
+ const FillFromAnotherLocaleAction = ({
614
+ documentId,
615
+ meta,
616
+ model,
617
+ collectionType
618
+ }) => {
619
+ const { formatMessage } = reactIntl.useIntl();
620
+ const [{ query: query2 }] = strapiAdmin.useQueryParams();
621
+ const currentDesiredLocale = query2.plugins?.i18n?.locale;
622
+ const [localeSelected, setLocaleSelected] = React__namespace.useState(null);
623
+ const setValues = strapiAdmin.useForm("FillFromAnotherLocale", (state) => state.setValues);
624
+ const { getDocument } = strapiAdmin$1.unstable_useDocumentActions();
625
+ const { schema, components } = strapiAdmin$1.unstable_useDocument({
626
+ model,
627
+ documentId,
628
+ collectionType,
629
+ params: { locale: currentDesiredLocale }
630
+ });
631
+ const { data: locales = [] } = useGetLocalesQuery();
632
+ const availableLocales = Array.isArray(locales) ? locales.filter((locale) => meta?.availableLocales.some((l) => l.locale === locale.code)) : [];
633
+ const fillFromLocale = (onClose) => async () => {
634
+ const response = await getDocument({
635
+ collectionType,
636
+ model,
637
+ documentId,
638
+ params: { locale: localeSelected }
639
+ });
640
+ if (!response || !schema) {
641
+ return;
642
+ }
643
+ const { data } = response;
644
+ const cleanedData = cleanData(data, schema, components);
645
+ setValues(cleanedData);
646
+ onClose();
647
+ };
648
+ return {
649
+ type: "icon",
650
+ icon: /* @__PURE__ */ jsxRuntime.jsx(icons.Download, {}),
651
+ disabled: availableLocales.length === 0,
652
+ label: formatMessage({
653
+ id: getTranslation("CMEditViewCopyLocale.copy-text"),
654
+ defaultMessage: "Fill in from another locale"
655
+ }),
656
+ dialog: {
657
+ type: "dialog",
658
+ title: formatMessage({
659
+ id: getTranslation("CMEditViewCopyLocale.dialog.title"),
660
+ defaultMessage: "Confirmation"
661
+ }),
662
+ content: ({ onClose }) => /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
663
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Body, { children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", gap: 3, children: [
664
+ /* @__PURE__ */ jsxRuntime.jsx(icons.WarningCircle, { width: "24px", height: "24px", fill: "danger600" }),
665
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { textAlign: "center", children: formatMessage({
666
+ id: getTranslation("CMEditViewCopyLocale.dialog.body"),
667
+ defaultMessage: "Your current content will be erased and filled by the content of the selected locale:"
668
+ }) }),
669
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Field.Root, { width: "100%", children: [
670
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Label, { children: formatMessage({
671
+ id: getTranslation("CMEditViewCopyLocale.dialog.field.label"),
672
+ defaultMessage: "Locale"
673
+ }) }),
674
+ /* @__PURE__ */ jsxRuntime.jsx(
675
+ designSystem.SingleSelect,
676
+ {
677
+ value: localeSelected,
678
+ placeholder: formatMessage({
679
+ id: getTranslation("CMEditViewCopyLocale.dialog.field.placeholder"),
680
+ defaultMessage: "Select one locale..."
681
+ }),
682
+ onChange: (value) => setLocaleSelected(value),
683
+ children: availableLocales.map((locale) => /* @__PURE__ */ jsxRuntime.jsx(designSystem.SingleSelectOption, { value: locale.code, children: locale.name }, locale.code))
684
+ }
685
+ )
686
+ ] })
687
+ ] }) }),
688
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Footer, { children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, width: "100%", children: [
689
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { flex: "auto", variant: "tertiary", onClick: onClose, children: formatMessage({
690
+ id: getTranslation("CMEditViewCopyLocale.cancel-text"),
691
+ defaultMessage: "No, cancel"
692
+ }) }),
693
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { flex: "auto", variant: "success", onClick: fillFromLocale(onClose), children: formatMessage({
694
+ id: getTranslation("CMEditViewCopyLocale.submit-text"),
695
+ defaultMessage: "Yes, fill in"
696
+ }) })
697
+ ] }) })
698
+ ] })
699
+ }
700
+ };
701
+ };
488
702
  const DeleteLocaleAction = ({
489
703
  document,
490
704
  documentId,
@@ -548,37 +762,43 @@ const DeleteLocaleAction = ({
548
762
  }
549
763
  };
550
764
  };
551
- const BulkLocalePublishAction = ({
765
+ const BulkLocaleAction = ({
552
766
  document: baseDocument,
553
767
  documentId,
554
768
  model,
555
- collectionType
769
+ collectionType,
770
+ action
556
771
  }) => {
557
772
  const baseLocale = baseDocument?.locale ?? null;
558
- const [{ query }] = strapiAdmin.useQueryParams();
559
- const params = React__namespace.useMemo(() => strapiAdmin$1.buildValidParams(query), [query]);
560
- const isPublishedTab = query.status === "published";
773
+ const [{ query: query$1 }] = strapiAdmin.useQueryParams();
774
+ const params = React__namespace.useMemo(() => strapiAdmin$1.buildValidParams(query$1), [query$1]);
775
+ const isOnPublishedTab = query$1.status === "published";
561
776
  const { formatMessage } = reactIntl.useIntl();
562
777
  const { hasI18n, canPublish } = useI18n();
563
778
  const { toggleNotification } = strapiAdmin.useNotification();
564
779
  const { _unstableFormatAPIError: formatAPIError } = strapiAdmin.useAPIErrorHandler();
565
780
  const [selectedRows, setSelectedRows] = React__namespace.useState([]);
566
- const [isConfirmationOpen, setIsConfirmationOpen] = React__namespace.useState(false);
567
- const { publishMany: publishManyAction } = strapiAdmin$1.unstable_useDocumentActions();
781
+ const [isDraftRelationConfirmationOpen, setIsDraftRelationConfirmationOpen] = React__namespace.useState(false);
782
+ const { publishMany: publishManyAction, unpublishMany: unpublishManyAction } = strapiAdmin$1.unstable_useDocumentActions();
568
783
  const {
569
784
  document,
570
785
  meta: documentMeta,
571
786
  schema,
572
787
  validate
573
- } = strapiAdmin$1.unstable_useDocument({
574
- model,
575
- collectionType,
576
- documentId,
577
- params: {
578
- locale: baseLocale
788
+ } = strapiAdmin$1.unstable_useDocument(
789
+ {
790
+ model,
791
+ collectionType,
792
+ documentId,
793
+ params: {
794
+ locale: baseLocale
795
+ }
796
+ },
797
+ {
798
+ skip: !hasI18n || !baseLocale
579
799
  }
580
- });
581
- const { data: localesMetadata = [] } = useGetLocalesQuery();
800
+ );
801
+ const { data: localesMetadata = [] } = useGetLocalesQuery(hasI18n ? void 0 : query.skipToken);
582
802
  const headers = [
583
803
  {
584
804
  label: formatMessage({
@@ -627,12 +847,19 @@ const BulkLocalePublishAction = ({
627
847
  }, {});
628
848
  return [rowsFromMeta, errors];
629
849
  }, [document, documentMeta?.availableLocales, validate]);
630
- const localesToPublish = selectedRows.reduce((acc, selectedRow) => {
631
- if (selectedRow.status !== "published" && !Object.keys(validationErrors).includes(selectedRow.locale)) {
850
+ const isBulkPublish = action === "bulk-publish";
851
+ const localesForAction = selectedRows.reduce((acc, selectedRow) => {
852
+ const isValidLocale = (
853
+ // Validation errors are irrelevant if we are trying to unpublish
854
+ !isBulkPublish || !Object.keys(validationErrors).includes(selectedRow.locale)
855
+ );
856
+ const shouldAddLocale = isBulkPublish ? selectedRow.status !== "published" && isValidLocale : selectedRow.status !== "draft" && isValidLocale;
857
+ if (shouldAddLocale) {
632
858
  acc.push(selectedRow.locale);
633
859
  }
634
860
  return acc;
635
861
  }, []);
862
+ const enableDraftRelationsCount = false;
636
863
  const {
637
864
  data: draftRelationsCount = 0,
638
865
  isLoading: isDraftRelationsLoading,
@@ -641,10 +868,10 @@ const BulkLocalePublishAction = ({
641
868
  {
642
869
  model,
643
870
  documentIds: [documentId],
644
- locale: localesToPublish
871
+ locale: localesForAction
645
872
  },
646
873
  {
647
- skip: !documentId || localesToPublish.length === 0
874
+ skip: !enableDraftRelationsCount
648
875
  }
649
876
  );
650
877
  React__namespace.useEffect(() => {
@@ -670,23 +897,32 @@ const BulkLocalePublishAction = ({
670
897
  documentIds: [documentId],
671
898
  params: {
672
899
  ...params,
673
- locale: localesToPublish
900
+ locale: localesForAction
901
+ }
902
+ });
903
+ setSelectedRows([]);
904
+ };
905
+ const unpublish = async () => {
906
+ await unpublishManyAction({
907
+ model,
908
+ documentIds: [documentId],
909
+ params: {
910
+ ...params,
911
+ locale: localesForAction
674
912
  }
675
913
  });
676
914
  setSelectedRows([]);
677
915
  };
678
916
  const handleAction = async () => {
679
917
  if (draftRelationsCount > 0) {
680
- setIsConfirmationOpen(true);
681
- } else {
918
+ setIsDraftRelationConfirmationOpen(true);
919
+ } else if (isBulkPublish) {
682
920
  await publish();
921
+ } else {
922
+ await unpublish();
683
923
  }
684
924
  };
685
- const isUnpublish = document?.status === "published";
686
- if (isUnpublish) {
687
- console.warn(["I18N"], "Bulk locale unpublish modal not implemented");
688
- }
689
- if (isConfirmationOpen) {
925
+ if (isDraftRelationConfirmationOpen) {
690
926
  return {
691
927
  label: formatMessage({
692
928
  id: "app.components.ConfirmDialog.title",
@@ -695,11 +931,11 @@ const BulkLocalePublishAction = ({
695
931
  variant: "danger",
696
932
  dialog: {
697
933
  onCancel: () => {
698
- setIsConfirmationOpen(false);
934
+ setIsDraftRelationConfirmationOpen(false);
699
935
  },
700
936
  onConfirm: async () => {
701
937
  await publish();
702
- setIsConfirmationOpen(false);
938
+ setIsDraftRelationConfirmationOpen(false);
703
939
  },
704
940
  type: "dialog",
705
941
  title: formatMessage({
@@ -709,27 +945,32 @@ const BulkLocalePublishAction = ({
709
945
  content: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", alignItems: "center", gap: 2, children: [
710
946
  /* @__PURE__ */ jsxRuntime.jsx(icons.WarningCircle, { width: "2.4rem", height: "2.4rem", fill: "danger600" }),
711
947
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { textAlign: "center", children: formatMessage({
712
- id: "content-manager.actions.discard.dialog.body",
713
- defaultMessage: "Are you sure you want to discard the changes? This action is irreversible."
948
+ id: getTranslation("CMEditViewBulkLocale.draft-relation-warning"),
949
+ defaultMessage: "Some locales are related to draft entries. Publishing them could leave broken links in your app."
950
+ }) }),
951
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { textAlign: "center", children: formatMessage({
952
+ id: getTranslation("CMEditViewBulkLocale.continue-confirmation"),
953
+ defaultMessage: "Are you sure you want to continue?"
714
954
  }) })
715
955
  ] })
716
956
  }
717
957
  };
718
958
  }
959
+ const hasPermission = selectedRows.map(({ locale }) => locale).every((locale) => canPublish.includes(locale));
719
960
  return {
720
961
  label: formatMessage({
721
- id: getTranslation("CMEditViewBulkLocale.publish-title"),
722
- defaultMessage: "Publish Multiple Locales"
962
+ id: getTranslation(`CMEditViewBulkLocale.${isBulkPublish ? "publish" : "unpublish"}-title`),
963
+ defaultMessage: `${isBulkPublish ? "Publish" : "Unpublish"} Multiple Locales`
723
964
  }),
724
- icon: /* @__PURE__ */ jsxRuntime.jsx(icons.ListPlus, {}),
725
- disabled: isPublishedTab || !canPublish,
965
+ variant: isBulkPublish ? "secondary" : "danger",
966
+ icon: isBulkPublish ? /* @__PURE__ */ jsxRuntime.jsx(icons.ListPlus, {}) : /* @__PURE__ */ jsxRuntime.jsx(icons.Cross, {}),
967
+ disabled: isOnPublishedTab || canPublish.length === 0,
726
968
  position: ["panel"],
727
- variant: "secondary",
728
969
  dialog: {
729
970
  type: "modal",
730
971
  title: formatMessage({
731
- id: getTranslation("CMEditViewBulkLocale.publish-title"),
732
- defaultMessage: "Publish Multiple Locales"
972
+ id: getTranslation(`CMEditViewBulkLocale.${isBulkPublish ? "publish" : "unpublish"}-title`),
973
+ defaultMessage: `${isBulkPublish ? "Publish" : "Unpublish"} Multiple Locales`
733
974
  }),
734
975
  content: () => {
735
976
  return /* @__PURE__ */ jsxRuntime.jsx(
@@ -748,28 +989,35 @@ const BulkLocalePublishAction = ({
748
989
  validationErrors,
749
990
  headers,
750
991
  rows,
751
- localesMetadata
992
+ localesMetadata,
993
+ action: action ?? "bulk-publish"
752
994
  }
753
995
  )
754
996
  }
755
997
  );
756
998
  },
757
- footer: () => /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { justifyContent: "flex-end", children: /* @__PURE__ */ jsxRuntime.jsx(
999
+ footer: () => /* @__PURE__ */ jsxRuntime.jsx(designSystem.Modal.Footer, { justifyContent: "flex-end", children: /* @__PURE__ */ jsxRuntime.jsx(
758
1000
  designSystem.Button,
759
1001
  {
760
1002
  loading: isDraftRelationsLoading,
761
- disabled: localesToPublish.length === 0,
1003
+ disabled: !hasPermission || localesForAction.length === 0,
762
1004
  variant: "default",
763
1005
  onClick: handleAction,
764
1006
  children: formatMessage({
765
- id: "app.utils.publish",
766
- defaultMessage: "Publish"
1007
+ id: isBulkPublish ? "app.utils.publish" : "app.utils.unpublish",
1008
+ defaultMessage: isBulkPublish ? "Publish" : "Unpublish"
767
1009
  })
768
1010
  }
769
1011
  ) })
770
1012
  }
771
1013
  };
772
1014
  };
1015
+ const BulkLocalePublishAction = (props) => {
1016
+ return BulkLocaleAction({ action: "bulk-publish", ...props });
1017
+ };
1018
+ const BulkLocaleUnpublishAction = (props) => {
1019
+ return BulkLocaleAction({ action: "bulk-unpublish", ...props });
1020
+ };
773
1021
  const StyledTrash = styledComponents.styled(icons.Trash)`
774
1022
  path {
775
1023
  fill: currentColor;
@@ -826,16 +1074,9 @@ const UnpublishModalAdditionalInfo = () => {
826
1074
  }
827
1075
  ) });
828
1076
  };
829
- const Initializer = ({ setPlugin }) => {
830
- const setPluginRef = React__namespace.useRef(setPlugin);
831
- React__namespace.useEffect(() => {
832
- setPluginRef.current(pluginId);
833
- }, []);
834
- return null;
835
- };
836
1077
  const LocalePicker = () => {
837
1078
  const { formatMessage } = reactIntl.useIntl();
838
- const [{ query }, setQuery] = strapiAdmin.useQueryParams();
1079
+ const [{ query: query2 }, setQuery] = strapiAdmin.useQueryParams();
839
1080
  const { hasI18n, canRead, canCreate } = useI18n();
840
1081
  const { data: locales = [] } = useGetLocalesQuery(void 0, {
841
1082
  skip: !hasI18n
@@ -845,25 +1086,25 @@ const LocalePicker = () => {
845
1086
  setQuery(
846
1087
  {
847
1088
  page: 1,
848
- plugins: { ...query.plugins, i18n: { locale: code } }
1089
+ plugins: { ...query2.plugins, i18n: { locale: code } }
849
1090
  },
850
1091
  "push",
851
1092
  replace
852
1093
  );
853
1094
  },
854
- [query.plugins, setQuery]
1095
+ [query2.plugins, setQuery]
855
1096
  );
856
1097
  React__namespace.useEffect(() => {
857
1098
  if (!Array.isArray(locales) || !hasI18n) {
858
1099
  return;
859
1100
  }
860
- const currentDesiredLocale = query.plugins?.i18n?.locale;
1101
+ const currentDesiredLocale = query2.plugins?.i18n?.locale;
861
1102
  const doesLocaleExist = locales.find((loc) => loc.code === currentDesiredLocale);
862
1103
  const defaultLocale = locales.find((locale) => locale.isDefault);
863
1104
  if (!doesLocaleExist && defaultLocale?.code) {
864
1105
  handleChange(defaultLocale.code, true);
865
1106
  }
866
- }, [hasI18n, handleChange, locales, query.plugins?.i18n?.locale]);
1107
+ }, [hasI18n, handleChange, locales, query2.plugins?.i18n?.locale]);
867
1108
  if (!hasI18n || !Array.isArray(locales) || locales.length === 0) {
868
1109
  return null;
869
1110
  }
@@ -878,7 +1119,7 @@ const LocalePicker = () => {
878
1119
  id: getTranslation("actions.select-locale"),
879
1120
  defaultMessage: "Select locale"
880
1121
  }),
881
- value: query.plugins?.i18n?.locale || locales.find((locale) => locale.isDefault)?.code,
1122
+ value: query2.plugins?.i18n?.locale || locales.find((locale) => locale.isDefault)?.code,
882
1123
  onChange: handleChange,
883
1124
  children: displayedLocales.map((locale) => /* @__PURE__ */ jsxRuntime.jsx(designSystem.SingleSelectOption, { value: locale.code, children: locale.name }, locale.id))
884
1125
  }
@@ -996,54 +1237,13 @@ const LocaleListCell = ({
996
1237
  return locale.name;
997
1238
  }).toSorted((a, b) => formatter.compare(a, b));
998
1239
  return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Popover.Root, { children: [
999
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Popover.Trigger, { children: /* @__PURE__ */ jsxRuntime.jsx(Button, { type: "button", onClick: (e) => e.stopPropagation(), children: /* @__PURE__ */ jsxRuntime.jsxs(
1000
- ActionWrapper,
1001
- {
1002
- minWidth: "100%",
1003
- alignItems: "center",
1004
- justifyContent: "center",
1005
- height: "3.2rem",
1006
- width: "3.2rem",
1007
- children: [
1008
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { textColor: "neutral800", ellipsis: true, children: localesForDocument.join(", ") }),
1009
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { children: /* @__PURE__ */ jsxRuntime.jsx(icons.CaretDown, {}) })
1010
- ]
1011
- }
1012
- ) }) }),
1240
+ /* @__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: [
1241
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { textColor: "neutral800", ellipsis: true, marginRight: 2, children: localesForDocument.join(", ") }),
1242
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { children: /* @__PURE__ */ jsxRuntime.jsx(icons.CaretDown, { width: "1.2rem", height: "1.2rem" }) })
1243
+ ] }) }) }),
1013
1244
  /* @__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)) }) })
1014
1245
  ] });
1015
1246
  };
1016
- const Button = styledComponents.styled.button`
1017
- width: 100%;
1018
-
1019
- svg {
1020
- > g,
1021
- path {
1022
- fill: ${({ theme }) => theme.colors.neutral500};
1023
- }
1024
- }
1025
- &:hover {
1026
- svg {
1027
- > g,
1028
- path {
1029
- fill: ${({ theme }) => theme.colors.neutral600};
1030
- }
1031
- }
1032
- }
1033
- &:active {
1034
- svg {
1035
- > g,
1036
- path {
1037
- fill: ${({ theme }) => theme.colors.neutral400};
1038
- }
1039
- }
1040
- }
1041
- `;
1042
- const ActionWrapper = styledComponents.styled(designSystem.Flex)`
1043
- svg {
1044
- height: 0.4rem;
1045
- }
1046
- `;
1047
1247
  const addColumnToTableHook = ({ displayedHeaders, layout }) => {
1048
1248
  const { options } = layout;
1049
1249
  const isFieldLocalized = doesPluginOptionsHaveI18nLocalized(options) ? options.i18n.localized : false;
@@ -1072,18 +1272,11 @@ const addColumnToTableHook = ({ displayedHeaders, layout }) => {
1072
1272
  const addLocaleToReleasesHook = ({ displayedHeaders = [] }) => {
1073
1273
  return {
1074
1274
  displayedHeaders: [
1075
- // TODO: Fix when migrating to v5
1076
- // ...displayedHeaders,
1275
+ ...displayedHeaders,
1077
1276
  {
1078
- key: "__locale__",
1079
- fieldSchema: { type: "string" },
1080
- metadatas: {
1081
- label: {
1082
- id: "content-releases.page.ReleaseDetails.table.header.label.locale",
1083
- defaultMessage: "locale"
1084
- },
1085
- searchable: false,
1086
- sortable: false
1277
+ label: {
1278
+ id: "content-releases.page.ReleaseDetails.table.header.label.locale",
1279
+ defaultMessage: "locale"
1087
1280
  },
1088
1281
  name: "locale"
1089
1282
  }
@@ -1231,8 +1424,6 @@ const index = {
1231
1424
  app.addRBACMiddleware([localeMiddleware]);
1232
1425
  app.registerPlugin({
1233
1426
  id: pluginId,
1234
- initializer: Initializer,
1235
- isReady: false,
1236
1427
  name: pluginId
1237
1428
  });
1238
1429
  },
@@ -1250,11 +1441,11 @@ const index = {
1250
1441
  },
1251
1442
  id: "internationalization",
1252
1443
  to: "internationalization",
1253
- Component: () => Promise.resolve().then(() => require("./SettingsPage-VN7sTzkb.js")).then((mod) => ({ default: mod.ProtectedSettingsPage })),
1444
+ Component: () => Promise.resolve().then(() => require("./SettingsPage-CfTmCkup.js")).then((mod) => ({ default: mod.ProtectedSettingsPage })),
1254
1445
  permissions: PERMISSIONS.accessMain
1255
1446
  });
1256
1447
  const contentManager = app.getPlugin("content-manager");
1257
- contentManager.apis.addDocumentHeaderAction([LocalePickerAction]);
1448
+ contentManager.apis.addDocumentHeaderAction([LocalePickerAction, FillFromAnotherLocaleAction]);
1258
1449
  contentManager.apis.addDocumentAction((actions) => {
1259
1450
  const indexOfDeleteAction = actions.findIndex((action) => action.type === "delete");
1260
1451
  actions.splice(indexOfDeleteAction, 0, DeleteLocaleAction);
@@ -1262,6 +1453,7 @@ const index = {
1262
1453
  });
1263
1454
  contentManager.apis.addDocumentAction((actions) => {
1264
1455
  actions.splice(2, 0, BulkLocalePublishAction);
1456
+ actions.splice(5, 0, BulkLocaleUnpublishAction);
1265
1457
  return actions;
1266
1458
  });
1267
1459
  contentManager.injectComponent("listView", "actions", {
@@ -1367,7 +1559,7 @@ const index = {
1367
1559
  async registerTrads({ locales }) {
1368
1560
  const importedTrads = await Promise.all(
1369
1561
  locales.map((locale) => {
1370
- 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-Kv6y9zPQ.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 }) => {
1562
+ 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-DWpfm8h5.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 }) => {
1371
1563
  return {
1372
1564
  data: prefixPluginTranslations(data, pluginId),
1373
1565
  locale
@@ -1391,4 +1583,4 @@ exports.useDeleteLocaleMutation = useDeleteLocaleMutation;
1391
1583
  exports.useGetDefaultLocalesQuery = useGetDefaultLocalesQuery;
1392
1584
  exports.useGetLocalesQuery = useGetLocalesQuery;
1393
1585
  exports.useUpdateLocaleMutation = useUpdateLocaleMutation;
1394
- //# sourceMappingURL=index-kedPlCo6.js.map
1586
+ //# sourceMappingURL=index-5XLZwzwx.js.map