@strapi/i18n 0.0.0-experimental.145e7d7ddefd1aef71aaf3d9bb86440d013035bf

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 (165) hide show
  1. package/LICENSE +37 -0
  2. package/README.md +17 -0
  3. package/dist/_chunks/SettingsPage-C-1h_H38.js +574 -0
  4. package/dist/_chunks/SettingsPage-C-1h_H38.js.map +1 -0
  5. package/dist/_chunks/SettingsPage-CPNFX0bZ.mjs +554 -0
  6. package/dist/_chunks/SettingsPage-CPNFX0bZ.mjs.map +1 -0
  7. package/dist/_chunks/de-9eCAqqrB.mjs +66 -0
  8. package/dist/_chunks/de-9eCAqqrB.mjs.map +1 -0
  9. package/dist/_chunks/de-DtWiGdHl.js +66 -0
  10. package/dist/_chunks/de-DtWiGdHl.js.map +1 -0
  11. package/dist/_chunks/dk-2qBjxt-P.mjs +66 -0
  12. package/dist/_chunks/dk-2qBjxt-P.mjs.map +1 -0
  13. package/dist/_chunks/dk-D8C-casx.js +66 -0
  14. package/dist/_chunks/dk-D8C-casx.js.map +1 -0
  15. package/dist/_chunks/en-CtekP_47.mjs +75 -0
  16. package/dist/_chunks/en-CtekP_47.mjs.map +1 -0
  17. package/dist/_chunks/en-CwI88-PP.js +75 -0
  18. package/dist/_chunks/en-CwI88-PP.js.map +1 -0
  19. package/dist/_chunks/es-DS-XFGSw.js +66 -0
  20. package/dist/_chunks/es-DS-XFGSw.js.map +1 -0
  21. package/dist/_chunks/es-DlmMVaBG.mjs +66 -0
  22. package/dist/_chunks/es-DlmMVaBG.mjs.map +1 -0
  23. package/dist/_chunks/fr-3S6ke71d.mjs +66 -0
  24. package/dist/_chunks/fr-3S6ke71d.mjs.map +1 -0
  25. package/dist/_chunks/fr-BTjekDpq.js +66 -0
  26. package/dist/_chunks/fr-BTjekDpq.js.map +1 -0
  27. package/dist/_chunks/index-CgjpU2bY.mjs +1391 -0
  28. package/dist/_chunks/index-CgjpU2bY.mjs.map +1 -0
  29. package/dist/_chunks/index-jpk39Rxo.js +1413 -0
  30. package/dist/_chunks/index-jpk39Rxo.js.map +1 -0
  31. package/dist/_chunks/ko-DmcGUBQ3.js +65 -0
  32. package/dist/_chunks/ko-DmcGUBQ3.js.map +1 -0
  33. package/dist/_chunks/ko-qTjQ8IMw.mjs +65 -0
  34. package/dist/_chunks/ko-qTjQ8IMw.mjs.map +1 -0
  35. package/dist/_chunks/pl-B67TSHqT.mjs +66 -0
  36. package/dist/_chunks/pl-B67TSHqT.mjs.map +1 -0
  37. package/dist/_chunks/pl-Cn5RYonZ.js +66 -0
  38. package/dist/_chunks/pl-Cn5RYonZ.js.map +1 -0
  39. package/dist/_chunks/ru-BMBgVL3s.js +68 -0
  40. package/dist/_chunks/ru-BMBgVL3s.js.map +1 -0
  41. package/dist/_chunks/ru-hagMa57T.mjs +68 -0
  42. package/dist/_chunks/ru-hagMa57T.mjs.map +1 -0
  43. package/dist/_chunks/tr-CarUU76c.js +66 -0
  44. package/dist/_chunks/tr-CarUU76c.js.map +1 -0
  45. package/dist/_chunks/tr-Dw_jmkG-.mjs +66 -0
  46. package/dist/_chunks/tr-Dw_jmkG-.mjs.map +1 -0
  47. package/dist/_chunks/zh-57YM4amO.mjs +66 -0
  48. package/dist/_chunks/zh-57YM4amO.mjs.map +1 -0
  49. package/dist/_chunks/zh-CukOviB0.js +66 -0
  50. package/dist/_chunks/zh-CukOviB0.js.map +1 -0
  51. package/dist/_chunks/zh-Hans-DSHIXAa3.js +57 -0
  52. package/dist/_chunks/zh-Hans-DSHIXAa3.js.map +1 -0
  53. package/dist/_chunks/zh-Hans-Dyc-aR-h.mjs +57 -0
  54. package/dist/_chunks/zh-Hans-Dyc-aR-h.mjs.map +1 -0
  55. package/dist/admin/index.js +6 -0
  56. package/dist/admin/index.js.map +1 -0
  57. package/dist/admin/index.mjs +7 -0
  58. package/dist/admin/index.mjs.map +1 -0
  59. package/dist/admin/src/components/BulkLocaleActionModal.d.ts +16 -0
  60. package/dist/admin/src/components/CMHeaderActions.d.ts +11 -0
  61. package/dist/admin/src/components/CMListViewModalsAdditionalInformation.d.ts +4 -0
  62. package/dist/admin/src/components/CheckboxConfirmation.d.ts +20 -0
  63. package/dist/admin/src/components/CreateLocale.d.ts +29 -0
  64. package/dist/admin/src/components/DeleteLocale.d.ts +5 -0
  65. package/dist/admin/src/components/EditLocale.d.ts +14 -0
  66. package/dist/admin/src/components/LocaleListCell.d.ts +9 -0
  67. package/dist/admin/src/components/LocalePicker.d.ts +2 -0
  68. package/dist/admin/src/components/LocaleTable.d.ts +11 -0
  69. package/dist/admin/src/constants.d.ts +22 -0
  70. package/dist/admin/src/contentManagerHooks/editView.d.ts +6 -0
  71. package/dist/admin/src/contentManagerHooks/listView.d.ts +22 -0
  72. package/dist/admin/src/contentReleasesHooks/releaseDetailsView.d.ts +40 -0
  73. package/dist/admin/src/hooks/useI18n.d.ts +16 -0
  74. package/dist/admin/src/index.d.ts +16 -0
  75. package/dist/admin/src/middlewares/extendCTBAttributeInitialData.d.ts +4 -0
  76. package/dist/admin/src/middlewares/extendCTBInitialData.d.ts +4 -0
  77. package/dist/admin/src/middlewares/rbac-middleware.d.ts +3 -0
  78. package/dist/admin/src/pages/SettingsPage.d.ts +3 -0
  79. package/dist/admin/src/pluginId.d.ts +1 -0
  80. package/dist/admin/src/services/api.d.ts +2 -0
  81. package/dist/admin/src/services/locales.d.ts +4 -0
  82. package/dist/admin/src/services/relations.d.ts +7 -0
  83. package/dist/admin/src/types.d.ts +9 -0
  84. package/dist/admin/src/utils/baseQuery.d.ts +5 -0
  85. package/dist/admin/src/utils/fields.d.ts +7 -0
  86. package/dist/admin/src/utils/getTranslation.d.ts +2 -0
  87. package/dist/admin/src/utils/prefixPluginTranslations.d.ts +3 -0
  88. package/dist/admin/src/utils/schemas.d.ts +25 -0
  89. package/dist/admin/src/utils/strings.d.ts +2 -0
  90. package/dist/server/index.js +3551 -0
  91. package/dist/server/index.js.map +1 -0
  92. package/dist/server/index.mjs +3532 -0
  93. package/dist/server/index.mjs.map +1 -0
  94. package/dist/server/src/bootstrap.d.ts +6 -0
  95. package/dist/server/src/bootstrap.d.ts.map +1 -0
  96. package/dist/server/src/constants/index.d.ts +15 -0
  97. package/dist/server/src/constants/index.d.ts.map +1 -0
  98. package/dist/server/src/content-types/index.d.ts +37 -0
  99. package/dist/server/src/content-types/index.d.ts.map +1 -0
  100. package/dist/server/src/content-types/locale/index.d.ts +35 -0
  101. package/dist/server/src/content-types/locale/index.d.ts.map +1 -0
  102. package/dist/server/src/controllers/content-types.d.ts +6 -0
  103. package/dist/server/src/controllers/content-types.d.ts.map +1 -0
  104. package/dist/server/src/controllers/index.d.ts +10 -0
  105. package/dist/server/src/controllers/index.d.ts.map +1 -0
  106. package/dist/server/src/controllers/iso-locales.d.ts +4 -0
  107. package/dist/server/src/controllers/iso-locales.d.ts.map +1 -0
  108. package/dist/server/src/controllers/locales.d.ts +4 -0
  109. package/dist/server/src/controllers/locales.d.ts.map +1 -0
  110. package/dist/server/src/controllers/validate-locale-creation.d.ts +4 -0
  111. package/dist/server/src/controllers/validate-locale-creation.d.ts.map +1 -0
  112. package/dist/server/src/domain/locale.d.ts +11 -0
  113. package/dist/server/src/domain/locale.d.ts.map +1 -0
  114. package/dist/server/src/graphql.d.ts +8 -0
  115. package/dist/server/src/graphql.d.ts.map +1 -0
  116. package/dist/server/src/index.d.ts +160 -0
  117. package/dist/server/src/index.d.ts.map +1 -0
  118. package/dist/server/src/migrations/content-type/disable/index.d.ts +3 -0
  119. package/dist/server/src/migrations/content-type/disable/index.d.ts.map +1 -0
  120. package/dist/server/src/migrations/content-type/enable/index.d.ts +3 -0
  121. package/dist/server/src/migrations/content-type/enable/index.d.ts.map +1 -0
  122. package/dist/server/src/register.d.ts +6 -0
  123. package/dist/server/src/register.d.ts.map +1 -0
  124. package/dist/server/src/routes/admin.d.ts +18 -0
  125. package/dist/server/src/routes/admin.d.ts.map +1 -0
  126. package/dist/server/src/routes/content-api.d.ts +10 -0
  127. package/dist/server/src/routes/content-api.d.ts.map +1 -0
  128. package/dist/server/src/routes/index.d.ts +28 -0
  129. package/dist/server/src/routes/index.d.ts.map +1 -0
  130. package/dist/server/src/services/content-types.d.ts +13 -0
  131. package/dist/server/src/services/content-types.d.ts.map +1 -0
  132. package/dist/server/src/services/entity-service-decorator.d.ts +29 -0
  133. package/dist/server/src/services/entity-service-decorator.d.ts.map +1 -0
  134. package/dist/server/src/services/index.d.ts +83 -0
  135. package/dist/server/src/services/index.d.ts.map +1 -0
  136. package/dist/server/src/services/iso-locales.d.ts +10 -0
  137. package/dist/server/src/services/iso-locales.d.ts.map +1 -0
  138. package/dist/server/src/services/locales.d.ts +17 -0
  139. package/dist/server/src/services/locales.d.ts.map +1 -0
  140. package/dist/server/src/services/localizations.d.ts +8 -0
  141. package/dist/server/src/services/localizations.d.ts.map +1 -0
  142. package/dist/server/src/services/metrics.d.ts +8 -0
  143. package/dist/server/src/services/metrics.d.ts.map +1 -0
  144. package/dist/server/src/services/permissions/actions.d.ts +28 -0
  145. package/dist/server/src/services/permissions/actions.d.ts.map +1 -0
  146. package/dist/server/src/services/permissions/conditions.d.ts +15 -0
  147. package/dist/server/src/services/permissions/conditions.d.ts.map +1 -0
  148. package/dist/server/src/services/permissions/engine.d.ts +6 -0
  149. package/dist/server/src/services/permissions/engine.d.ts.map +1 -0
  150. package/dist/server/src/services/permissions/sections-builder.d.ts +6 -0
  151. package/dist/server/src/services/permissions/sections-builder.d.ts.map +1 -0
  152. package/dist/server/src/services/permissions.d.ts +40 -0
  153. package/dist/server/src/services/permissions.d.ts.map +1 -0
  154. package/dist/server/src/utils/index.d.ts +43 -0
  155. package/dist/server/src/utils/index.d.ts.map +1 -0
  156. package/dist/server/src/validation/content-types.d.ts +3 -0
  157. package/dist/server/src/validation/content-types.d.ts.map +1 -0
  158. package/dist/server/src/validation/locales.d.ts +12 -0
  159. package/dist/server/src/validation/locales.d.ts.map +1 -0
  160. package/dist/shared/contracts/content-manager.d.ts +46 -0
  161. package/dist/shared/contracts/iso-locales.d.ts +21 -0
  162. package/dist/shared/contracts/locales.d.ts +77 -0
  163. package/dist/shared/contracts/shared.d.ts +6 -0
  164. package/package.json +100 -0
  165. package/strapi-server.js +3 -0
@@ -0,0 +1,1391 @@
1
+ import get from "lodash/get";
2
+ import * as yup from "yup";
3
+ import { jsxs, jsx } from "react/jsx-runtime";
4
+ import * as React from "react";
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, ListPlus, Cross, Earth, EarthStriked, CaretDown } from "@strapi/icons";
7
+ import { useIntl } from "react-intl";
8
+ import { styled } from "styled-components";
9
+ import { skipToken } from "@reduxjs/toolkit/query";
10
+ import { useAuth, adminApi, useTable, Table, useQueryParams, useNotification, useAPIErrorHandler } from "@strapi/admin/strapi-admin";
11
+ import { unstable_useDocument, unstable_useDocumentActions, buildValidParams } from "@strapi/content-manager/strapi-admin";
12
+ import { useParams, Link, useNavigate, matchPath } from "react-router-dom";
13
+ import * as qs from "qs";
14
+ import { stringify } from "qs";
15
+ import omit from "lodash/omit";
16
+ const __variableDynamicImportRuntimeHelper = (glob, path) => {
17
+ const v = glob[path];
18
+ if (v) {
19
+ return typeof v === "function" ? v() : Promise.resolve(v);
20
+ }
21
+ return new Promise((_, reject) => {
22
+ (typeof queueMicrotask === "function" ? queueMicrotask : setTimeout)(reject.bind(null, new Error("Unknown variable dynamic import: " + path)));
23
+ });
24
+ };
25
+ const pluginId = "i18n";
26
+ const getTranslation = (id) => `${pluginId}.${id}`;
27
+ const TextAlignTypography = styled(Typography)`
28
+ text-align: center;
29
+ `;
30
+ const CheckboxConfirmation = ({
31
+ description,
32
+ isCreating = false,
33
+ intlLabel,
34
+ name,
35
+ onChange,
36
+ value
37
+ }) => {
38
+ const { formatMessage } = useIntl();
39
+ const [isOpen, setIsOpen] = React.useState(false);
40
+ const handleChange = (value2) => {
41
+ if (isCreating || value2) {
42
+ return onChange({ target: { name, value: value2, type: "checkbox" } });
43
+ }
44
+ if (!value2) {
45
+ return setIsOpen(true);
46
+ }
47
+ return null;
48
+ };
49
+ const handleConfirm = () => {
50
+ onChange({ target: { name, value: false, type: "checkbox" } });
51
+ };
52
+ const label = intlLabel.id ? formatMessage(
53
+ { id: intlLabel.id, defaultMessage: intlLabel.defaultMessage },
54
+ { ...intlLabel.values }
55
+ ) : name;
56
+ const hint = description ? formatMessage(
57
+ { id: description.id, defaultMessage: description.defaultMessage },
58
+ { ...description.values }
59
+ ) : "";
60
+ return /* @__PURE__ */ jsxs(Dialog.Root, { open: isOpen, onOpenChange: setIsOpen, children: [
61
+ /* @__PURE__ */ jsxs(Field.Root, { hint, name, children: [
62
+ /* @__PURE__ */ jsx(Checkbox, { onCheckedChange: handleChange, checked: value, children: label }),
63
+ /* @__PURE__ */ jsx(Field.Hint, {})
64
+ ] }),
65
+ /* @__PURE__ */ jsxs(Dialog.Content, { children: [
66
+ /* @__PURE__ */ jsx(Dialog.Header, { children: formatMessage({
67
+ id: getTranslation("CheckboxConfirmation.Modal.title"),
68
+ defaultMessage: "Disable localization"
69
+ }) }),
70
+ /* @__PURE__ */ jsx(Dialog.Body, { icon: /* @__PURE__ */ jsx(WarningCircle, {}), children: /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "stretch", gap: 2, children: [
71
+ /* @__PURE__ */ jsx(Flex, { justifyContent: "center", children: /* @__PURE__ */ jsx(TextAlignTypography, { children: formatMessage({
72
+ id: getTranslation("CheckboxConfirmation.Modal.content"),
73
+ defaultMessage: "Disabling localization will engender the deletion of all your content but the one associated to your default locale (if existing)."
74
+ }) }) }),
75
+ /* @__PURE__ */ jsx(Flex, { justifyContent: "center", children: /* @__PURE__ */ jsx(Typography, { fontWeight: "semiBold", children: formatMessage({
76
+ id: getTranslation("CheckboxConfirmation.Modal.body"),
77
+ defaultMessage: "Do you want to disable it?"
78
+ }) }) })
79
+ ] }) }),
80
+ /* @__PURE__ */ jsxs(Dialog.Footer, { children: [
81
+ /* @__PURE__ */ jsx(Dialog.Cancel, { children: /* @__PURE__ */ jsx(Button, { variant: "tertiary", children: formatMessage({
82
+ id: "components.popUpWarning.button.cancel",
83
+ defaultMessage: "No, cancel"
84
+ }) }) }),
85
+ /* @__PURE__ */ jsx(Dialog.Action, { children: /* @__PURE__ */ jsx(Button, { variant: "danger-light", onClick: handleConfirm, children: formatMessage({
86
+ id: getTranslation("CheckboxConfirmation.Modal.button-confirm"),
87
+ defaultMessage: "Yes, disable"
88
+ }) }) })
89
+ ] })
90
+ ] })
91
+ ] });
92
+ };
93
+ const LOCALIZED_FIELDS = [
94
+ "biginteger",
95
+ "boolean",
96
+ "component",
97
+ "date",
98
+ "datetime",
99
+ "decimal",
100
+ "dynamiczone",
101
+ "email",
102
+ "enumeration",
103
+ "float",
104
+ "integer",
105
+ "json",
106
+ "media",
107
+ "number",
108
+ "password",
109
+ "richtext",
110
+ "blocks",
111
+ "string",
112
+ "text",
113
+ "time"
114
+ ];
115
+ const doesPluginOptionsHaveI18nLocalized = (opts) => typeof opts === "object" && opts !== null && "i18n" in opts && typeof opts.i18n === "object" && opts.i18n !== null && "localized" in opts.i18n && typeof opts.i18n.localized === "boolean";
116
+ const capitalize = (str) => str.charAt(0).toUpperCase() + str.slice(1);
117
+ const useI18n = () => {
118
+ const params = useParams();
119
+ const userPermissions = useAuth("useI18n", (state) => state.permissions);
120
+ const actions = React.useMemo(() => {
121
+ const permissions = userPermissions.filter((permission) => permission.subject === params.slug);
122
+ return permissions.reduce(
123
+ (acc, permission) => {
124
+ const [actionShorthand] = permission.action.split(".").slice(-1);
125
+ return {
126
+ ...acc,
127
+ [`can${capitalize(actionShorthand)}`]: permission.properties?.locales ?? []
128
+ };
129
+ },
130
+ { canCreate: [], canRead: [], canUpdate: [], canDelete: [], canPublish: [] }
131
+ );
132
+ }, [params.slug, userPermissions]);
133
+ const { schema } = unstable_useDocument(
134
+ {
135
+ // We can non-null assert these because below we skip the query if they are not present
136
+ collectionType: params.collectionType,
137
+ model: params.slug
138
+ },
139
+ {
140
+ skip: true
141
+ }
142
+ );
143
+ if (doesPluginOptionsHaveI18nLocalized(schema?.pluginOptions)) {
144
+ return {
145
+ hasI18n: schema.pluginOptions.i18n.localized,
146
+ ...actions
147
+ };
148
+ }
149
+ return {
150
+ hasI18n: false,
151
+ ...actions
152
+ };
153
+ };
154
+ const i18nApi = adminApi.enhanceEndpoints({
155
+ addTagTypes: ["Locale"]
156
+ });
157
+ const localesApi = i18nApi.injectEndpoints({
158
+ endpoints: (builder) => ({
159
+ createLocale: builder.mutation({
160
+ query: (data) => ({
161
+ url: "/i18n/locales",
162
+ method: "POST",
163
+ data
164
+ }),
165
+ invalidatesTags: [{ type: "Locale", id: "LIST" }]
166
+ }),
167
+ deleteLocale: builder.mutation({
168
+ query: (id) => ({
169
+ url: `/i18n/locales/${id}`,
170
+ method: "DELETE"
171
+ }),
172
+ invalidatesTags: (result, error, id) => [{ type: "Locale", id }]
173
+ }),
174
+ getLocales: builder.query({
175
+ query: () => "/i18n/locales",
176
+ providesTags: (res) => [
177
+ { type: "Locale", id: "LIST" },
178
+ ...Array.isArray(res) ? res.map((locale) => ({
179
+ type: "Locale",
180
+ id: locale.id
181
+ })) : []
182
+ ]
183
+ }),
184
+ getDefaultLocales: builder.query({
185
+ query: () => "/i18n/iso-locales"
186
+ }),
187
+ updateLocale: builder.mutation({
188
+ query: ({ id, ...data }) => ({
189
+ url: `/i18n/locales/${id}`,
190
+ method: "PUT",
191
+ data
192
+ }),
193
+ invalidatesTags: (result, error, { id }) => [{ type: "Locale", id }]
194
+ })
195
+ })
196
+ });
197
+ const {
198
+ useCreateLocaleMutation,
199
+ useDeleteLocaleMutation,
200
+ useGetLocalesQuery,
201
+ useGetDefaultLocalesQuery,
202
+ useUpdateLocaleMutation
203
+ } = localesApi;
204
+ const relationsApi = i18nApi.injectEndpoints({
205
+ overrideExisting: true,
206
+ endpoints: (builder) => ({
207
+ getManyDraftRelationCount: builder.query({
208
+ query: ({ model, ...params }) => ({
209
+ url: `/content-manager/collection-types/${model}/actions/countManyEntriesDraftRelations`,
210
+ method: "GET",
211
+ config: {
212
+ params
213
+ }
214
+ }),
215
+ transformResponse: (response) => response.data
216
+ })
217
+ })
218
+ });
219
+ const { useGetManyDraftRelationCountQuery } = relationsApi;
220
+ const isErrorMessageDescriptor = (object) => {
221
+ return typeof object === "object" && object !== null && "id" in object && "defaultMessage" in object;
222
+ };
223
+ const EntryValidationText = ({
224
+ status = "draft",
225
+ validationErrors,
226
+ action
227
+ }) => {
228
+ const { formatMessage } = useIntl();
229
+ const getErrorStr = (key, value) => {
230
+ if (typeof value === "string") {
231
+ return `${key}: ${value}`;
232
+ } else if (isErrorMessageDescriptor(value)) {
233
+ return `${key}: ${formatMessage(value)}`;
234
+ } else if (Array.isArray(value)) {
235
+ return value.map((v) => getErrorStr(key, v)).join(" ");
236
+ } else if (typeof value === "object" && !Array.isArray(value)) {
237
+ return Object.entries(value).map(([k, v]) => getErrorStr(k, v)).join(" ");
238
+ } else {
239
+ return "";
240
+ }
241
+ };
242
+ if (validationErrors) {
243
+ const validationErrorsMessages = Object.entries(validationErrors).map(([key, value]) => {
244
+ return getErrorStr(key, value);
245
+ }).join(" ");
246
+ return /* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
247
+ /* @__PURE__ */ jsx(CrossCircle, { fill: "danger600" }),
248
+ /* @__PURE__ */ jsx(Tooltip, { label: validationErrorsMessages, children: /* @__PURE__ */ jsx(
249
+ Typography,
250
+ {
251
+ maxWidth: "30rem",
252
+ textColor: "danger600",
253
+ variant: "omega",
254
+ fontWeight: "semiBold",
255
+ ellipsis: true,
256
+ children: validationErrorsMessages
257
+ }
258
+ ) })
259
+ ] });
260
+ }
261
+ const getStatusMessage = () => {
262
+ if (action === "bulk-publish") {
263
+ if (status === "published") {
264
+ return {
265
+ icon: /* @__PURE__ */ jsx(CheckCircle, { fill: "success600" }),
266
+ text: formatMessage({
267
+ id: "content-manager.bulk-publish.already-published",
268
+ defaultMessage: "Already Published"
269
+ }),
270
+ textColor: "success600",
271
+ fontWeight: "bold"
272
+ };
273
+ } else if (status === "modified") {
274
+ return {
275
+ icon: /* @__PURE__ */ jsx(ArrowsCounterClockwise, { fill: "alternative600" }),
276
+ text: formatMessage({
277
+ id: "app.utils.ready-to-publish-changes",
278
+ defaultMessage: "Ready to publish changes"
279
+ })
280
+ };
281
+ } else {
282
+ return {
283
+ icon: /* @__PURE__ */ jsx(CheckCircle, { fill: "success600" }),
284
+ text: formatMessage({
285
+ id: "app.utils.ready-to-publish",
286
+ defaultMessage: "Ready to publish"
287
+ })
288
+ };
289
+ }
290
+ } else {
291
+ if (status === "draft") {
292
+ return {
293
+ icon: /* @__PURE__ */ jsx(CheckCircle, { fill: "success600" }),
294
+ text: formatMessage({
295
+ id: "content-manager.bulk-unpublish.already-unpublished",
296
+ defaultMessage: "Already Unpublished"
297
+ }),
298
+ textColor: "success600",
299
+ fontWeight: "bold"
300
+ };
301
+ } else {
302
+ return {
303
+ icon: /* @__PURE__ */ jsx(CheckCircle, { fill: "success600" }),
304
+ text: formatMessage({
305
+ id: "app.utils.ready-to-unpublish-changes",
306
+ defaultMessage: "Ready to unpublish"
307
+ }),
308
+ textColor: "success600",
309
+ fontWeight: "bold"
310
+ };
311
+ }
312
+ }
313
+ };
314
+ const { icon, text, textColor = "success600", fontWeight = "normal" } = getStatusMessage();
315
+ return /* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
316
+ icon,
317
+ /* @__PURE__ */ jsx(Typography, { textColor, fontWeight, children: text })
318
+ ] });
319
+ };
320
+ const BoldChunk = (chunks) => /* @__PURE__ */ jsx(Typography, { fontWeight: "bold", children: chunks });
321
+ const BulkLocaleActionModal = ({
322
+ headers,
323
+ rows,
324
+ localesMetadata,
325
+ validationErrors = {},
326
+ action
327
+ }) => {
328
+ const { formatMessage } = useIntl();
329
+ const selectedRows = useTable(
330
+ "BulkLocaleActionModal",
331
+ (state) => state.selectedRows
332
+ );
333
+ const getFormattedCountMessage = () => {
334
+ const currentStatusByLocale = rows.reduce((acc, { locale, status }) => {
335
+ acc[locale] = status;
336
+ return acc;
337
+ }, {});
338
+ const localesWithErrors = Object.keys(validationErrors);
339
+ const publishedCount = selectedRows.filter(
340
+ ({ locale }) => currentStatusByLocale[locale] === "published"
341
+ ).length;
342
+ const draftCount = selectedRows.filter(
343
+ ({ locale }) => (currentStatusByLocale[locale] === "draft" || currentStatusByLocale[locale] === "modified") && !localesWithErrors.includes(locale)
344
+ ).length;
345
+ const withErrorsCount = localesWithErrors.length;
346
+ const messageId = action === "bulk-publish" ? "content-manager.containers.list.selectedEntriesModal.selectedCount.publish" : "content-manager.containers.list.selectedEntriesModal.selectedCount.unpublish";
347
+ 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.";
348
+ return formatMessage(
349
+ {
350
+ id: messageId,
351
+ defaultMessage
352
+ },
353
+ {
354
+ withErrorsCount,
355
+ draftCount,
356
+ publishedCount,
357
+ b: BoldChunk
358
+ }
359
+ );
360
+ };
361
+ return /* @__PURE__ */ jsxs(Modal.Body, { children: [
362
+ /* @__PURE__ */ jsx(Typography, { children: getFormattedCountMessage() }),
363
+ /* @__PURE__ */ jsx(Box, { marginTop: 5, children: /* @__PURE__ */ jsxs(Table.Content, { children: [
364
+ /* @__PURE__ */ jsxs(Table.Head, { children: [
365
+ /* @__PURE__ */ jsx(Table.HeaderCheckboxCell, {}),
366
+ headers.map((head) => /* @__PURE__ */ jsx(Table.HeaderCell, { ...head }, head.name))
367
+ ] }),
368
+ /* @__PURE__ */ jsx(Table.Body, { children: rows.map(({ locale, status }, index2) => {
369
+ const error = validationErrors?.[locale] ?? null;
370
+ const statusVariant = status === "draft" ? "primary" : status === "published" ? "success" : "alternative";
371
+ return /* @__PURE__ */ jsxs(Table.Row, { children: [
372
+ /* @__PURE__ */ jsx(Table.CheckboxCell, { id: locale, "aria-label": `Select ${locale}` }),
373
+ /* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsx(Typography, { variant: "sigma", textColor: "neutral600", children: Array.isArray(localesMetadata) ? localesMetadata.find((localeEntry) => localeEntry.code === locale)?.name : locale }) }),
374
+ /* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsx(Box, { display: "flex", children: /* @__PURE__ */ jsx(
375
+ Status,
376
+ {
377
+ display: "flex",
378
+ paddingLeft: "6px",
379
+ paddingRight: "6px",
380
+ paddingTop: "2px",
381
+ paddingBottom: "2px",
382
+ showBullet: false,
383
+ size: "S",
384
+ variant: statusVariant,
385
+ children: /* @__PURE__ */ jsx(Typography, { tag: "span", variant: "pi", fontWeight: "bold", children: capitalize(status) })
386
+ }
387
+ ) }) }),
388
+ /* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsx(EntryValidationText, { validationErrors: error, status, action }) }),
389
+ /* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsx(
390
+ IconButton,
391
+ {
392
+ tag: Link,
393
+ to: {
394
+ search: stringify({ plugins: { i18n: { locale } } })
395
+ },
396
+ label: formatMessage(
397
+ {
398
+ id: getTranslation("Settings.list.actions.edit"),
399
+ defaultMessage: "Edit {name} locale"
400
+ },
401
+ {
402
+ name: locale
403
+ }
404
+ ),
405
+ variant: "ghost",
406
+ children: /* @__PURE__ */ jsx(Pencil, {})
407
+ }
408
+ ) })
409
+ ] }, index2);
410
+ }) })
411
+ ] }) })
412
+ ] });
413
+ };
414
+ const LocalePickerAction = ({
415
+ document,
416
+ meta,
417
+ model,
418
+ collectionType,
419
+ documentId
420
+ }) => {
421
+ const { formatMessage } = useIntl();
422
+ const [{ query }, setQuery] = useQueryParams();
423
+ const { hasI18n, canCreate, canRead } = useI18n();
424
+ const { data: locales = [] } = useGetLocalesQuery();
425
+ const { schema } = unstable_useDocument({ model, collectionType, documentId });
426
+ const handleSelect = React.useCallback(
427
+ (value) => {
428
+ setQuery({
429
+ plugins: {
430
+ ...query.plugins,
431
+ i18n: {
432
+ locale: value
433
+ }
434
+ }
435
+ });
436
+ },
437
+ [query.plugins, setQuery]
438
+ );
439
+ React.useEffect(() => {
440
+ if (!Array.isArray(locales) || !hasI18n) {
441
+ return;
442
+ }
443
+ const currentDesiredLocale = query.plugins?.i18n?.locale;
444
+ const doesLocaleExist = locales.find((loc) => loc.code === currentDesiredLocale);
445
+ const defaultLocale = locales.find((locale) => locale.isDefault);
446
+ if (!doesLocaleExist && defaultLocale?.code) {
447
+ handleSelect(defaultLocale.code);
448
+ }
449
+ }, [handleSelect, hasI18n, locales, query.plugins?.i18n?.locale]);
450
+ if (!hasI18n || !Array.isArray(locales) || locales.length === 0) {
451
+ return null;
452
+ }
453
+ const currentLocale = query.plugins?.i18n?.locale || locales.find((loc) => loc.isDefault)?.code;
454
+ const allCurrentLocales = [
455
+ { status: getDocumentStatus(document, meta), locale: currentLocale },
456
+ ...meta?.availableLocales ?? []
457
+ ];
458
+ return {
459
+ label: formatMessage({
460
+ id: getTranslation("Settings.locales.modal.locales.label"),
461
+ defaultMessage: "Locales"
462
+ }),
463
+ options: locales.map((locale) => {
464
+ const currentLocaleDoc = allCurrentLocales.find(
465
+ (doc) => "locale" in doc ? doc.locale === locale.code : false
466
+ );
467
+ const status = currentLocaleDoc?.status ?? "draft";
468
+ const permissionsToCheck = currentLocaleDoc ? canCreate : canRead;
469
+ const statusVariant = status === "draft" ? "primary" : status === "published" ? "success" : "alternative";
470
+ return {
471
+ disabled: !permissionsToCheck.includes(locale.code),
472
+ value: locale.code,
473
+ label: locale.name,
474
+ startIcon: schema?.options?.draftAndPublish ? /* @__PURE__ */ jsx(
475
+ Status,
476
+ {
477
+ display: "flex",
478
+ paddingLeft: "6px",
479
+ paddingRight: "6px",
480
+ paddingTop: "2px",
481
+ paddingBottom: "2px",
482
+ showBullet: false,
483
+ size: "S",
484
+ variant: statusVariant,
485
+ children: /* @__PURE__ */ jsx(Typography, { tag: "span", variant: "pi", fontWeight: "bold", children: capitalize(status) })
486
+ }
487
+ ) : null
488
+ };
489
+ }),
490
+ onSelect: handleSelect,
491
+ value: currentLocale
492
+ };
493
+ };
494
+ const getDocumentStatus = (document, meta) => {
495
+ const docStatus = document?.status;
496
+ const statuses = meta?.availableStatus ?? [];
497
+ if (!docStatus) {
498
+ return "draft";
499
+ }
500
+ if (docStatus === "draft" && statuses.find((doc) => doc.publishedAt !== null)) {
501
+ return "published";
502
+ }
503
+ return docStatus;
504
+ };
505
+ const DeleteLocaleAction = ({
506
+ document,
507
+ documentId,
508
+ model,
509
+ collectionType
510
+ }) => {
511
+ const { formatMessage } = useIntl();
512
+ const navigate = useNavigate();
513
+ const { toggleNotification } = useNotification();
514
+ const { delete: deleteAction } = unstable_useDocumentActions();
515
+ const { hasI18n, canDelete } = useI18n();
516
+ if (!hasI18n) {
517
+ return null;
518
+ }
519
+ return {
520
+ disabled: document?.locale && !canDelete.includes(document.locale) || !document || !document.id,
521
+ position: ["header", "table-row"],
522
+ label: formatMessage({
523
+ id: getTranslation("actions.delete.label"),
524
+ defaultMessage: "Delete locale"
525
+ }),
526
+ icon: /* @__PURE__ */ jsx(StyledTrash, {}),
527
+ variant: "danger",
528
+ dialog: {
529
+ type: "dialog",
530
+ title: formatMessage({
531
+ id: getTranslation("actions.delete.dialog.title"),
532
+ defaultMessage: "Confirmation"
533
+ }),
534
+ content: /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: 2, children: [
535
+ /* @__PURE__ */ jsx(WarningCircle, { width: "24px", height: "24px", fill: "danger600" }),
536
+ /* @__PURE__ */ jsx(Typography, { tag: "p", variant: "omega", textAlign: "center", children: formatMessage({
537
+ id: getTranslation("actions.delete.dialog.body"),
538
+ defaultMessage: "Are you sure?"
539
+ }) })
540
+ ] }),
541
+ onConfirm: async () => {
542
+ if (!documentId || !document?.locale) {
543
+ console.error(
544
+ "You're trying to delete a document without an id or locale, this is likely a bug with Strapi. Please open an issue."
545
+ );
546
+ toggleNotification({
547
+ message: formatMessage({
548
+ id: getTranslation("actions.delete.error"),
549
+ defaultMessage: "An error occurred while trying to delete the document locale."
550
+ }),
551
+ type: "danger"
552
+ });
553
+ return;
554
+ }
555
+ const res = await deleteAction({
556
+ documentId,
557
+ model,
558
+ collectionType,
559
+ params: { locale: document.locale }
560
+ });
561
+ if (!("error" in res)) {
562
+ navigate({ pathname: `../${collectionType}/${model}` }, { replace: true });
563
+ }
564
+ }
565
+ }
566
+ };
567
+ };
568
+ const BulkLocaleAction = ({
569
+ document: baseDocument,
570
+ documentId,
571
+ model,
572
+ collectionType,
573
+ action
574
+ }) => {
575
+ const baseLocale = baseDocument?.locale ?? null;
576
+ const [{ query }] = useQueryParams();
577
+ const params = React.useMemo(() => buildValidParams(query), [query]);
578
+ const isOnPublishedTab = query.status === "published";
579
+ const { formatMessage } = useIntl();
580
+ const { hasI18n, canPublish } = useI18n();
581
+ const { toggleNotification } = useNotification();
582
+ const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler();
583
+ const [selectedRows, setSelectedRows] = React.useState([]);
584
+ const [isDraftRelationConfirmationOpen, setIsDraftRelationConfirmationOpen] = React.useState(false);
585
+ const { publishMany: publishManyAction, unpublishMany: unpublishManyAction } = unstable_useDocumentActions();
586
+ const {
587
+ document,
588
+ meta: documentMeta,
589
+ schema,
590
+ validate
591
+ } = unstable_useDocument(
592
+ {
593
+ model,
594
+ collectionType,
595
+ documentId,
596
+ params: {
597
+ locale: baseLocale
598
+ }
599
+ },
600
+ {
601
+ skip: !hasI18n
602
+ }
603
+ );
604
+ const { data: localesMetadata = [] } = useGetLocalesQuery(hasI18n ? void 0 : skipToken);
605
+ const headers = [
606
+ {
607
+ label: formatMessage({
608
+ id: "global.name",
609
+ defaultMessage: "Name"
610
+ }),
611
+ name: "name"
612
+ },
613
+ {
614
+ label: formatMessage({
615
+ id: getTranslation("CMEditViewBulkLocale.status"),
616
+ defaultMessage: "Status"
617
+ }),
618
+ name: "status"
619
+ },
620
+ {
621
+ label: formatMessage({
622
+ id: getTranslation("CMEditViewBulkLocale.publication-status"),
623
+ defaultMessage: "Publication Status"
624
+ }),
625
+ name: "publication-status"
626
+ }
627
+ ];
628
+ const [rows, validationErrors] = React.useMemo(() => {
629
+ if (!document || !documentMeta?.availableLocales) {
630
+ return [[], {}];
631
+ }
632
+ const rowsFromMeta = documentMeta?.availableLocales.map((doc) => {
633
+ const { locale, status } = doc;
634
+ return { locale, status };
635
+ });
636
+ rowsFromMeta.unshift({
637
+ locale: document.locale,
638
+ status: document.status
639
+ });
640
+ const allDocuments = [document, ...documentMeta?.availableLocales ?? []];
641
+ const errors = allDocuments.reduce((errs, document2) => {
642
+ if (!document2) {
643
+ return errs;
644
+ }
645
+ const validation = validate(document2);
646
+ if (validation !== null) {
647
+ errs[document2.locale] = validation;
648
+ }
649
+ return errs;
650
+ }, {});
651
+ return [rowsFromMeta, errors];
652
+ }, [document, documentMeta?.availableLocales, validate]);
653
+ const isBulkPublish = action === "bulk-publish";
654
+ const localesForAction = selectedRows.reduce((acc, selectedRow) => {
655
+ const isValidLocale = (
656
+ // Validation errors are irrelevant if we are trying to unpublish
657
+ !isBulkPublish || !Object.keys(validationErrors).includes(selectedRow.locale)
658
+ );
659
+ const shouldAddLocale = isBulkPublish ? selectedRow.status !== "published" && isValidLocale : selectedRow.status !== "draft" && isValidLocale;
660
+ if (shouldAddLocale) {
661
+ acc.push(selectedRow.locale);
662
+ }
663
+ return acc;
664
+ }, []);
665
+ const enableDraftRelationsCount = false;
666
+ const {
667
+ data: draftRelationsCount = 0,
668
+ isLoading: isDraftRelationsLoading,
669
+ error: isDraftRelationsError
670
+ } = useGetManyDraftRelationCountQuery(
671
+ {
672
+ model,
673
+ documentIds: [documentId],
674
+ locale: localesForAction
675
+ },
676
+ {
677
+ skip: !enableDraftRelationsCount
678
+ }
679
+ );
680
+ React.useEffect(() => {
681
+ if (isDraftRelationsError) {
682
+ toggleNotification({
683
+ type: "danger",
684
+ message: formatAPIError(isDraftRelationsError)
685
+ });
686
+ }
687
+ }, [isDraftRelationsError, toggleNotification, formatAPIError]);
688
+ if (!schema?.options?.draftAndPublish) {
689
+ return null;
690
+ }
691
+ if (!hasI18n) {
692
+ return null;
693
+ }
694
+ if (!documentId) {
695
+ return null;
696
+ }
697
+ const publish = async () => {
698
+ await publishManyAction({
699
+ model,
700
+ documentIds: [documentId],
701
+ params: {
702
+ ...params,
703
+ locale: localesForAction
704
+ }
705
+ });
706
+ setSelectedRows([]);
707
+ };
708
+ const unpublish = async () => {
709
+ await unpublishManyAction({
710
+ model,
711
+ documentIds: [documentId],
712
+ params: {
713
+ ...params,
714
+ locale: localesForAction
715
+ }
716
+ });
717
+ setSelectedRows([]);
718
+ };
719
+ const handleAction = async () => {
720
+ if (draftRelationsCount > 0) {
721
+ setIsDraftRelationConfirmationOpen(true);
722
+ } else if (isBulkPublish) {
723
+ await publish();
724
+ } else {
725
+ await unpublish();
726
+ }
727
+ };
728
+ if (isDraftRelationConfirmationOpen) {
729
+ return {
730
+ label: formatMessage({
731
+ id: "app.components.ConfirmDialog.title",
732
+ defaultMessage: "Confirmation"
733
+ }),
734
+ variant: "danger",
735
+ dialog: {
736
+ onCancel: () => {
737
+ setIsDraftRelationConfirmationOpen(false);
738
+ },
739
+ onConfirm: async () => {
740
+ await publish();
741
+ setIsDraftRelationConfirmationOpen(false);
742
+ },
743
+ type: "dialog",
744
+ title: formatMessage({
745
+ id: getTranslation("actions.publish.dialog.title"),
746
+ defaultMessage: "Confirmation"
747
+ }),
748
+ content: /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "center", gap: 2, children: [
749
+ /* @__PURE__ */ jsx(WarningCircle, { width: "2.4rem", height: "2.4rem", fill: "danger600" }),
750
+ /* @__PURE__ */ jsx(Typography, { textAlign: "center", children: formatMessage({
751
+ id: getTranslation("CMEditViewBulkLocale.draft-relation-warning"),
752
+ defaultMessage: "Some locales are related to draft entries. Publishing them could leave broken links in your app."
753
+ }) }),
754
+ /* @__PURE__ */ jsx(Typography, { textAlign: "center", children: formatMessage({
755
+ id: getTranslation("CMEditViewBulkLocale.continue-confirmation"),
756
+ defaultMessage: "Are you sure you want to continue?"
757
+ }) })
758
+ ] })
759
+ }
760
+ };
761
+ }
762
+ const hasPermission = selectedRows.map(({ locale }) => locale).every((locale) => canPublish.includes(locale));
763
+ return {
764
+ label: formatMessage({
765
+ id: getTranslation(`CMEditViewBulkLocale.${isBulkPublish ? "publish" : "unpublish"}-title`),
766
+ defaultMessage: `${isBulkPublish ? "Publish" : "Unpublish"} Multiple Locales`
767
+ }),
768
+ variant: isBulkPublish ? "secondary" : "danger",
769
+ icon: isBulkPublish ? /* @__PURE__ */ jsx(ListPlus, {}) : /* @__PURE__ */ jsx(Cross, {}),
770
+ disabled: isOnPublishedTab || canPublish.length === 0,
771
+ position: ["panel"],
772
+ dialog: {
773
+ type: "modal",
774
+ title: formatMessage({
775
+ id: getTranslation(`CMEditViewBulkLocale.${isBulkPublish ? "publish" : "unpublish"}-title`),
776
+ defaultMessage: `${isBulkPublish ? "Publish" : "Unpublish"} Multiple Locales`
777
+ }),
778
+ content: () => {
779
+ return /* @__PURE__ */ jsx(
780
+ Table.Root,
781
+ {
782
+ headers,
783
+ rows: rows.map((row) => ({
784
+ ...row,
785
+ id: row.locale
786
+ })),
787
+ selectedRows,
788
+ onSelectedRowsChange: (tableSelectedRows) => setSelectedRows(tableSelectedRows),
789
+ children: /* @__PURE__ */ jsx(
790
+ BulkLocaleActionModal,
791
+ {
792
+ validationErrors,
793
+ headers,
794
+ rows,
795
+ localesMetadata,
796
+ action: action ?? "bulk-publish"
797
+ }
798
+ )
799
+ }
800
+ );
801
+ },
802
+ footer: () => /* @__PURE__ */ jsx(Modal.Footer, { justifyContent: "flex-end", children: /* @__PURE__ */ jsx(
803
+ Button,
804
+ {
805
+ loading: isDraftRelationsLoading,
806
+ disabled: !hasPermission || localesForAction.length === 0,
807
+ variant: "default",
808
+ onClick: handleAction,
809
+ children: formatMessage({
810
+ id: isBulkPublish ? "app.utils.publish" : "app.utils.unpublish",
811
+ defaultMessage: isBulkPublish ? "Publish" : "Unpublish"
812
+ })
813
+ }
814
+ ) })
815
+ }
816
+ };
817
+ };
818
+ const BulkLocalePublishAction = (props) => {
819
+ return BulkLocaleAction({ action: "bulk-publish", ...props });
820
+ };
821
+ const BulkLocaleUnpublishAction = (props) => {
822
+ return BulkLocaleAction({ action: "bulk-unpublish", ...props });
823
+ };
824
+ const StyledTrash = styled(Trash)`
825
+ path {
826
+ fill: currentColor;
827
+ }
828
+ `;
829
+ const Emphasis = (chunks) => {
830
+ return /* @__PURE__ */ jsx(Typography, { fontWeight: "semiBold", textColor: "danger500", children: chunks });
831
+ };
832
+ const DeleteModalAdditionalInfo = () => {
833
+ const { hasI18n } = useI18n();
834
+ const { formatMessage } = useIntl();
835
+ if (!hasI18n) {
836
+ return null;
837
+ }
838
+ return /* @__PURE__ */ jsx(Typography, { textColor: "danger500", children: formatMessage(
839
+ {
840
+ id: getTranslation("Settings.list.actions.deleteAdditionalInfos"),
841
+ defaultMessage: "This will delete the active locale versions <em>(from Internationalization)</em>"
842
+ },
843
+ {
844
+ em: Emphasis
845
+ }
846
+ ) });
847
+ };
848
+ const PublishModalAdditionalInfo = () => {
849
+ const { hasI18n } = useI18n();
850
+ const { formatMessage } = useIntl();
851
+ if (!hasI18n) {
852
+ return null;
853
+ }
854
+ return /* @__PURE__ */ jsx(Typography, { textColor: "danger500", children: formatMessage(
855
+ {
856
+ id: getTranslation("Settings.list.actions.publishAdditionalInfos"),
857
+ defaultMessage: "This will publish the active locale versions <em>(from Internationalization)</em>"
858
+ },
859
+ {
860
+ em: Emphasis
861
+ }
862
+ ) });
863
+ };
864
+ const UnpublishModalAdditionalInfo = () => {
865
+ const { hasI18n } = useI18n();
866
+ const { formatMessage } = useIntl();
867
+ if (!hasI18n) {
868
+ return null;
869
+ }
870
+ return /* @__PURE__ */ jsx(Typography, { textColor: "danger500", children: formatMessage(
871
+ {
872
+ id: getTranslation("Settings.list.actions.unpublishAdditionalInfos"),
873
+ defaultMessage: "This will unpublish the active locale versions <em>(from Internationalization)</em>"
874
+ },
875
+ {
876
+ em: Emphasis
877
+ }
878
+ ) });
879
+ };
880
+ const LocalePicker = () => {
881
+ const { formatMessage } = useIntl();
882
+ const [{ query }, setQuery] = useQueryParams();
883
+ const { hasI18n, canRead, canCreate } = useI18n();
884
+ const { data: locales = [] } = useGetLocalesQuery(void 0, {
885
+ skip: !hasI18n
886
+ });
887
+ const handleChange = React.useCallback(
888
+ (code, replace = false) => {
889
+ setQuery(
890
+ {
891
+ page: 1,
892
+ plugins: { ...query.plugins, i18n: { locale: code } }
893
+ },
894
+ "push",
895
+ replace
896
+ );
897
+ },
898
+ [query.plugins, setQuery]
899
+ );
900
+ React.useEffect(() => {
901
+ if (!Array.isArray(locales) || !hasI18n) {
902
+ return;
903
+ }
904
+ const currentDesiredLocale = query.plugins?.i18n?.locale;
905
+ const doesLocaleExist = locales.find((loc) => loc.code === currentDesiredLocale);
906
+ const defaultLocale = locales.find((locale) => locale.isDefault);
907
+ if (!doesLocaleExist && defaultLocale?.code) {
908
+ handleChange(defaultLocale.code, true);
909
+ }
910
+ }, [hasI18n, handleChange, locales, query.plugins?.i18n?.locale]);
911
+ if (!hasI18n || !Array.isArray(locales) || locales.length === 0) {
912
+ return null;
913
+ }
914
+ const displayedLocales = locales.filter((locale) => {
915
+ return canCreate.includes(locale.code) || canRead.includes(locale.code);
916
+ });
917
+ return /* @__PURE__ */ jsx(
918
+ SingleSelect,
919
+ {
920
+ size: "S",
921
+ "aria-label": formatMessage({
922
+ id: getTranslation("actions.select-locale"),
923
+ defaultMessage: "Select locale"
924
+ }),
925
+ value: query.plugins?.i18n?.locale || locales.find((locale) => locale.isDefault)?.code,
926
+ onChange: handleChange,
927
+ children: displayedLocales.map((locale) => /* @__PURE__ */ jsx(SingleSelectOption, { value: locale.code, children: locale.name }, locale.id))
928
+ }
929
+ );
930
+ };
931
+ const PERMISSIONS = {
932
+ accessMain: [{ action: "plugin::i18n.locale.read", subject: null }],
933
+ create: [{ action: "plugin::i18n.locale.create", subject: null }],
934
+ delete: [{ action: "plugin::i18n.locale.delete", subject: null }],
935
+ update: [{ action: "plugin::i18n.locale.update", subject: null }],
936
+ read: [{ action: "plugin::i18n.locale.read", subject: null }]
937
+ };
938
+ const mutateEditViewHook = ({ layout }) => {
939
+ if (!("i18n" in layout.options) || typeof layout.options.i18n === "object" && layout.options.i18n !== null && "localized" in layout.options.i18n && !layout.options.i18n.localized) {
940
+ return { layout };
941
+ }
942
+ const components = Object.entries(layout.components).reduce(
943
+ (acc, [key, componentLayout]) => {
944
+ return {
945
+ ...acc,
946
+ [key]: {
947
+ ...componentLayout,
948
+ layout: componentLayout.layout.map((row) => row.map(addLabelActionToField))
949
+ }
950
+ };
951
+ },
952
+ {}
953
+ );
954
+ return {
955
+ layout: {
956
+ ...layout,
957
+ components,
958
+ layout: layout.layout.map((panel) => panel.map((row) => row.map(addLabelActionToField)))
959
+ }
960
+ };
961
+ };
962
+ const addLabelActionToField = (field) => {
963
+ const isFieldLocalized = doesFieldHaveI18nPluginOpt(field.attribute.pluginOptions) ? field.attribute.pluginOptions.i18n.localized : true;
964
+ const labelActionProps = {
965
+ title: {
966
+ id: isFieldLocalized ? getTranslation("Field.localized") : getTranslation("Field.not-localized"),
967
+ defaultMessage: isFieldLocalized ? "This value is unique for the selected locale" : "This value is the same across all locales"
968
+ },
969
+ icon: isFieldLocalized ? /* @__PURE__ */ jsx(Earth, {}) : /* @__PURE__ */ jsx(EarthStriked, {})
970
+ };
971
+ return {
972
+ ...field,
973
+ labelAction: /* @__PURE__ */ jsx(LabelAction, { ...labelActionProps })
974
+ };
975
+ };
976
+ const doesFieldHaveI18nPluginOpt = (pluginOpts) => {
977
+ if (!pluginOpts) {
978
+ return false;
979
+ }
980
+ return "i18n" in pluginOpts && typeof pluginOpts.i18n === "object" && pluginOpts.i18n !== null && "localized" in pluginOpts.i18n;
981
+ };
982
+ const LabelAction = ({ title, icon }) => {
983
+ const { formatMessage } = useIntl();
984
+ return /* @__PURE__ */ jsxs(Span, { tag: "span", children: [
985
+ /* @__PURE__ */ jsx(VisuallyHidden, { tag: "span", children: formatMessage(title) }),
986
+ React.cloneElement(icon, {
987
+ "aria-hidden": true,
988
+ focusable: false
989
+ // See: https://allyjs.io/tutorials/focusing-in-svg.html#making-svg-elements-focusable
990
+ })
991
+ ] });
992
+ };
993
+ const Span = styled(Flex)`
994
+ svg {
995
+ width: 12px;
996
+ height: 12px;
997
+
998
+ fill: ${({ theme }) => theme.colors.neutral500};
999
+
1000
+ path {
1001
+ fill: ${({ theme }) => theme.colors.neutral500};
1002
+ }
1003
+ }
1004
+ `;
1005
+ const LocaleListCell = ({
1006
+ documentId,
1007
+ locale: currentLocale,
1008
+ collectionType,
1009
+ model
1010
+ }) => {
1011
+ const { meta, isLoading } = unstable_useDocument({
1012
+ documentId,
1013
+ collectionType,
1014
+ model,
1015
+ params: {
1016
+ locale: currentLocale
1017
+ }
1018
+ });
1019
+ const { locale: language } = useIntl();
1020
+ const { data: locales = [] } = useGetLocalesQuery();
1021
+ const formatter = useCollator(language, {
1022
+ sensitivity: "base"
1023
+ });
1024
+ if (!Array.isArray(locales) || isLoading) {
1025
+ return null;
1026
+ }
1027
+ const availableLocales = meta?.availableLocales.map((doc) => doc.locale) ?? [];
1028
+ const localesForDocument = locales.reduce((acc, locale) => {
1029
+ const createdLocale = [currentLocale, ...availableLocales].find((loc) => {
1030
+ return loc === locale.code;
1031
+ });
1032
+ if (createdLocale) {
1033
+ acc.push(locale);
1034
+ }
1035
+ return acc;
1036
+ }, []).map((locale) => {
1037
+ if (locale.isDefault) {
1038
+ return `${locale.name} (default)`;
1039
+ }
1040
+ return locale.name;
1041
+ }).toSorted((a, b) => formatter.compare(a, b));
1042
+ return /* @__PURE__ */ jsxs(Popover.Root, { children: [
1043
+ /* @__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: [
1044
+ /* @__PURE__ */ jsx(Typography, { textColor: "neutral800", ellipsis: true, marginRight: 2, children: localesForDocument.join(", ") }),
1045
+ /* @__PURE__ */ jsx(Flex, { children: /* @__PURE__ */ jsx(CaretDown, { width: "1.2rem", height: "1.2rem" }) })
1046
+ ] }) }) }),
1047
+ /* @__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)) }) })
1048
+ ] });
1049
+ };
1050
+ const addColumnToTableHook = ({ displayedHeaders, layout }) => {
1051
+ const { options } = layout;
1052
+ const isFieldLocalized = doesPluginOptionsHaveI18nLocalized(options) ? options.i18n.localized : false;
1053
+ if (!isFieldLocalized) {
1054
+ return { displayedHeaders, layout };
1055
+ }
1056
+ return {
1057
+ displayedHeaders: [
1058
+ ...displayedHeaders,
1059
+ {
1060
+ attribute: { type: "string" },
1061
+ label: {
1062
+ id: getTranslation("list-view.table.header.label"),
1063
+ defaultMessage: "Available in"
1064
+ },
1065
+ searchable: false,
1066
+ sortable: false,
1067
+ name: "locales",
1068
+ // @ts-expect-error – ID is seen as number | string; this will change when we move the type over.
1069
+ cellFormatter: (props, _header, meta) => /* @__PURE__ */ jsx(LocaleListCell, { ...props, ...meta })
1070
+ }
1071
+ ],
1072
+ layout
1073
+ };
1074
+ };
1075
+ const addLocaleToReleasesHook = ({ displayedHeaders = [] }) => {
1076
+ return {
1077
+ displayedHeaders: [
1078
+ ...displayedHeaders,
1079
+ {
1080
+ label: {
1081
+ id: "content-releases.page.ReleaseDetails.table.header.label.locale",
1082
+ defaultMessage: "locale"
1083
+ },
1084
+ name: "locale"
1085
+ }
1086
+ ],
1087
+ hasI18nEnabled: true
1088
+ };
1089
+ };
1090
+ const extendCTBAttributeInitialDataMiddleware = () => {
1091
+ return ({ getState }) => (next) => (action) => {
1092
+ const enhanceAction = () => {
1093
+ try {
1094
+ const store = getState();
1095
+ const hasi18nEnabled = get(
1096
+ store,
1097
+ [
1098
+ "content-type-builder_dataManagerProvider",
1099
+ "modifiedData",
1100
+ "contentType",
1101
+ "schema",
1102
+ "pluginOptions",
1103
+ "i18n",
1104
+ "localized"
1105
+ ],
1106
+ false
1107
+ );
1108
+ if (hasi18nEnabled) {
1109
+ const pluginOptions = action.options ? { ...action.options.pluginOptions, i18n: { localized: true } } : { i18n: { localized: true } };
1110
+ return next({
1111
+ ...action,
1112
+ options: {
1113
+ pluginOptions
1114
+ }
1115
+ });
1116
+ }
1117
+ return next(action);
1118
+ } catch (err) {
1119
+ return next(action);
1120
+ }
1121
+ };
1122
+ if (action.type === "ContentTypeBuilder/FormModal/SET_ATTRIBUTE_DATA_SCHEMA" && action.forTarget === "contentType" && !["relation", "component"].includes(action.attributeType) && !action.isEditing) {
1123
+ return enhanceAction();
1124
+ }
1125
+ if (action.type === "ContentTypeBuilder/FormModal/SET_CUSTOM_FIELD_DATA_SCHEMA" && action.forTarget === "contentType" && !action.isEditing) {
1126
+ return enhanceAction();
1127
+ }
1128
+ if ((action.type === "ContentTypeBuilder/FormModal/RESET_PROPS_AND_SET_FORM_FOR_ADDING_AN_EXISTING_COMPO" || action.type === "ContentTypeBuilder/FormModal/RESET_PROPS_AND_SAVE_CURRENT_DATA") && action.forTarget === "contentType") {
1129
+ return enhanceAction();
1130
+ }
1131
+ return next(action);
1132
+ };
1133
+ };
1134
+ const extendCTBInitialDataMiddleware = () => {
1135
+ return () => (next) => (action) => {
1136
+ if (action.type === "ContentTypeBuilder/FormModal/SET_DATA_TO_EDIT" && action.modalType === "contentType") {
1137
+ const i18n = { localized: false };
1138
+ const pluginOptions = action.data.pluginOptions ? { ...action.data.pluginOptions, i18n } : { i18n };
1139
+ const data = { ...action.data, pluginOptions };
1140
+ if (action.actionType === "create") {
1141
+ return next({ ...action, data });
1142
+ }
1143
+ if (!action.data.pluginOptions?.i18n?.localized) {
1144
+ return next({ ...action, data });
1145
+ }
1146
+ }
1147
+ return next(action);
1148
+ };
1149
+ };
1150
+ const localeMiddleware = (ctx) => (next) => (permissions) => {
1151
+ const match = matchPath("/content-manager/:collectionType/:model?/:id", ctx.pathname);
1152
+ if (!match) {
1153
+ return next(permissions);
1154
+ }
1155
+ const search = qs.parse(ctx.search);
1156
+ if (typeof search !== "object") {
1157
+ return next(permissions);
1158
+ }
1159
+ if (!("plugins" in search && typeof search.plugins === "object")) {
1160
+ return next(permissions);
1161
+ }
1162
+ if (!("i18n" in search.plugins && typeof search.plugins.i18n === "object" && !Array.isArray(search.plugins.i18n))) {
1163
+ return next(permissions);
1164
+ }
1165
+ const { locale } = search.plugins.i18n;
1166
+ if (typeof locale !== "string") {
1167
+ return next(permissions);
1168
+ }
1169
+ const revisedPermissions = permissions.filter(
1170
+ (permission) => !permission.properties?.locales || permission.properties.locales.includes(locale)
1171
+ );
1172
+ return next(revisedPermissions);
1173
+ };
1174
+ const prefixPluginTranslations = (trad, pluginId2) => {
1175
+ if (!pluginId2) {
1176
+ throw new TypeError("pluginId can't be empty");
1177
+ }
1178
+ return Object.keys(trad).reduce((acc, current) => {
1179
+ acc[`${pluginId2}.${current}`] = trad[current];
1180
+ return acc;
1181
+ }, {});
1182
+ };
1183
+ const mutateCTBContentTypeSchema = (nextSchema, prevSchema) => {
1184
+ if (!doesPluginOptionsHaveI18nLocalized(nextSchema.pluginOptions)) {
1185
+ return nextSchema;
1186
+ }
1187
+ const isNextSchemaLocalized = nextSchema.pluginOptions.i18n.localized;
1188
+ const isPrevSchemaLocalized = doesPluginOptionsHaveI18nLocalized(
1189
+ prevSchema?.schema?.pluginOptions
1190
+ ) ? prevSchema?.schema?.pluginOptions.i18n.localized : false;
1191
+ if (isNextSchemaLocalized && isPrevSchemaLocalized) {
1192
+ return nextSchema;
1193
+ }
1194
+ if (isNextSchemaLocalized) {
1195
+ const attributes = addLocalisationToFields(nextSchema.attributes);
1196
+ return { ...nextSchema, attributes };
1197
+ }
1198
+ if (!isNextSchemaLocalized) {
1199
+ const pluginOptions = omit(nextSchema.pluginOptions, "i18n");
1200
+ const attributes = disableAttributesLocalisation(nextSchema.attributes);
1201
+ return { ...nextSchema, pluginOptions, attributes };
1202
+ }
1203
+ return nextSchema;
1204
+ };
1205
+ const addLocalisationToFields = (attributes) => Object.keys(attributes).reduce((acc, current) => {
1206
+ const currentAttribute = attributes[current];
1207
+ if (LOCALIZED_FIELDS.includes(currentAttribute.type)) {
1208
+ const i18n = { localized: true };
1209
+ const pluginOptions = currentAttribute.pluginOptions ? { ...currentAttribute.pluginOptions, i18n } : { i18n };
1210
+ acc[current] = { ...currentAttribute, pluginOptions };
1211
+ return acc;
1212
+ }
1213
+ acc[current] = currentAttribute;
1214
+ return acc;
1215
+ }, {});
1216
+ const disableAttributesLocalisation = (attributes) => Object.keys(attributes).reduce((acc, current) => {
1217
+ acc[current] = omit(attributes[current], "pluginOptions.i18n");
1218
+ return acc;
1219
+ }, {});
1220
+ const index = {
1221
+ register(app) {
1222
+ app.addMiddlewares([extendCTBAttributeInitialDataMiddleware, extendCTBInitialDataMiddleware]);
1223
+ app.addMiddlewares([() => i18nApi.middleware]);
1224
+ app.addReducers({
1225
+ [i18nApi.reducerPath]: i18nApi.reducer
1226
+ });
1227
+ app.addRBACMiddleware([localeMiddleware]);
1228
+ app.registerPlugin({
1229
+ id: pluginId,
1230
+ name: pluginId
1231
+ });
1232
+ },
1233
+ bootstrap(app) {
1234
+ app.registerHook("Admin/CM/pages/ListView/inject-column-in-table", addColumnToTableHook);
1235
+ app.registerHook("Admin/CM/pages/EditView/mutate-edit-view-layout", mutateEditViewHook);
1236
+ app.registerHook(
1237
+ "ContentReleases/pages/ReleaseDetails/add-locale-in-releases",
1238
+ addLocaleToReleasesHook
1239
+ );
1240
+ app.addSettingsLink("global", {
1241
+ intlLabel: {
1242
+ id: getTranslation("plugin.name"),
1243
+ defaultMessage: "Internationalization"
1244
+ },
1245
+ id: "internationalization",
1246
+ to: "internationalization",
1247
+ Component: () => import("./SettingsPage-CPNFX0bZ.mjs").then((mod) => ({ default: mod.ProtectedSettingsPage })),
1248
+ permissions: PERMISSIONS.accessMain
1249
+ });
1250
+ const contentManager = app.getPlugin("content-manager");
1251
+ contentManager.apis.addDocumentHeaderAction([LocalePickerAction]);
1252
+ contentManager.apis.addDocumentAction((actions) => {
1253
+ const indexOfDeleteAction = actions.findIndex((action) => action.type === "delete");
1254
+ actions.splice(indexOfDeleteAction, 0, DeleteLocaleAction);
1255
+ return actions;
1256
+ });
1257
+ contentManager.apis.addDocumentAction((actions) => {
1258
+ actions.splice(2, 0, BulkLocalePublishAction);
1259
+ actions.splice(5, 0, BulkLocaleUnpublishAction);
1260
+ return actions;
1261
+ });
1262
+ contentManager.injectComponent("listView", "actions", {
1263
+ name: "i18n-locale-filter",
1264
+ Component: LocalePicker
1265
+ });
1266
+ contentManager.injectComponent("listView", "publishModalAdditionalInfos", {
1267
+ name: "i18n-publish-bullets-in-modal",
1268
+ Component: PublishModalAdditionalInfo
1269
+ });
1270
+ contentManager.injectComponent("listView", "unpublishModalAdditionalInfos", {
1271
+ name: "i18n-unpublish-bullets-in-modal",
1272
+ Component: UnpublishModalAdditionalInfo
1273
+ });
1274
+ contentManager.injectComponent("listView", "deleteModalAdditionalInfos", {
1275
+ name: "i18n-delete-bullets-in-modal",
1276
+ Component: DeleteModalAdditionalInfo
1277
+ });
1278
+ const ctbPlugin = app.getPlugin("content-type-builder");
1279
+ if (ctbPlugin) {
1280
+ const ctbFormsAPI = ctbPlugin.apis.forms;
1281
+ ctbFormsAPI.addContentTypeSchemaMutation(mutateCTBContentTypeSchema);
1282
+ ctbFormsAPI.components.add({ id: "checkboxConfirmation", component: CheckboxConfirmation });
1283
+ ctbFormsAPI.extendContentType({
1284
+ validator: () => ({
1285
+ i18n: yup.object().shape({
1286
+ localized: yup.bool()
1287
+ })
1288
+ }),
1289
+ form: {
1290
+ advanced() {
1291
+ return [
1292
+ {
1293
+ name: "pluginOptions.i18n.localized",
1294
+ description: {
1295
+ id: getTranslation("plugin.schema.i18n.localized.description-content-type"),
1296
+ defaultMessage: "Allows translating an entry into different languages"
1297
+ },
1298
+ type: "checkboxConfirmation",
1299
+ intlLabel: {
1300
+ id: getTranslation("plugin.schema.i18n.localized.label-content-type"),
1301
+ defaultMessage: "Localization"
1302
+ }
1303
+ }
1304
+ ];
1305
+ }
1306
+ }
1307
+ });
1308
+ ctbFormsAPI.extendFields(LOCALIZED_FIELDS, {
1309
+ validator: (args) => ({
1310
+ i18n: yup.object().shape({
1311
+ localized: yup.bool().test({
1312
+ name: "ensure-unique-localization",
1313
+ message: getTranslation("plugin.schema.i18n.ensure-unique-localization"),
1314
+ test(value) {
1315
+ if (value === void 0 || value) {
1316
+ return true;
1317
+ }
1318
+ const unique = get(args, ["3", "modifiedData", "unique"], null);
1319
+ if (unique && !value) {
1320
+ return false;
1321
+ }
1322
+ return true;
1323
+ }
1324
+ })
1325
+ })
1326
+ }),
1327
+ form: {
1328
+ advanced({ contentTypeSchema, forTarget, type, step }) {
1329
+ if (forTarget !== "contentType") {
1330
+ return [];
1331
+ }
1332
+ const hasI18nEnabled = get(
1333
+ contentTypeSchema,
1334
+ ["schema", "pluginOptions", "i18n", "localized"],
1335
+ false
1336
+ );
1337
+ if (!hasI18nEnabled) {
1338
+ return [];
1339
+ }
1340
+ if (type === "component" && step === "1") {
1341
+ return [];
1342
+ }
1343
+ return [
1344
+ {
1345
+ name: "pluginOptions.i18n.localized",
1346
+ description: {
1347
+ id: getTranslation("plugin.schema.i18n.localized.description-field"),
1348
+ defaultMessage: "The field can have different values in each locale"
1349
+ },
1350
+ type: "checkbox",
1351
+ intlLabel: {
1352
+ id: getTranslation("plugin.schema.i18n.localized.label-field"),
1353
+ defaultMessage: "Enable localization for this field"
1354
+ }
1355
+ }
1356
+ ];
1357
+ }
1358
+ }
1359
+ });
1360
+ }
1361
+ },
1362
+ async registerTrads({ locales }) {
1363
+ const importedTrads = await Promise.all(
1364
+ locales.map((locale) => {
1365
+ 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-CtekP_47.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 }) => {
1366
+ return {
1367
+ data: prefixPluginTranslations(data, pluginId),
1368
+ locale
1369
+ };
1370
+ }).catch(() => {
1371
+ return {
1372
+ data: {},
1373
+ locale
1374
+ };
1375
+ });
1376
+ })
1377
+ );
1378
+ return Promise.resolve(importedTrads);
1379
+ }
1380
+ };
1381
+ export {
1382
+ PERMISSIONS as P,
1383
+ useGetDefaultLocalesQuery as a,
1384
+ useDeleteLocaleMutation as b,
1385
+ useUpdateLocaleMutation as c,
1386
+ useGetLocalesQuery as d,
1387
+ getTranslation as g,
1388
+ index as i,
1389
+ useCreateLocaleMutation as u
1390
+ };
1391
+ //# sourceMappingURL=index-CgjpU2bY.mjs.map