@strapi/i18n 0.0.0-next.5f27c76d39a0c192701bdc9daabce3bb59389ce3 → 0.0.0-next.62638801ce303ba9d03355a9f041541cc6668ae0

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 (190) hide show
  1. package/dist/admin/components/BulkLocaleActionModal.js +2 -2
  2. package/dist/admin/components/BulkLocaleActionModal.js.map +1 -1
  3. package/dist/admin/components/BulkLocaleActionModal.mjs +2 -2
  4. package/dist/admin/components/BulkLocaleActionModal.mjs.map +1 -1
  5. package/dist/admin/components/CMHeaderActions.js +294 -20
  6. package/dist/admin/components/CMHeaderActions.js.map +1 -1
  7. package/dist/admin/components/CMHeaderActions.mjs +298 -25
  8. package/dist/admin/components/CMHeaderActions.mjs.map +1 -1
  9. package/dist/admin/components/CreateLocale.js +8 -4
  10. package/dist/admin/components/CreateLocale.js.map +1 -1
  11. package/dist/admin/components/CreateLocale.mjs +9 -5
  12. package/dist/admin/components/CreateLocale.mjs.map +1 -1
  13. package/dist/admin/components/EditLocale.js +1 -1
  14. package/dist/admin/components/EditLocale.js.map +1 -1
  15. package/dist/admin/components/EditLocale.mjs +1 -1
  16. package/dist/admin/components/EditLocale.mjs.map +1 -1
  17. package/dist/admin/components/LocaleListCell.js +65 -45
  18. package/dist/admin/components/LocaleListCell.js.map +1 -1
  19. package/dist/admin/components/LocaleListCell.mjs +66 -46
  20. package/dist/admin/components/LocaleListCell.mjs.map +1 -1
  21. package/dist/admin/components/LocalePicker.js +18 -11
  22. package/dist/admin/components/LocalePicker.js.map +1 -1
  23. package/dist/admin/components/LocalePicker.mjs +19 -12
  24. package/dist/admin/components/LocalePicker.mjs.map +1 -1
  25. package/dist/admin/contentManagerHooks/editView.js +6 -3
  26. package/dist/admin/contentManagerHooks/editView.js.map +1 -1
  27. package/dist/admin/contentManagerHooks/editView.mjs +7 -4
  28. package/dist/admin/contentManagerHooks/editView.mjs.map +1 -1
  29. package/dist/admin/contentManagerHooks/listView.js +2 -1
  30. package/dist/admin/contentManagerHooks/listView.js.map +1 -1
  31. package/dist/admin/contentManagerHooks/listView.mjs +2 -1
  32. package/dist/admin/contentManagerHooks/listView.mjs.map +1 -1
  33. package/dist/admin/hooks/useAILocalizationJobsPolling.js +110 -0
  34. package/dist/admin/hooks/useAILocalizationJobsPolling.js.map +1 -0
  35. package/dist/admin/hooks/useAILocalizationJobsPolling.mjs +89 -0
  36. package/dist/admin/hooks/useAILocalizationJobsPolling.mjs.map +1 -0
  37. package/dist/admin/hooks/useI18n.js +4 -4
  38. package/dist/admin/hooks/useI18n.js.map +1 -1
  39. package/dist/admin/hooks/useI18n.mjs +4 -4
  40. package/dist/admin/hooks/useI18n.mjs.map +1 -1
  41. package/dist/admin/index.js +1 -0
  42. package/dist/admin/index.js.map +1 -1
  43. package/dist/admin/index.mjs +2 -1
  44. package/dist/admin/index.mjs.map +1 -1
  45. package/dist/admin/pages/SettingsPage.js +121 -46
  46. package/dist/admin/pages/SettingsPage.js.map +1 -1
  47. package/dist/admin/pages/SettingsPage.mjs +124 -30
  48. package/dist/admin/pages/SettingsPage.mjs.map +1 -1
  49. package/dist/admin/services/aiLocalizationJobs.js +26 -0
  50. package/dist/admin/services/aiLocalizationJobs.js.map +1 -0
  51. package/dist/admin/services/aiLocalizationJobs.mjs +24 -0
  52. package/dist/admin/services/aiLocalizationJobs.mjs.map +1 -0
  53. package/dist/admin/services/api.js +4 -1
  54. package/dist/admin/services/api.js.map +1 -1
  55. package/dist/admin/services/api.mjs +4 -1
  56. package/dist/admin/services/api.mjs.map +1 -1
  57. package/dist/admin/services/locales.js +4 -2
  58. package/dist/admin/services/locales.js.map +1 -1
  59. package/dist/admin/services/locales.mjs +4 -2
  60. package/dist/admin/services/locales.mjs.map +1 -1
  61. package/dist/admin/services/settings.js +30 -0
  62. package/dist/admin/services/settings.js.map +1 -0
  63. package/dist/admin/services/settings.mjs +27 -0
  64. package/dist/admin/services/settings.mjs.map +1 -0
  65. package/dist/admin/src/components/CMHeaderActions.d.ts +17 -4
  66. package/dist/admin/src/components/LocaleListCell.d.ts +2 -1
  67. package/dist/admin/src/hooks/useAILocalizationJobsPolling.d.ts +9 -0
  68. package/dist/admin/src/services/aiLocalizationJobs.d.ts +6 -0
  69. package/dist/admin/src/services/api.d.ts +1 -1
  70. package/dist/admin/src/services/locales.d.ts +1 -1
  71. package/dist/admin/src/services/relations.d.ts +1 -1
  72. package/dist/admin/src/services/settings.d.ts +5 -0
  73. package/dist/admin/translations/en.json.js +10 -0
  74. package/dist/admin/translations/en.json.js.map +1 -1
  75. package/dist/admin/translations/en.json.mjs +10 -0
  76. package/dist/admin/translations/en.json.mjs.map +1 -1
  77. package/dist/admin/utils/clean.js +2 -2
  78. package/dist/admin/utils/clean.js.map +1 -1
  79. package/dist/admin/utils/clean.mjs +2 -2
  80. package/dist/admin/utils/clean.mjs.map +1 -1
  81. package/dist/admin/utils/getTranslation.js.map +1 -1
  82. package/dist/admin/utils/getTranslation.mjs.map +1 -1
  83. package/dist/admin/utils/prefixPluginTranslations.js.map +1 -1
  84. package/dist/admin/utils/prefixPluginTranslations.mjs.map +1 -1
  85. package/dist/server/bootstrap.js +24 -8
  86. package/dist/server/bootstrap.js.map +1 -1
  87. package/dist/server/bootstrap.mjs +24 -8
  88. package/dist/server/bootstrap.mjs.map +1 -1
  89. package/dist/server/constants/iso-locales.json.js +4 -0
  90. package/dist/server/constants/iso-locales.json.js.map +1 -1
  91. package/dist/server/constants/iso-locales.json.mjs +4 -0
  92. package/dist/server/constants/iso-locales.json.mjs.map +1 -1
  93. package/dist/server/controllers/ai-localization-jobs.js +47 -0
  94. package/dist/server/controllers/ai-localization-jobs.js.map +1 -0
  95. package/dist/server/controllers/ai-localization-jobs.mjs +45 -0
  96. package/dist/server/controllers/ai-localization-jobs.mjs.map +1 -0
  97. package/dist/server/controllers/index.js +5 -1
  98. package/dist/server/controllers/index.js.map +1 -1
  99. package/dist/server/controllers/index.mjs +5 -1
  100. package/dist/server/controllers/index.mjs.map +1 -1
  101. package/dist/server/controllers/settings.js +24 -0
  102. package/dist/server/controllers/settings.js.map +1 -0
  103. package/dist/server/controllers/settings.mjs +22 -0
  104. package/dist/server/controllers/settings.mjs.map +1 -0
  105. package/dist/server/models/ai-localization-job.js +60 -0
  106. package/dist/server/models/ai-localization-job.js.map +1 -0
  107. package/dist/server/models/ai-localization-job.mjs +57 -0
  108. package/dist/server/models/ai-localization-job.mjs.map +1 -0
  109. package/dist/server/register.js +3 -1
  110. package/dist/server/register.js.map +1 -1
  111. package/dist/server/register.mjs +3 -1
  112. package/dist/server/register.mjs.map +1 -1
  113. package/dist/server/routes/admin.js +40 -0
  114. package/dist/server/routes/admin.js.map +1 -1
  115. package/dist/server/routes/admin.mjs +40 -0
  116. package/dist/server/routes/admin.mjs.map +1 -1
  117. package/dist/server/routes/content-api.js +11 -7
  118. package/dist/server/routes/content-api.js.map +1 -1
  119. package/dist/server/routes/content-api.mjs +11 -7
  120. package/dist/server/routes/content-api.mjs.map +1 -1
  121. package/dist/server/routes/index.mjs +2 -2
  122. package/dist/server/routes/validation/locale.js +57 -0
  123. package/dist/server/routes/validation/locale.js.map +1 -0
  124. package/dist/server/routes/validation/locale.mjs +36 -0
  125. package/dist/server/routes/validation/locale.mjs.map +1 -0
  126. package/dist/server/services/ai-localization-jobs.js +64 -0
  127. package/dist/server/services/ai-localization-jobs.js.map +1 -0
  128. package/dist/server/services/ai-localization-jobs.mjs +62 -0
  129. package/dist/server/services/ai-localization-jobs.mjs.map +1 -0
  130. package/dist/server/services/ai-localizations.js +268 -0
  131. package/dist/server/services/ai-localizations.js.map +1 -0
  132. package/dist/server/services/ai-localizations.mjs +266 -0
  133. package/dist/server/services/ai-localizations.mjs.map +1 -0
  134. package/dist/server/services/content-types.js.map +1 -1
  135. package/dist/server/services/content-types.mjs.map +1 -1
  136. package/dist/server/services/index.js +7 -1
  137. package/dist/server/services/index.js.map +1 -1
  138. package/dist/server/services/index.mjs +7 -1
  139. package/dist/server/services/index.mjs.map +1 -1
  140. package/dist/server/services/settings.js +25 -0
  141. package/dist/server/services/settings.js.map +1 -0
  142. package/dist/server/services/settings.mjs +23 -0
  143. package/dist/server/services/settings.mjs.map +1 -0
  144. package/dist/server/src/bootstrap.d.ts.map +1 -1
  145. package/dist/server/src/controllers/ai-localization-jobs.d.ts +17 -0
  146. package/dist/server/src/controllers/ai-localization-jobs.d.ts.map +1 -0
  147. package/dist/server/src/controllers/index.d.ts +10 -0
  148. package/dist/server/src/controllers/index.d.ts.map +1 -1
  149. package/dist/server/src/controllers/settings.d.ts +7 -0
  150. package/dist/server/src/controllers/settings.d.ts.map +1 -0
  151. package/dist/server/src/index.d.ts +47 -8
  152. package/dist/server/src/index.d.ts.map +1 -1
  153. package/dist/server/src/models/ai-localization-job.d.ts +5 -0
  154. package/dist/server/src/models/ai-localization-job.d.ts.map +1 -0
  155. package/dist/server/src/models/index.d.ts +5 -0
  156. package/dist/server/src/models/index.d.ts.map +1 -0
  157. package/dist/server/src/register.d.ts +1 -1
  158. package/dist/server/src/register.d.ts.map +1 -1
  159. package/dist/server/src/routes/admin.d.ts.map +1 -1
  160. package/dist/server/src/routes/content-api.d.ts +5 -8
  161. package/dist/server/src/routes/content-api.d.ts.map +1 -1
  162. package/dist/server/src/routes/index.d.ts +3 -7
  163. package/dist/server/src/routes/index.d.ts.map +1 -1
  164. package/dist/server/src/routes/validation/index.d.ts +2 -0
  165. package/dist/server/src/routes/validation/index.d.ts.map +1 -0
  166. package/dist/server/src/routes/validation/locale.d.ts +41 -0
  167. package/dist/server/src/routes/validation/locale.d.ts.map +1 -0
  168. package/dist/server/src/services/ai-localization-jobs.d.ts +26 -0
  169. package/dist/server/src/services/ai-localization-jobs.d.ts.map +1 -0
  170. package/dist/server/src/services/ai-localizations.d.ts +18 -0
  171. package/dist/server/src/services/ai-localizations.d.ts.map +1 -0
  172. package/dist/server/src/services/index.d.ts +33 -0
  173. package/dist/server/src/services/index.d.ts.map +1 -1
  174. package/dist/server/src/services/settings.d.ts +13 -0
  175. package/dist/server/src/services/settings.d.ts.map +1 -0
  176. package/dist/server/src/utils/index.d.ts +7 -1
  177. package/dist/server/src/utils/index.d.ts.map +1 -1
  178. package/dist/server/src/validation/settings.d.ts +12 -0
  179. package/dist/server/src/validation/settings.d.ts.map +1 -0
  180. package/dist/server/utils/index.js.map +1 -1
  181. package/dist/server/utils/index.mjs.map +1 -1
  182. package/dist/server/validation/settings.js +11 -0
  183. package/dist/server/validation/settings.js.map +1 -0
  184. package/dist/server/validation/settings.mjs +9 -0
  185. package/dist/server/validation/settings.mjs.map +1 -0
  186. package/dist/shared/contracts/ai-localization-jobs.d.ts +27 -0
  187. package/dist/shared/contracts/ai-localization-jobs.d.ts.map +1 -0
  188. package/dist/shared/contracts/settings.d.ts +40 -0
  189. package/dist/shared/contracts/shared.d.ts.map +1 -0
  190. package/package.json +13 -10
@@ -1,16 +1,20 @@
1
- import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
1
+ import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
2
2
  import * as React from 'react';
3
3
  import { skipToken } from '@reduxjs/toolkit/query';
4
4
  import { useQueryParams, useForm, useNotification, useAPIErrorHandler, Table } from '@strapi/admin/strapi-admin';
5
+ import { useAIAvailability } from '@strapi/admin/strapi-admin/ee';
5
6
  import { unstable_useDocument, unstable_useDocumentActions, buildValidParams } from '@strapi/content-manager/strapi-admin';
6
- import { Dialog, Flex, Typography, Field, SingleSelect, SingleSelectOption, Button, Status, Modal } from '@strapi/design-system';
7
- import { Trash, Plus, Earth, WarningCircle, ListPlus, Cross } from '@strapi/icons';
7
+ import { Status, SingleSelectOption, Box, Typography, Flex, Link, Dialog, Field, SingleSelect, Button, Modal } from '@strapi/design-system';
8
+ import { Loader, Trash, Sparkle, Earth, WarningCircle, Plus, ListPlus, Cross } from '@strapi/icons';
8
9
  import { useIntl } from 'react-intl';
9
- import { useNavigate } from 'react-router-dom';
10
+ import { NavLink, useNavigate } from 'react-router-dom';
10
11
  import { styled } from 'styled-components';
12
+ import { useAILocalizationJobsPolling } from '../hooks/useAILocalizationJobsPolling.mjs';
11
13
  import { useI18n } from '../hooks/useI18n.mjs';
14
+ import { useGetAILocalizationJobsByDocumentQuery } from '../services/aiLocalizationJobs.mjs';
12
15
  import { useGetLocalesQuery } from '../services/locales.mjs';
13
16
  import { useGetManyDraftRelationCountQuery } from '../services/relations.mjs';
17
+ import { useGetSettingsQuery } from '../services/settings.mjs';
14
18
  import { cleanData } from '../utils/clean.mjs';
15
19
  import { getTranslation } from '../utils/getTranslation.mjs';
16
20
  import { capitalize } from '../utils/strings.mjs';
@@ -60,6 +64,18 @@ const LocaleOption = ({ isDraftAndPublishEnabled, locale, status, entryExists })
60
64
  ]
61
65
  });
62
66
  };
67
+ const LocaleOptionStartIcon = ({ entryWithLocaleExists, translationStatus, index })=>{
68
+ const isAiAvailable = useAIAvailability();
69
+ if (!entryWithLocaleExists) {
70
+ return /*#__PURE__*/ jsx(Plus, {});
71
+ }
72
+ if (isAiAvailable && index !== 0 && translationStatus === 'failed') {
73
+ return /*#__PURE__*/ jsx(WarningCircle, {
74
+ fill: "warning600"
75
+ });
76
+ }
77
+ return null;
78
+ };
63
79
  const LocalePickerAction = ({ document, meta, model, collectionType, documentId })=>{
64
80
  const { formatMessage } = useIntl();
65
81
  const [{ query }, setQuery] = useQueryParams();
@@ -74,6 +90,14 @@ const LocalePickerAction = ({ document, meta, model, collectionType, documentId
74
90
  locale: currentDesiredLocale
75
91
  }
76
92
  });
93
+ const { data: jobData } = useGetAILocalizationJobsByDocumentQuery({
94
+ documentId: documentId,
95
+ model: model,
96
+ collectionType: collectionType
97
+ });
98
+ const { data: settings } = useGetSettingsQuery();
99
+ const isAiAvailable = useAIAvailability();
100
+ const setValues = useForm('LocalePickerAction', (state)=>state.setValues);
77
101
  const handleSelect = React.useCallback((value)=>{
78
102
  setQuery({
79
103
  plugins: {
@@ -82,11 +106,56 @@ const LocalePickerAction = ({ document, meta, model, collectionType, documentId
82
106
  locale: value
83
107
  }
84
108
  }
85
- });
109
+ }, 'push', true);
86
110
  }, [
87
111
  query.plugins,
88
112
  setQuery
89
113
  ]);
114
+ const nonTranslatedFields = React.useMemo(()=>{
115
+ if (!schema?.attributes) return [];
116
+ return Object.keys(schema.attributes).filter((field)=>{
117
+ const attribute = schema.attributes[field];
118
+ return attribute?.pluginOptions?.i18n?.localized === false;
119
+ });
120
+ }, [
121
+ schema?.attributes
122
+ ]);
123
+ const sourceLocaleData = React.useMemo(()=>{
124
+ if (!Array.isArray(locales) || !meta?.availableLocales) return null;
125
+ const defaultLocale = locales.find((locale)=>locale.isDefault);
126
+ const existingLocales = meta.availableLocales.map((loc)=>loc.locale);
127
+ const sourceLocaleCode = defaultLocale && existingLocales.includes(defaultLocale.code) && defaultLocale.code !== currentDesiredLocale ? defaultLocale.code : existingLocales.find((locale)=>locale !== currentDesiredLocale);
128
+ if (!sourceLocaleCode) return null;
129
+ // Find the document data from availableLocales (now includes non-translatable fields)
130
+ const sourceLocaleDoc = meta.availableLocales.find((loc)=>loc.locale === sourceLocaleCode);
131
+ return sourceLocaleDoc ? {
132
+ locale: sourceLocaleCode,
133
+ data: sourceLocaleDoc
134
+ } : null;
135
+ }, [
136
+ locales,
137
+ meta?.availableLocales,
138
+ currentDesiredLocale
139
+ ]);
140
+ /**
141
+ * Prefilling form with non-translatable fields from already existing locale
142
+ */ React.useEffect(()=>{
143
+ // Only run when creating a new locale (no document ID yet) and when we have non-translatable fields
144
+ if (!document?.id && nonTranslatedFields.length > 0 && sourceLocaleData?.data) {
145
+ const dataToSet = nonTranslatedFields.reduce((acc, field)=>{
146
+ acc[field] = sourceLocaleData.data[field];
147
+ return acc;
148
+ }, {});
149
+ if (Object.keys(dataToSet).length > 0) {
150
+ setValues(dataToSet);
151
+ }
152
+ }
153
+ }, [
154
+ document?.id,
155
+ nonTranslatedFields,
156
+ sourceLocaleData?.data,
157
+ setValues
158
+ ]);
90
159
  React.useEffect(()=>{
91
160
  if (!Array.isArray(locales) || !hasI18n) {
92
161
  return;
@@ -106,12 +175,18 @@ const LocalePickerAction = ({ document, meta, model, collectionType, documentId
106
175
  currentDesiredLocale
107
176
  ]);
108
177
  const currentLocale = Array.isArray(locales) ? locales.find((locale)=>locale.code === currentDesiredLocale) : undefined;
178
+ // Use meta.availableLocales instead of document.localizations
179
+ // meta.availableLocales contains all locales for the document, even when creating new locales
180
+ const availableLocales = meta?.availableLocales ?? [];
181
+ const documentLocalizations = document?.localizations ?? [];
182
+ // Prefer meta.availableLocales as it's more reliable, fallback to document.localizations
183
+ const allLocalizations = availableLocales.length > 0 ? availableLocales : documentLocalizations;
109
184
  const allCurrentLocales = [
110
185
  {
111
186
  status: getDocumentStatus(document, meta),
112
187
  locale: currentLocale?.code
113
188
  },
114
- ...document?.localizations ?? []
189
+ ...allLocalizations
115
190
  ];
116
191
  if (!hasI18n || !Array.isArray(locales) || locales.length === 0) {
117
192
  return null;
@@ -122,15 +197,52 @@ const LocalePickerAction = ({ document, meta, model, collectionType, documentId
122
197
  * otherwise the locale is hidden.
123
198
  */ return canRead.includes(locale.code);
124
199
  });
200
+ const localesSortingDefaultFirst = displayedLocales.sort((a, b)=>a.isDefault ? -1 : b.isDefault ? 1 : 0);
125
201
  return {
126
202
  label: formatMessage({
127
203
  id: getTranslation('Settings.locales.modal.locales.label'),
128
204
  defaultMessage: 'Locales'
129
205
  }),
130
- options: displayedLocales.map((locale)=>{
206
+ options: localesSortingDefaultFirst.map((locale, index)=>{
131
207
  const entryWithLocaleExists = allCurrentLocales.some((doc)=>doc.locale === locale.code);
132
208
  const currentLocaleDoc = allCurrentLocales.find((doc)=>'locale' in doc ? doc.locale === locale.code : false);
133
209
  const permissionsToCheck = currentLocaleDoc ? canRead : canCreate;
210
+ if (isAiAvailable && settings?.data?.aiLocalizations) {
211
+ return {
212
+ _render: ()=>/*#__PURE__*/ jsxs(React.Fragment, {
213
+ children: [
214
+ /*#__PURE__*/ jsx(SingleSelectOption, {
215
+ disabled: !permissionsToCheck.includes(locale.code),
216
+ startIcon: /*#__PURE__*/ jsx(LocaleOptionStartIcon, {
217
+ entryWithLocaleExists: entryWithLocaleExists,
218
+ translationStatus: jobData?.data?.status,
219
+ index: index
220
+ }),
221
+ value: locale.code,
222
+ children: /*#__PURE__*/ jsx(LocaleOption, {
223
+ isDraftAndPublishEnabled: !!schema?.options?.draftAndPublish,
224
+ locale: locale,
225
+ status: currentLocaleDoc?.status,
226
+ entryExists: entryWithLocaleExists
227
+ })
228
+ }, locale.code),
229
+ localesSortingDefaultFirst.length > 1 && index === 0 && /*#__PURE__*/ jsx(Box, {
230
+ paddingRight: 4,
231
+ paddingLeft: 4,
232
+ paddingTop: 2,
233
+ paddingBottom: 2,
234
+ children: /*#__PURE__*/ jsx(Typography, {
235
+ variant: "sigma",
236
+ children: formatMessage({
237
+ id: getTranslation('CMEditViewLocalePicker.locale.ai-translations'),
238
+ defaultMessage: 'AI Translations'
239
+ })
240
+ })
241
+ })
242
+ ]
243
+ }, index)
244
+ };
245
+ }
134
246
  return {
135
247
  disabled: !permissionsToCheck.includes(locale.code),
136
248
  value: locale.code,
@@ -138,9 +250,12 @@ const LocalePickerAction = ({ document, meta, model, collectionType, documentId
138
250
  isDraftAndPublishEnabled: !!schema?.options?.draftAndPublish,
139
251
  locale: locale,
140
252
  status: currentLocaleDoc?.status,
141
- entryExists: entryWithLocaleExists
253
+ entryExists: entryWithLocaleExists,
254
+ translationStatus: jobData?.data?.status
142
255
  }),
143
- startIcon: !entryWithLocaleExists ? /*#__PURE__*/ jsx(Plus, {}) : null
256
+ startIcon: /*#__PURE__*/ jsx(LocaleOptionStartIcon, {
257
+ entryWithLocaleExists: entryWithLocaleExists
258
+ })
144
259
  };
145
260
  }),
146
261
  customizeContent: ()=>currentLocale?.name,
@@ -163,6 +278,130 @@ const getDocumentStatus = (document, meta)=>{
163
278
  }
164
279
  return docStatus;
165
280
  };
281
+ /* -------------------------------------------------------------------------------------------------
282
+ * AISettingsStatusAction
283
+ * -----------------------------------------------------------------------------------------------*/ const AITranslationStatusIcon = styled(Status)`
284
+ display: flex;
285
+ gap: ${({ theme })=>theme.spaces[1]};
286
+ justify-content: center;
287
+ align-items: center;
288
+ height: 100%;
289
+
290
+ // Disabled state
291
+ ${({ $isAISettingEnabled, theme })=>!$isAISettingEnabled && `
292
+ background-color: ${theme.colors.neutral150};
293
+ `}
294
+
295
+ svg {
296
+ ${({ $isAISettingEnabled, theme })=>!$isAISettingEnabled && `
297
+ fill: ${theme.colors.neutral300};
298
+ `}
299
+ }
300
+ `;
301
+ const SpinningLoader = styled(Loader)`
302
+ @keyframes spin {
303
+ from {
304
+ transform: rotate(0deg);
305
+ }
306
+ to {
307
+ transform: rotate(360deg);
308
+ }
309
+ }
310
+
311
+ animation: spin 2s linear infinite;
312
+ `;
313
+ const AITranslationStatusAction = ({ documentId, model, collectionType })=>{
314
+ const { formatMessage } = useIntl();
315
+ const isAIAvailable = useAIAvailability();
316
+ const { data: settings } = useGetSettingsQuery();
317
+ const isAISettingEnabled = settings?.data?.aiLocalizations;
318
+ const { hasI18n } = useI18n();
319
+ // Poll for AI localizations jobs when AI is enabled and we have a documentId
320
+ const { status } = useAILocalizationJobsPolling({
321
+ documentId,
322
+ model,
323
+ collectionType
324
+ });
325
+ const statusVariant = (()=>{
326
+ if (status === 'failed') {
327
+ return 'warning';
328
+ }
329
+ if (isAISettingEnabled) {
330
+ return 'alternative';
331
+ }
332
+ return 'neutral';
333
+ })();
334
+ // Do not display this action when i18n is not available
335
+ if (!hasI18n) {
336
+ return null;
337
+ }
338
+ // Do not display this action when AI is not available
339
+ if (!isAIAvailable) {
340
+ return null;
341
+ }
342
+ return {
343
+ _status: {
344
+ message: /*#__PURE__*/ jsx(Box, {
345
+ height: "100%",
346
+ "aria-label": formatMessage({
347
+ id: getTranslation('CMEditViewAITranslation.status-aria-label'),
348
+ defaultMessage: 'AI Translation Status'
349
+ }),
350
+ children: /*#__PURE__*/ jsx(AITranslationStatusIcon, {
351
+ $isAISettingEnabled: Boolean(isAISettingEnabled),
352
+ variant: statusVariant,
353
+ size: "S",
354
+ children: status === 'processing' ? /*#__PURE__*/ jsx(SpinningLoader, {}) : /*#__PURE__*/ jsx(Sparkle, {})
355
+ })
356
+ }),
357
+ tooltip: /*#__PURE__*/ jsxs(Flex, {
358
+ direction: "column",
359
+ padding: 4,
360
+ alignItems: "flex-start",
361
+ width: "25rem",
362
+ children: [
363
+ /*#__PURE__*/ jsx(Typography, {
364
+ variant: "pi",
365
+ fontWeight: "600",
366
+ children: formatMessage({
367
+ id: getTranslation('CMEditViewAITranslation.status-title'),
368
+ defaultMessage: '{enabled, select, true {AI translation enabled} false {AI translation disabled} other {AI translation disabled}}'
369
+ }, {
370
+ enabled: isAISettingEnabled
371
+ })
372
+ }),
373
+ /*#__PURE__*/ jsx(Typography, {
374
+ variant: "pi",
375
+ paddingTop: 1,
376
+ paddingBottom: 3,
377
+ children: formatMessage({
378
+ id: getTranslation('CMEditViewAITranslation.status-description'),
379
+ defaultMessage: 'Our AI translates content in all locales each time you save a modification in the default locale.'
380
+ })
381
+ }),
382
+ /*#__PURE__*/ jsx(Link, {
383
+ fontSize: "inherit",
384
+ tag: NavLink,
385
+ to: "/settings/internationalization",
386
+ style: {
387
+ alignSelf: 'flex-end'
388
+ },
389
+ children: /*#__PURE__*/ jsx(Typography, {
390
+ variant: "pi",
391
+ textAlign: "right",
392
+ children: formatMessage({
393
+ id: getTranslation('CMEditViewAITranslation.settings-link'),
394
+ defaultMessage: '{enabled, select, true {Disable it in settings} false {Enable it in settings} other {Enable it in settings}}'
395
+ }, {
396
+ enabled: isAISettingEnabled
397
+ })
398
+ })
399
+ })
400
+ ]
401
+ })
402
+ }
403
+ };
404
+ };
166
405
  /* -------------------------------------------------------------------------------------------------
167
406
  * FillFromAnotherLocaleAction
168
407
  * -----------------------------------------------------------------------------------------------*/ const FillFromAnotherLocaleAction = ({ documentId, meta, model, collectionType })=>{
@@ -182,6 +421,9 @@ const getDocumentStatus = (document, meta)=>{
182
421
  }
183
422
  });
184
423
  const { data: locales = [] } = useGetLocalesQuery();
424
+ const isAIAvailable = useAIAvailability();
425
+ const { data: settings } = useGetSettingsQuery();
426
+ const isAISettingEnabled = settings?.data?.aiLocalizations;
185
427
  const availableLocales = Array.isArray(locales) ? locales.filter((locale)=>meta?.availableLocales.some((l)=>l.locale === locale.code)) : [];
186
428
  const fillFromLocale = (onClose)=>async ()=>{
187
429
  const response = await getDocument({
@@ -203,6 +445,10 @@ const getDocumentStatus = (document, meta)=>{
203
445
  if (!hasI18n) {
204
446
  return null;
205
447
  }
448
+ // Do not display this action when AI is available and AI translations are enabled
449
+ if (isAIAvailable && isAISettingEnabled) {
450
+ return null;
451
+ }
206
452
  return {
207
453
  type: 'icon',
208
454
  icon: /*#__PURE__*/ jsx(Earth, {}),
@@ -389,7 +635,7 @@ const getDocumentStatus = (document, meta)=>{
389
635
  * BulkLocaleAction
390
636
  *
391
637
  * This component is used to handle bulk publish and unpublish actions on locales.
392
- * -----------------------------------------------------------------------------------------------*/ const BulkLocaleAction = ({ document, documentId, model, collectionType, action })=>{
638
+ * -----------------------------------------------------------------------------------------------*/ const BulkLocaleAction = ({ document, documentId, model, collectionType, action, meta })=>{
393
639
  const locale = document?.locale ?? null;
394
640
  const [{ query }] = useQueryParams();
395
641
  const params = React.useMemo(()=>buildValidParams(query), [
@@ -447,25 +693,51 @@ const getDocumentStatus = (document, meta)=>{
447
693
  {}
448
694
  ];
449
695
  }
450
- const localizations = document.localizations ?? [];
451
- // Build the rows for the bulk locale publish modal by combining the current
452
- // document with all the available locales from the document meta
453
- const locales = localizations.map((doc)=>{
454
- const { locale, status } = doc;
455
- return {
456
- locale,
457
- status
458
- };
696
+ const metaLocalizations = (meta?.availableLocales ?? []).map((locale)=>({
697
+ locale: locale.locale,
698
+ status: locale.status ?? 'draft'
699
+ }));
700
+ const documentLocalizations = (document.localizations ?? []).map((doc)=>({
701
+ locale: doc.locale ?? undefined,
702
+ status: doc.status ?? 'draft'
703
+ }));
704
+ const localesMap = new Map();
705
+ metaLocalizations.forEach(({ locale, status })=>{
706
+ if (locale) {
707
+ localesMap.set(locale, {
708
+ locale,
709
+ status
710
+ });
711
+ }
459
712
  });
460
- // Add the current document locale
461
- locales.unshift({
462
- locale: document.locale,
463
- status: document.status
713
+ documentLocalizations.forEach(({ locale, status })=>{
714
+ if (locale) {
715
+ localesMap.set(locale, {
716
+ locale,
717
+ status
718
+ });
719
+ }
464
720
  });
721
+ // Build the rows for the bulk locale publish modal by combining the current
722
+ // document with all the available locales from the document meta
723
+ const locales = [];
724
+ if (document?.locale) {
725
+ locales.push({
726
+ locale: document.locale,
727
+ status: document.status ?? 'draft'
728
+ });
729
+ }
730
+ locales.push(...Array.from(localesMap.entries()).filter(([locale])=>locale !== document?.locale).map(([, value])=>value));
731
+ if (locales.length === 0 && document?.locale) {
732
+ locales.push({
733
+ locale: document.locale,
734
+ status: document.status ?? 'draft'
735
+ });
736
+ }
465
737
  // Build the validation errors for each locale.
466
738
  const allDocuments = [
467
739
  document,
468
- ...localizations
740
+ ...document.localizations ?? []
469
741
  ];
470
742
  const errors = allDocuments.reduce((errs, document)=>{
471
743
  if (!document) {
@@ -484,6 +756,7 @@ const getDocumentStatus = (document, meta)=>{
484
756
  ];
485
757
  }, [
486
758
  document,
759
+ meta?.availableLocales,
487
760
  validate
488
761
  ]);
489
762
  const isBulkPublish = action === 'bulk-publish';
@@ -692,5 +965,5 @@ const getDocumentStatus = (document, meta)=>{
692
965
  }
693
966
  `;
694
967
 
695
- export { BulkLocalePublishAction, BulkLocaleUnpublishAction, DeleteLocaleAction, FillFromAnotherLocaleAction, LocalePickerAction };
968
+ export { AITranslationStatusAction, BulkLocalePublishAction, BulkLocaleUnpublishAction, DeleteLocaleAction, FillFromAnotherLocaleAction, LocalePickerAction };
696
969
  //# sourceMappingURL=CMHeaderActions.mjs.map