@strapi/i18n 0.0.0-experimental.65ad956ae83ac65d866b9bb3e8c022c34b85468f → 0.0.0-experimental.65ea8c7363e4ca01d05c1f059f39d24b3db53ca7

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 (469) hide show
  1. package/dist/admin/components/BulkLocaleActionModal.js +262 -0
  2. package/dist/admin/components/BulkLocaleActionModal.js.map +1 -0
  3. package/dist/admin/components/BulkLocaleActionModal.mjs +260 -0
  4. package/dist/admin/components/BulkLocaleActionModal.mjs.map +1 -0
  5. package/dist/admin/components/CMHeaderActions.js +852 -0
  6. package/dist/admin/components/CMHeaderActions.js.map +1 -0
  7. package/dist/admin/components/CMHeaderActions.mjs +826 -0
  8. package/dist/admin/components/CMHeaderActions.mjs.map +1 -0
  9. package/dist/admin/components/CMListViewModalsAdditionalInformation.js +69 -0
  10. package/dist/admin/components/CMListViewModalsAdditionalInformation.js.map +1 -0
  11. package/dist/admin/components/CMListViewModalsAdditionalInformation.mjs +65 -0
  12. package/dist/admin/components/CMListViewModalsAdditionalInformation.mjs.map +1 -0
  13. package/dist/admin/components/CheckboxConfirmation.js +155 -0
  14. package/dist/admin/components/CheckboxConfirmation.js.map +1 -0
  15. package/dist/admin/components/CheckboxConfirmation.mjs +134 -0
  16. package/dist/admin/components/CheckboxConfirmation.mjs.map +1 -0
  17. package/dist/admin/components/CreateLocale.js +395 -0
  18. package/dist/admin/components/CreateLocale.js.map +1 -0
  19. package/dist/admin/components/CreateLocale.mjs +369 -0
  20. package/dist/admin/components/CreateLocale.mjs.map +1 -0
  21. package/dist/admin/components/DeleteLocale.js +90 -0
  22. package/dist/admin/components/DeleteLocale.js.map +1 -0
  23. package/dist/admin/components/DeleteLocale.mjs +69 -0
  24. package/dist/admin/components/DeleteLocale.mjs.map +1 -0
  25. package/dist/admin/components/EditLocale.js +212 -0
  26. package/dist/admin/components/EditLocale.js.map +1 -0
  27. package/dist/admin/components/EditLocale.mjs +190 -0
  28. package/dist/admin/components/EditLocale.mjs.map +1 -0
  29. package/dist/admin/components/LocaleListCell.js +102 -0
  30. package/dist/admin/components/LocaleListCell.js.map +1 -0
  31. package/dist/admin/components/LocaleListCell.mjs +100 -0
  32. package/dist/admin/components/LocaleListCell.mjs.map +1 -0
  33. package/dist/admin/components/LocalePicker.js +105 -0
  34. package/dist/admin/components/LocalePicker.js.map +1 -0
  35. package/dist/admin/components/LocalePicker.mjs +84 -0
  36. package/dist/admin/components/LocalePicker.mjs.map +1 -0
  37. package/dist/admin/components/LocaleTable.js +143 -0
  38. package/dist/admin/components/LocaleTable.js.map +1 -0
  39. package/dist/admin/components/LocaleTable.mjs +122 -0
  40. package/dist/admin/components/LocaleTable.mjs.map +1 -0
  41. package/dist/admin/constants.js +37 -0
  42. package/dist/admin/constants.js.map +1 -0
  43. package/dist/admin/constants.mjs +35 -0
  44. package/dist/admin/constants.mjs.map +1 -0
  45. package/dist/admin/contentManagerHooks/editView.js +109 -0
  46. package/dist/admin/contentManagerHooks/editView.js.map +1 -0
  47. package/dist/admin/contentManagerHooks/editView.mjs +88 -0
  48. package/dist/admin/contentManagerHooks/editView.mjs.map +1 -0
  49. package/dist/admin/contentManagerHooks/listView.js +44 -0
  50. package/dist/admin/contentManagerHooks/listView.js.map +1 -0
  51. package/dist/admin/contentManagerHooks/listView.mjs +42 -0
  52. package/dist/admin/contentManagerHooks/listView.mjs.map +1 -0
  53. package/dist/admin/contentReleasesHooks/releaseDetailsView.js +20 -0
  54. package/dist/admin/contentReleasesHooks/releaseDetailsView.js.map +1 -0
  55. package/dist/admin/contentReleasesHooks/releaseDetailsView.mjs +18 -0
  56. package/dist/admin/contentReleasesHooks/releaseDetailsView.mjs.map +1 -0
  57. package/dist/admin/hooks/useAILocalizationJobsPolling.js +91 -0
  58. package/dist/admin/hooks/useAILocalizationJobsPolling.js.map +1 -0
  59. package/dist/admin/hooks/useAILocalizationJobsPolling.mjs +70 -0
  60. package/dist/admin/hooks/useAILocalizationJobsPolling.mjs.map +1 -0
  61. package/dist/admin/hooks/useI18n.js +78 -0
  62. package/dist/admin/hooks/useI18n.js.map +1 -0
  63. package/dist/admin/hooks/useI18n.mjs +57 -0
  64. package/dist/admin/hooks/useI18n.mjs.map +1 -0
  65. package/dist/admin/index.js +226 -5
  66. package/dist/admin/index.js.map +1 -1
  67. package/dist/admin/index.mjs +202 -5
  68. package/dist/admin/index.mjs.map +1 -1
  69. package/dist/admin/middlewares/extendCTBAttributeInitialData.js +71 -0
  70. package/dist/admin/middlewares/extendCTBAttributeInitialData.js.map +1 -0
  71. package/dist/admin/middlewares/extendCTBAttributeInitialData.mjs +69 -0
  72. package/dist/admin/middlewares/extendCTBAttributeInitialData.mjs.map +1 -0
  73. package/dist/admin/middlewares/extendCTBInitialData.js +40 -0
  74. package/dist/admin/middlewares/extendCTBInitialData.js.map +1 -0
  75. package/dist/admin/middlewares/extendCTBInitialData.mjs +38 -0
  76. package/dist/admin/middlewares/extendCTBInitialData.mjs.map +1 -0
  77. package/dist/admin/middlewares/rbac-middleware.js +49 -0
  78. package/dist/admin/middlewares/rbac-middleware.js.map +1 -0
  79. package/dist/admin/middlewares/rbac-middleware.mjs +28 -0
  80. package/dist/admin/middlewares/rbac-middleware.mjs.map +1 -0
  81. package/dist/admin/pages/SettingsPage.js +182 -0
  82. package/dist/admin/pages/SettingsPage.js.map +1 -0
  83. package/dist/admin/pages/SettingsPage.mjs +179 -0
  84. package/dist/admin/pages/SettingsPage.mjs.map +1 -0
  85. package/dist/admin/pluginId.js +6 -0
  86. package/dist/admin/pluginId.js.map +1 -0
  87. package/dist/admin/pluginId.mjs +4 -0
  88. package/dist/admin/pluginId.mjs.map +1 -0
  89. package/dist/admin/services/aiLocalizationJobs.js +26 -0
  90. package/dist/admin/services/aiLocalizationJobs.js.map +1 -0
  91. package/dist/admin/services/aiLocalizationJobs.mjs +24 -0
  92. package/dist/admin/services/aiLocalizationJobs.mjs.map +1 -0
  93. package/dist/admin/services/api.js +15 -0
  94. package/dist/admin/services/api.js.map +1 -0
  95. package/dist/admin/services/api.mjs +13 -0
  96. package/dist/admin/services/api.mjs.map +1 -0
  97. package/dist/admin/services/locales.js +72 -0
  98. package/dist/admin/services/locales.js.map +1 -0
  99. package/dist/admin/services/locales.mjs +66 -0
  100. package/dist/admin/services/locales.mjs.map +1 -0
  101. package/dist/admin/services/relations.js +23 -0
  102. package/dist/admin/services/relations.js.map +1 -0
  103. package/dist/admin/services/relations.mjs +21 -0
  104. package/dist/admin/services/relations.mjs.map +1 -0
  105. package/dist/admin/services/settings.js +29 -0
  106. package/dist/admin/services/settings.js.map +1 -0
  107. package/dist/admin/services/settings.mjs +26 -0
  108. package/dist/admin/services/settings.mjs.map +1 -0
  109. package/dist/admin/src/components/CMHeaderActions.d.ts +13 -5
  110. package/dist/admin/src/components/CreateLocale.d.ts +6 -6
  111. package/dist/admin/src/components/LocaleListCell.d.ts +5 -4
  112. package/dist/admin/src/components/tests/CreateLocale.test.d.ts +1 -0
  113. package/dist/admin/src/components/tests/DeleteLocale.test.d.ts +1 -0
  114. package/dist/admin/src/components/tests/EditLocale.test.d.ts +1 -0
  115. package/dist/admin/src/components/tests/LocaleListCell.test.d.ts +1 -0
  116. package/dist/admin/src/contentReleasesHooks/releaseDetailsView.d.ts +1 -1
  117. package/dist/admin/src/hooks/useAILocalizationJobsPolling.d.ts +9 -0
  118. package/dist/admin/src/pages/tests/SettingsPage.test.d.ts +1 -0
  119. package/dist/admin/src/services/aiLocalizationJobs.d.ts +6 -0
  120. package/dist/admin/src/services/api.d.ts +1 -1
  121. package/dist/admin/src/services/locales.d.ts +1 -1
  122. package/dist/admin/src/services/relations.d.ts +1 -1
  123. package/dist/admin/src/services/settings.d.ts +5 -0
  124. package/dist/admin/src/utils/schemas.d.ts +642 -16
  125. package/dist/admin/tests/server.d.ts +1 -0
  126. package/dist/admin/tests/utils.d.ts +6 -0
  127. package/dist/admin/translations/de.json.js +66 -0
  128. package/dist/admin/translations/de.json.js.map +1 -0
  129. package/dist/admin/translations/de.json.mjs +64 -0
  130. package/dist/admin/translations/de.json.mjs.map +1 -0
  131. package/dist/admin/translations/dk.json.js +66 -0
  132. package/dist/admin/translations/dk.json.js.map +1 -0
  133. package/dist/admin/translations/dk.json.mjs +64 -0
  134. package/dist/admin/translations/dk.json.mjs.map +1 -0
  135. package/dist/admin/translations/en.json.js +90 -0
  136. package/dist/admin/translations/en.json.js.map +1 -0
  137. package/dist/admin/translations/en.json.mjs +88 -0
  138. package/dist/admin/translations/en.json.mjs.map +1 -0
  139. package/dist/admin/translations/es.json.js +66 -0
  140. package/dist/admin/translations/es.json.js.map +1 -0
  141. package/dist/admin/translations/es.json.mjs +64 -0
  142. package/dist/admin/translations/es.json.mjs.map +1 -0
  143. package/dist/admin/translations/fr.json.js +66 -0
  144. package/dist/admin/translations/fr.json.js.map +1 -0
  145. package/dist/admin/translations/fr.json.mjs +64 -0
  146. package/dist/admin/translations/fr.json.mjs.map +1 -0
  147. package/dist/admin/translations/ko.json.js +65 -0
  148. package/dist/admin/translations/ko.json.js.map +1 -0
  149. package/dist/admin/translations/ko.json.mjs +63 -0
  150. package/dist/admin/translations/ko.json.mjs.map +1 -0
  151. package/dist/admin/translations/pl.json.js +66 -0
  152. package/dist/admin/translations/pl.json.js.map +1 -0
  153. package/dist/admin/translations/pl.json.mjs +64 -0
  154. package/dist/admin/translations/pl.json.mjs.map +1 -0
  155. package/dist/admin/translations/ru.json.js +68 -0
  156. package/dist/admin/translations/ru.json.js.map +1 -0
  157. package/dist/admin/translations/ru.json.mjs +66 -0
  158. package/dist/admin/translations/ru.json.mjs.map +1 -0
  159. package/dist/admin/translations/tr.json.js +66 -0
  160. package/dist/admin/translations/tr.json.js.map +1 -0
  161. package/dist/admin/translations/tr.json.mjs +64 -0
  162. package/dist/admin/translations/tr.json.mjs.map +1 -0
  163. package/dist/admin/translations/uk.json.js +82 -0
  164. package/dist/admin/translations/uk.json.js.map +1 -0
  165. package/dist/admin/translations/uk.json.mjs +80 -0
  166. package/dist/admin/translations/uk.json.mjs.map +1 -0
  167. package/dist/admin/translations/zh-Hans.json.js +57 -0
  168. package/dist/admin/translations/zh-Hans.json.js.map +1 -0
  169. package/dist/admin/translations/zh-Hans.json.mjs +55 -0
  170. package/dist/admin/translations/zh-Hans.json.mjs.map +1 -0
  171. package/dist/admin/translations/zh.json.js +66 -0
  172. package/dist/admin/translations/zh.json.js.map +1 -0
  173. package/dist/admin/translations/zh.json.mjs +64 -0
  174. package/dist/admin/translations/zh.json.mjs.map +1 -0
  175. package/dist/admin/utils/baseQuery.js +8 -0
  176. package/dist/admin/utils/baseQuery.js.map +1 -0
  177. package/dist/admin/utils/baseQuery.mjs +6 -0
  178. package/dist/admin/utils/baseQuery.mjs.map +1 -0
  179. package/dist/admin/utils/clean.js +70 -0
  180. package/dist/admin/utils/clean.js.map +1 -0
  181. package/dist/admin/utils/clean.mjs +68 -0
  182. package/dist/admin/utils/clean.mjs.map +1 -0
  183. package/dist/admin/utils/fields.js +34 -0
  184. package/dist/admin/utils/fields.js.map +1 -0
  185. package/dist/admin/utils/fields.mjs +31 -0
  186. package/dist/admin/utils/fields.mjs.map +1 -0
  187. package/dist/admin/utils/getTranslation.js +8 -0
  188. package/dist/admin/utils/getTranslation.js.map +1 -0
  189. package/dist/admin/utils/getTranslation.mjs +6 -0
  190. package/dist/admin/utils/getTranslation.mjs.map +1 -0
  191. package/dist/admin/utils/prefixPluginTranslations.js +11 -0
  192. package/dist/admin/utils/prefixPluginTranslations.js.map +1 -0
  193. package/dist/admin/utils/prefixPluginTranslations.mjs +9 -0
  194. package/dist/admin/utils/prefixPluginTranslations.mjs.map +1 -0
  195. package/dist/admin/utils/schemas.js +74 -0
  196. package/dist/admin/utils/schemas.js.map +1 -0
  197. package/dist/admin/utils/schemas.mjs +72 -0
  198. package/dist/admin/utils/schemas.mjs.map +1 -0
  199. package/dist/admin/utils/strings.js +6 -0
  200. package/dist/admin/utils/strings.js.map +1 -0
  201. package/dist/admin/utils/strings.mjs +4 -0
  202. package/dist/admin/utils/strings.mjs.map +1 -0
  203. package/dist/server/bootstrap.js +81 -0
  204. package/dist/server/bootstrap.js.map +1 -0
  205. package/dist/server/bootstrap.mjs +79 -0
  206. package/dist/server/bootstrap.mjs.map +1 -0
  207. package/dist/server/constants/index.js +29 -0
  208. package/dist/server/constants/index.js.map +1 -0
  209. package/dist/server/constants/index.mjs +25 -0
  210. package/dist/server/constants/index.mjs.map +1 -0
  211. package/dist/server/constants/iso-locales.json.js +2427 -0
  212. package/dist/server/constants/iso-locales.json.js.map +1 -0
  213. package/dist/server/constants/iso-locales.json.mjs +2425 -0
  214. package/dist/server/constants/iso-locales.json.mjs.map +1 -0
  215. package/dist/server/content-types/index.js +10 -0
  216. package/dist/server/content-types/index.js.map +1 -0
  217. package/dist/server/content-types/index.mjs +8 -0
  218. package/dist/server/content-types/index.mjs.map +1 -0
  219. package/dist/server/content-types/locale/index.js +10 -0
  220. package/dist/server/content-types/locale/index.js.map +1 -0
  221. package/dist/server/content-types/locale/index.mjs +8 -0
  222. package/dist/server/content-types/locale/index.mjs.map +1 -0
  223. package/dist/server/content-types/locale/schema.json.js +46 -0
  224. package/dist/server/content-types/locale/schema.json.js.map +1 -0
  225. package/dist/server/content-types/locale/schema.json.mjs +38 -0
  226. package/dist/server/content-types/locale/schema.json.mjs.map +1 -0
  227. package/dist/server/controllers/ai-localization-jobs.js +47 -0
  228. package/dist/server/controllers/ai-localization-jobs.js.map +1 -0
  229. package/dist/server/controllers/ai-localization-jobs.mjs +45 -0
  230. package/dist/server/controllers/ai-localization-jobs.mjs.map +1 -0
  231. package/dist/server/controllers/content-types.js +76 -0
  232. package/dist/server/controllers/content-types.js.map +1 -0
  233. package/dist/server/controllers/content-types.mjs +74 -0
  234. package/dist/server/controllers/content-types.mjs.map +1 -0
  235. package/dist/server/controllers/index.js +18 -0
  236. package/dist/server/controllers/index.js.map +1 -0
  237. package/dist/server/controllers/index.mjs +16 -0
  238. package/dist/server/controllers/index.mjs.map +1 -0
  239. package/dist/server/controllers/iso-locales.js +13 -0
  240. package/dist/server/controllers/iso-locales.js.map +1 -0
  241. package/dist/server/controllers/iso-locales.mjs +11 -0
  242. package/dist/server/controllers/iso-locales.mjs.map +1 -0
  243. package/dist/server/controllers/locales.js +108 -0
  244. package/dist/server/controllers/locales.js.map +1 -0
  245. package/dist/server/controllers/locales.mjs +87 -0
  246. package/dist/server/controllers/locales.mjs.map +1 -0
  247. package/dist/server/controllers/settings.js +24 -0
  248. package/dist/server/controllers/settings.js.map +1 -0
  249. package/dist/server/controllers/settings.mjs +22 -0
  250. package/dist/server/controllers/settings.mjs.map +1 -0
  251. package/dist/server/controllers/validate-locale-creation.js +47 -0
  252. package/dist/server/controllers/validate-locale-creation.js.map +1 -0
  253. package/dist/server/controllers/validate-locale-creation.mjs +45 -0
  254. package/dist/server/controllers/validate-locale-creation.mjs.map +1 -0
  255. package/dist/server/domain/locale.js +11 -0
  256. package/dist/server/domain/locale.js.map +1 -0
  257. package/dist/server/domain/locale.mjs +9 -0
  258. package/dist/server/domain/locale.mjs.map +1 -0
  259. package/dist/server/graphql.js +115 -0
  260. package/dist/server/graphql.js.map +1 -0
  261. package/dist/server/graphql.mjs +113 -0
  262. package/dist/server/graphql.mjs.map +1 -0
  263. package/dist/server/index.js +18 -3549
  264. package/dist/server/index.js.map +1 -1
  265. package/dist/server/index.mjs +17 -3531
  266. package/dist/server/index.mjs.map +1 -1
  267. package/dist/server/models/ai-localization-job.js +60 -0
  268. package/dist/server/models/ai-localization-job.js.map +1 -0
  269. package/dist/server/models/ai-localization-job.mjs +57 -0
  270. package/dist/server/models/ai-localization-job.mjs.map +1 -0
  271. package/dist/server/register.js +81 -0
  272. package/dist/server/register.js.map +1 -0
  273. package/dist/server/register.mjs +79 -0
  274. package/dist/server/register.mjs.map +1 -0
  275. package/dist/server/routes/admin.js +142 -0
  276. package/dist/server/routes/admin.js.map +1 -0
  277. package/dist/server/routes/admin.mjs +140 -0
  278. package/dist/server/routes/admin.mjs.map +1 -0
  279. package/dist/server/routes/content-api.js +19 -0
  280. package/dist/server/routes/content-api.js.map +1 -0
  281. package/dist/server/routes/content-api.mjs +17 -0
  282. package/dist/server/routes/content-api.mjs.map +1 -0
  283. package/dist/server/routes/index.js +12 -0
  284. package/dist/server/routes/index.js.map +1 -0
  285. package/dist/server/routes/index.mjs +10 -0
  286. package/dist/server/routes/index.mjs.map +1 -0
  287. package/dist/server/routes/validation/locale.js +57 -0
  288. package/dist/server/routes/validation/locale.js.map +1 -0
  289. package/dist/server/routes/validation/locale.mjs +36 -0
  290. package/dist/server/routes/validation/locale.mjs.map +1 -0
  291. package/dist/server/services/ai-localization-jobs.js +64 -0
  292. package/dist/server/services/ai-localization-jobs.js.map +1 -0
  293. package/dist/server/services/ai-localization-jobs.mjs +62 -0
  294. package/dist/server/services/ai-localization-jobs.mjs.map +1 -0
  295. package/dist/server/services/ai-localizations.js +210 -0
  296. package/dist/server/services/ai-localizations.js.map +1 -0
  297. package/dist/server/services/ai-localizations.mjs +208 -0
  298. package/dist/server/services/ai-localizations.mjs.map +1 -0
  299. package/dist/server/services/content-types.js +157 -0
  300. package/dist/server/services/content-types.js.map +1 -0
  301. package/dist/server/services/content-types.mjs +155 -0
  302. package/dist/server/services/content-types.mjs.map +1 -0
  303. package/dist/server/services/index.js +28 -0
  304. package/dist/server/services/index.js.map +1 -0
  305. package/dist/server/services/index.mjs +26 -0
  306. package/dist/server/services/index.mjs.map +1 -0
  307. package/dist/server/services/iso-locales.js +12 -0
  308. package/dist/server/services/iso-locales.js.map +1 -0
  309. package/dist/server/services/iso-locales.mjs +10 -0
  310. package/dist/server/services/iso-locales.mjs.map +1 -0
  311. package/dist/server/services/locales.js +114 -0
  312. package/dist/server/services/locales.js.map +1 -0
  313. package/dist/server/services/locales.mjs +112 -0
  314. package/dist/server/services/locales.mjs.map +1 -0
  315. package/dist/server/services/localizations.js +68 -0
  316. package/dist/server/services/localizations.js.map +1 -0
  317. package/dist/server/services/localizations.mjs +66 -0
  318. package/dist/server/services/localizations.mjs.map +1 -0
  319. package/dist/server/services/metrics.js +30 -0
  320. package/dist/server/services/metrics.js.map +1 -0
  321. package/dist/server/services/metrics.mjs +28 -0
  322. package/dist/server/services/metrics.mjs.map +1 -0
  323. package/dist/server/services/permissions/actions.js +136 -0
  324. package/dist/server/services/permissions/actions.js.map +1 -0
  325. package/dist/server/services/permissions/actions.mjs +134 -0
  326. package/dist/server/services/permissions/actions.mjs.map +1 -0
  327. package/dist/server/services/permissions/engine.js +52 -0
  328. package/dist/server/services/permissions/engine.js.map +1 -0
  329. package/dist/server/services/permissions/engine.mjs +50 -0
  330. package/dist/server/services/permissions/engine.mjs.map +1 -0
  331. package/dist/server/services/permissions/sections-builder.js +45 -0
  332. package/dist/server/services/permissions/sections-builder.js.map +1 -0
  333. package/dist/server/services/permissions/sections-builder.mjs +43 -0
  334. package/dist/server/services/permissions/sections-builder.mjs.map +1 -0
  335. package/dist/server/services/permissions.js +14 -0
  336. package/dist/server/services/permissions.js.map +1 -0
  337. package/dist/server/services/permissions.mjs +12 -0
  338. package/dist/server/services/permissions.mjs.map +1 -0
  339. package/dist/server/services/sanitize/index.js +34 -0
  340. package/dist/server/services/sanitize/index.js.map +1 -0
  341. package/dist/server/services/sanitize/index.mjs +32 -0
  342. package/dist/server/services/sanitize/index.mjs.map +1 -0
  343. package/dist/server/services/settings.js +25 -0
  344. package/dist/server/services/settings.js.map +1 -0
  345. package/dist/server/services/settings.mjs +23 -0
  346. package/dist/server/services/settings.mjs.map +1 -0
  347. package/dist/server/src/bootstrap.d.ts +1 -4
  348. package/dist/server/src/bootstrap.d.ts.map +1 -1
  349. package/dist/server/src/controllers/ai-localization-jobs.d.ts +17 -0
  350. package/dist/server/src/controllers/ai-localization-jobs.d.ts.map +1 -0
  351. package/dist/server/src/controllers/index.d.ts +10 -0
  352. package/dist/server/src/controllers/index.d.ts.map +1 -1
  353. package/dist/server/src/controllers/settings.d.ts +7 -0
  354. package/dist/server/src/controllers/settings.d.ts.map +1 -0
  355. package/dist/server/src/index.d.ts +53 -18
  356. package/dist/server/src/index.d.ts.map +1 -1
  357. package/dist/server/src/models/ai-localization-job.d.ts +5 -0
  358. package/dist/server/src/models/ai-localization-job.d.ts.map +1 -0
  359. package/dist/server/src/models/index.d.ts +5 -0
  360. package/dist/server/src/models/index.d.ts.map +1 -0
  361. package/dist/server/src/register.d.ts +1 -1
  362. package/dist/server/src/register.d.ts.map +1 -1
  363. package/dist/server/src/routes/admin.d.ts.map +1 -1
  364. package/dist/server/src/routes/content-api.d.ts +5 -8
  365. package/dist/server/src/routes/content-api.d.ts.map +1 -1
  366. package/dist/server/src/routes/index.d.ts +3 -7
  367. package/dist/server/src/routes/index.d.ts.map +1 -1
  368. package/dist/server/src/routes/validation/index.d.ts +2 -0
  369. package/dist/server/src/routes/validation/index.d.ts.map +1 -0
  370. package/dist/server/src/routes/validation/locale.d.ts +41 -0
  371. package/dist/server/src/routes/validation/locale.d.ts.map +1 -0
  372. package/dist/server/src/services/ai-localization-jobs.d.ts +26 -0
  373. package/dist/server/src/services/ai-localization-jobs.d.ts.map +1 -0
  374. package/dist/server/src/services/ai-localizations.d.ts +18 -0
  375. package/dist/server/src/services/ai-localizations.d.ts.map +1 -0
  376. package/dist/server/src/services/index.d.ts +39 -8
  377. package/dist/server/src/services/index.d.ts.map +1 -1
  378. package/dist/server/src/services/localizations.d.ts +1 -1
  379. package/dist/server/src/services/localizations.d.ts.map +1 -1
  380. package/dist/server/src/services/sanitize/index.d.ts +11 -0
  381. package/dist/server/src/services/sanitize/index.d.ts.map +1 -0
  382. package/dist/server/src/services/settings.d.ts +13 -0
  383. package/dist/server/src/services/settings.d.ts.map +1 -0
  384. package/dist/server/src/utils/index.d.ts +9 -3
  385. package/dist/server/src/utils/index.d.ts.map +1 -1
  386. package/dist/server/src/validation/settings.d.ts +12 -0
  387. package/dist/server/src/validation/settings.d.ts.map +1 -0
  388. package/dist/server/utils/index.js +16 -0
  389. package/dist/server/utils/index.js.map +1 -0
  390. package/dist/server/utils/index.mjs +13 -0
  391. package/dist/server/utils/index.mjs.map +1 -0
  392. package/dist/server/validation/content-types.js +18 -0
  393. package/dist/server/validation/content-types.js.map +1 -0
  394. package/dist/server/validation/content-types.mjs +16 -0
  395. package/dist/server/validation/content-types.mjs.map +1 -0
  396. package/dist/server/validation/locales.js +23 -0
  397. package/dist/server/validation/locales.js.map +1 -0
  398. package/dist/server/validation/locales.mjs +20 -0
  399. package/dist/server/validation/locales.mjs.map +1 -0
  400. package/dist/server/validation/settings.js +11 -0
  401. package/dist/server/validation/settings.js.map +1 -0
  402. package/dist/server/validation/settings.mjs +9 -0
  403. package/dist/server/validation/settings.mjs.map +1 -0
  404. package/dist/shared/contracts/ai-localization-jobs.d.ts +27 -0
  405. package/dist/shared/contracts/ai-localization-jobs.d.ts.map +1 -0
  406. package/dist/shared/contracts/content-manager.d.ts +1 -1
  407. package/dist/shared/contracts/settings.d.ts +40 -0
  408. package/dist/shared/contracts/shared.d.ts +1 -1
  409. package/dist/shared/contracts/shared.d.ts.map +1 -0
  410. package/package.json +22 -17
  411. package/dist/_chunks/SettingsPage-BjxjwEOb.mjs +0 -554
  412. package/dist/_chunks/SettingsPage-BjxjwEOb.mjs.map +0 -1
  413. package/dist/_chunks/SettingsPage-CfTmCkup.js +0 -574
  414. package/dist/_chunks/SettingsPage-CfTmCkup.js.map +0 -1
  415. package/dist/_chunks/de-9eCAqqrB.mjs +0 -66
  416. package/dist/_chunks/de-9eCAqqrB.mjs.map +0 -1
  417. package/dist/_chunks/de-DtWiGdHl.js +0 -66
  418. package/dist/_chunks/de-DtWiGdHl.js.map +0 -1
  419. package/dist/_chunks/dk-2qBjxt-P.mjs +0 -66
  420. package/dist/_chunks/dk-2qBjxt-P.mjs.map +0 -1
  421. package/dist/_chunks/dk-D8C-casx.js +0 -66
  422. package/dist/_chunks/dk-D8C-casx.js.map +0 -1
  423. package/dist/_chunks/en-2xztdZE1.mjs +0 -80
  424. package/dist/_chunks/en-2xztdZE1.mjs.map +0 -1
  425. package/dist/_chunks/en-DWpfm8h5.js +0 -80
  426. package/dist/_chunks/en-DWpfm8h5.js.map +0 -1
  427. package/dist/_chunks/es-DS-XFGSw.js +0 -66
  428. package/dist/_chunks/es-DS-XFGSw.js.map +0 -1
  429. package/dist/_chunks/es-DlmMVaBG.mjs +0 -66
  430. package/dist/_chunks/es-DlmMVaBG.mjs.map +0 -1
  431. package/dist/_chunks/fr-3S6ke71d.mjs +0 -66
  432. package/dist/_chunks/fr-3S6ke71d.mjs.map +0 -1
  433. package/dist/_chunks/fr-BTjekDpq.js +0 -66
  434. package/dist/_chunks/fr-BTjekDpq.js.map +0 -1
  435. package/dist/_chunks/index-5XLZwzwx.js +0 -1586
  436. package/dist/_chunks/index-5XLZwzwx.js.map +0 -1
  437. package/dist/_chunks/index-D-qx3tz4.mjs +0 -1564
  438. package/dist/_chunks/index-D-qx3tz4.mjs.map +0 -1
  439. package/dist/_chunks/ko-DmcGUBQ3.js +0 -65
  440. package/dist/_chunks/ko-DmcGUBQ3.js.map +0 -1
  441. package/dist/_chunks/ko-qTjQ8IMw.mjs +0 -65
  442. package/dist/_chunks/ko-qTjQ8IMw.mjs.map +0 -1
  443. package/dist/_chunks/pl-B67TSHqT.mjs +0 -66
  444. package/dist/_chunks/pl-B67TSHqT.mjs.map +0 -1
  445. package/dist/_chunks/pl-Cn5RYonZ.js +0 -66
  446. package/dist/_chunks/pl-Cn5RYonZ.js.map +0 -1
  447. package/dist/_chunks/ru-BMBgVL3s.js +0 -68
  448. package/dist/_chunks/ru-BMBgVL3s.js.map +0 -1
  449. package/dist/_chunks/ru-hagMa57T.mjs +0 -68
  450. package/dist/_chunks/ru-hagMa57T.mjs.map +0 -1
  451. package/dist/_chunks/tr-CarUU76c.js +0 -66
  452. package/dist/_chunks/tr-CarUU76c.js.map +0 -1
  453. package/dist/_chunks/tr-Dw_jmkG-.mjs +0 -66
  454. package/dist/_chunks/tr-Dw_jmkG-.mjs.map +0 -1
  455. package/dist/_chunks/zh-57YM4amO.mjs +0 -66
  456. package/dist/_chunks/zh-57YM4amO.mjs.map +0 -1
  457. package/dist/_chunks/zh-CukOviB0.js +0 -66
  458. package/dist/_chunks/zh-CukOviB0.js.map +0 -1
  459. package/dist/_chunks/zh-Hans-DSHIXAa3.js +0 -57
  460. package/dist/_chunks/zh-Hans-DSHIXAa3.js.map +0 -1
  461. package/dist/_chunks/zh-Hans-Dyc-aR-h.mjs +0 -57
  462. package/dist/_chunks/zh-Hans-Dyc-aR-h.mjs.map +0 -1
  463. package/dist/server/src/migrations/content-type/disable/index.d.ts +0 -3
  464. package/dist/server/src/migrations/content-type/disable/index.d.ts.map +0 -1
  465. package/dist/server/src/migrations/content-type/enable/index.d.ts +0 -3
  466. package/dist/server/src/migrations/content-type/enable/index.d.ts.map +0 -1
  467. package/dist/server/src/services/entity-service-decorator.d.ts +0 -29
  468. package/dist/server/src/services/entity-service-decorator.d.ts.map +0 -1
  469. package/strapi-server.js +0 -3
@@ -0,0 +1,210 @@
1
+ 'use strict';
2
+
3
+ var utils = require('@strapi/utils');
4
+ var index = require('../utils/index.js');
5
+
6
+ const createAILocalizationsService = ({ strapi })=>{
7
+ // TODO: add a helper function to get the AI server URL
8
+ const aiServerUrl = process.env.STRAPI_AI_URL || 'https://strapi-ai.apps.strapi.io';
9
+ const aiLocalizationJobsService = index.getService('ai-localization-jobs');
10
+ return {
11
+ // Async to avoid changing the signature later (there will be a db check in the future)
12
+ async isEnabled () {
13
+ // Check if future flag is enabled
14
+ const isFutureFlagEnabled = strapi.features.future.isEnabled('unstableAILocalizations');
15
+ if (!isFutureFlagEnabled) {
16
+ return false;
17
+ }
18
+ // Check if user disabled AI features globally
19
+ const isAIEnabled = strapi.config.get('admin.ai.enabled', true);
20
+ if (!isAIEnabled) {
21
+ return false;
22
+ }
23
+ // Check if the user's license grants access to AI features
24
+ const hasAccess = strapi.ee.features.isEnabled('cms-ai');
25
+ if (!hasAccess) {
26
+ return false;
27
+ }
28
+ const settings = index.getService('settings');
29
+ const aiSettings = await settings.getSettings();
30
+ if (!aiSettings?.aiLocalizations) {
31
+ return false;
32
+ }
33
+ return true;
34
+ },
35
+ /**
36
+ * Checks if there are localizations that need to be generated for the given document,
37
+ * and if so, calls the AI service and saves the results to the database.
38
+ * Works for both single and collection types, on create and update.
39
+ */ async generateDocumentLocalizations ({ model, document }) {
40
+ const isFeatureEnabled = await this.isEnabled();
41
+ if (!isFeatureEnabled) {
42
+ return;
43
+ }
44
+ const schema = strapi.getModel(model);
45
+ const localeService = index.getService('locales');
46
+ // No localizations needed for content types with i18n disabled
47
+ const isLocalizedContentType = index.getService('content-types').isLocalizedContentType(schema);
48
+ if (!isLocalizedContentType) {
49
+ return;
50
+ }
51
+ // Don't trigger localizations if the update is on a derived locale, only do it on the default
52
+ const defaultLocale = await localeService.getDefaultLocale();
53
+ if (document?.locale !== defaultLocale) {
54
+ return;
55
+ }
56
+ const documentId = document.documentId;
57
+ if (!documentId) {
58
+ strapi.log.warn(`AI Localizations: missing documentId for ${schema.uid}`);
59
+ return;
60
+ }
61
+ // Extract only the localized content from the document
62
+ const translateableContent = await utils.traverseEntity(({ key, attribute }, { remove })=>{
63
+ const hasLocalizedOption = attribute?.pluginOptions?.i18n?.localized === true;
64
+ // Only keep fields that actually need to be localized
65
+ // TODO: remove blocks from this list once the AI server can handle it reliably
66
+ if (!hasLocalizedOption || [
67
+ 'media',
68
+ 'blocks'
69
+ ].includes(attribute.type)) {
70
+ remove(key);
71
+ }
72
+ }, {
73
+ schema,
74
+ getModel: strapi.getModel.bind(strapi)
75
+ }, document);
76
+ // Call the AI server to get the localized content
77
+ const localesList = await localeService.find();
78
+ const targetLocales = localesList.filter((l)=>l.code !== document.locale).map((l)=>l.code);
79
+ if (targetLocales.length === 0) {
80
+ strapi.log.info(`AI Localizations: no target locales for ${schema.uid} document ${documentId}`);
81
+ return;
82
+ }
83
+ await aiLocalizationJobsService.upsertJobForDocument({
84
+ contentType: model,
85
+ documentId,
86
+ sourceLocale: document.locale,
87
+ targetLocales,
88
+ status: 'processing'
89
+ });
90
+ let token;
91
+ try {
92
+ const tokenData = await strapi.service('admin::user').getAiToken();
93
+ token = tokenData.token;
94
+ } catch (error) {
95
+ await aiLocalizationJobsService.upsertJobForDocument({
96
+ documentId,
97
+ contentType: model,
98
+ sourceLocale: document.locale,
99
+ targetLocales,
100
+ status: 'failed'
101
+ });
102
+ throw new Error('Failed to retrieve AI token', {
103
+ cause: error instanceof Error ? error : undefined
104
+ });
105
+ }
106
+ strapi.log.http('Contacting AI Server for localizations generation');
107
+ const response = await fetch(`${aiServerUrl}/i18n/generate-localizations`, {
108
+ method: 'POST',
109
+ headers: {
110
+ 'Content-Type': 'application/json',
111
+ Authorization: `Bearer ${token}`
112
+ },
113
+ body: JSON.stringify({
114
+ content: translateableContent,
115
+ sourceLocale: document.locale,
116
+ targetLocales
117
+ })
118
+ });
119
+ if (!response.ok) {
120
+ strapi.log.error(`AI Localizations request failed: ${response.status} ${response.statusText}`);
121
+ await aiLocalizationJobsService.upsertJobForDocument({
122
+ documentId,
123
+ contentType: model,
124
+ sourceLocale: document.locale,
125
+ targetLocales,
126
+ status: 'failed'
127
+ });
128
+ throw new Error(`AI Localizations request failed: ${response.statusText}`);
129
+ } else {
130
+ await aiLocalizationJobsService.upsertJobForDocument({
131
+ documentId,
132
+ contentType: model,
133
+ sourceLocale: document.locale,
134
+ targetLocales,
135
+ status: 'completed'
136
+ });
137
+ }
138
+ const aiResult = await response.json();
139
+ // Get all media field names dynamically from the schema
140
+ const mediaFields = Object.entries(schema.attributes)// eslint-disable-next-line @typescript-eslint/no-unused-vars
141
+ .filter(([_, attr])=>attr.type === 'media').map(([key])=>key);
142
+ try {
143
+ await Promise.allSettled(aiResult.localizations.map(async (localization)=>{
144
+ const { content, locale } = localization;
145
+ // Fetch the derived locale document
146
+ const derivedDoc = await strapi.documents(model).findOne({
147
+ documentId,
148
+ locale,
149
+ populate: mediaFields
150
+ });
151
+ // Merge AI content and media fields
152
+ const mergedData = {
153
+ ...content
154
+ };
155
+ for (const field of mediaFields){
156
+ // Only copy media if not already set in derived locale
157
+ if (!derivedDoc || !derivedDoc[field]) {
158
+ mergedData[field] = document[field];
159
+ } else {
160
+ mergedData[field] = derivedDoc[field];
161
+ }
162
+ }
163
+ return strapi.documents(model).update({
164
+ documentId,
165
+ locale,
166
+ fields: [],
167
+ data: mergedData
168
+ });
169
+ }));
170
+ } catch (error) {
171
+ await aiLocalizationJobsService.upsertJobForDocument({
172
+ documentId,
173
+ contentType: model,
174
+ sourceLocale: document.locale,
175
+ targetLocales,
176
+ status: 'failed'
177
+ });
178
+ strapi.log.error('AI Localizations generation failed', error);
179
+ }
180
+ },
181
+ setupMiddleware () {
182
+ strapi.documents.use(async (context, next)=>{
183
+ const result = await next();
184
+ // Only trigger on create/update actions
185
+ if (![
186
+ 'create',
187
+ 'update'
188
+ ].includes(context.action)) {
189
+ return result;
190
+ }
191
+ // Check if AI localizations are enabled before triggering
192
+ const isEnabled = await this.isEnabled();
193
+ if (!isEnabled) {
194
+ return result;
195
+ }
196
+ // Don't await since localizations should be done in the background without blocking the request
197
+ strapi.plugin('i18n').service('ai-localizations').generateDocumentLocalizations({
198
+ model: context.contentType.uid,
199
+ document: result
200
+ }).catch((error)=>{
201
+ strapi.log.error('AI Localizations generation failed', error);
202
+ });
203
+ return result;
204
+ });
205
+ }
206
+ };
207
+ };
208
+
209
+ exports.createAILocalizationsService = createAILocalizationsService;
210
+ //# sourceMappingURL=ai-localizations.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ai-localizations.js","sources":["../../../server/src/services/ai-localizations.ts"],"sourcesContent":["import type { Core, Modules, UID } from '@strapi/types';\nimport { traverseEntity } from '@strapi/utils';\nimport { getService } from '../utils';\n\nconst createAILocalizationsService = ({ strapi }: { strapi: Core.Strapi }) => {\n // TODO: add a helper function to get the AI server URL\n const aiServerUrl = process.env.STRAPI_AI_URL || 'https://strapi-ai.apps.strapi.io';\n const aiLocalizationJobsService = getService('ai-localization-jobs');\n\n return {\n // Async to avoid changing the signature later (there will be a db check in the future)\n async isEnabled() {\n // Check if future flag is enabled\n const isFutureFlagEnabled = strapi.features.future.isEnabled('unstableAILocalizations');\n if (!isFutureFlagEnabled) {\n return false;\n }\n\n // Check if user disabled AI features globally\n const isAIEnabled = strapi.config.get('admin.ai.enabled', true);\n if (!isAIEnabled) {\n return false;\n }\n\n // Check if the user's license grants access to AI features\n const hasAccess = strapi.ee.features.isEnabled('cms-ai');\n if (!hasAccess) {\n return false;\n }\n\n const settings = getService('settings');\n const aiSettings = await settings.getSettings();\n if (!aiSettings?.aiLocalizations) {\n return false;\n }\n\n return true;\n },\n\n /**\n * Checks if there are localizations that need to be generated for the given document,\n * and if so, calls the AI service and saves the results to the database.\n * Works for both single and collection types, on create and update.\n */\n async generateDocumentLocalizations({\n model,\n document,\n }: {\n model: UID.ContentType;\n document: Modules.Documents.AnyDocument;\n }) {\n const isFeatureEnabled = await this.isEnabled();\n if (!isFeatureEnabled) {\n return;\n }\n\n const schema = strapi.getModel(model);\n const localeService = getService('locales');\n\n // No localizations needed for content types with i18n disabled\n const isLocalizedContentType = getService('content-types').isLocalizedContentType(schema);\n if (!isLocalizedContentType) {\n return;\n }\n\n // Don't trigger localizations if the update is on a derived locale, only do it on the default\n const defaultLocale = await localeService.getDefaultLocale();\n if (document?.locale !== defaultLocale) {\n return;\n }\n\n const documentId = document.documentId;\n\n if (!documentId) {\n strapi.log.warn(`AI Localizations: missing documentId for ${schema.uid}`);\n return;\n }\n\n // Extract only the localized content from the document\n const translateableContent = await traverseEntity(\n ({ key, attribute }, { remove }) => {\n const hasLocalizedOption = attribute?.pluginOptions?.i18n?.localized === true;\n // Only keep fields that actually need to be localized\n // TODO: remove blocks from this list once the AI server can handle it reliably\n if (!hasLocalizedOption || ['media', 'blocks'].includes(attribute.type)) {\n remove(key);\n }\n },\n { schema, getModel: strapi.getModel.bind(strapi) },\n document\n );\n\n // Call the AI server to get the localized content\n const localesList = await localeService.find();\n const targetLocales = localesList\n .filter((l) => l.code !== document.locale)\n .map((l) => l.code);\n\n if (targetLocales.length === 0) {\n strapi.log.info(\n `AI Localizations: no target locales for ${schema.uid} document ${documentId}`\n );\n return;\n }\n\n await aiLocalizationJobsService.upsertJobForDocument({\n contentType: model,\n documentId,\n sourceLocale: document.locale,\n targetLocales,\n status: 'processing',\n });\n\n let token: string;\n try {\n const tokenData = await strapi.service('admin::user').getAiToken();\n token = tokenData.token;\n } catch (error) {\n await aiLocalizationJobsService.upsertJobForDocument({\n documentId,\n contentType: model,\n sourceLocale: document.locale,\n targetLocales,\n status: 'failed',\n });\n\n throw new Error('Failed to retrieve AI token', {\n cause: error instanceof Error ? error : undefined,\n });\n }\n\n strapi.log.http('Contacting AI Server for localizations generation');\n const response = await fetch(`${aiServerUrl}/i18n/generate-localizations`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${token}`,\n },\n body: JSON.stringify({\n content: translateableContent,\n sourceLocale: document.locale,\n targetLocales,\n }),\n });\n\n if (!response.ok) {\n strapi.log.error(\n `AI Localizations request failed: ${response.status} ${response.statusText}`\n );\n\n await aiLocalizationJobsService.upsertJobForDocument({\n documentId,\n contentType: model,\n sourceLocale: document.locale,\n targetLocales,\n status: 'failed',\n });\n\n throw new Error(`AI Localizations request failed: ${response.statusText}`);\n } else {\n await aiLocalizationJobsService.upsertJobForDocument({\n documentId,\n contentType: model,\n sourceLocale: document.locale,\n targetLocales,\n status: 'completed',\n });\n }\n\n const aiResult = await response.json();\n\n // Get all media field names dynamically from the schema\n const mediaFields = Object.entries(schema.attributes)\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n .filter(([_, attr]) => attr.type === 'media')\n .map(([key]) => key);\n\n try {\n await Promise.allSettled(\n aiResult.localizations.map(async (localization: any) => {\n const { content, locale } = localization;\n\n // Fetch the derived locale document\n const derivedDoc = await strapi.documents(model).findOne({\n documentId,\n locale,\n populate: mediaFields,\n });\n\n // Merge AI content and media fields\n const mergedData = { ...content };\n for (const field of mediaFields) {\n // Only copy media if not already set in derived locale\n if (!derivedDoc || !derivedDoc[field]) {\n mergedData[field] = document[field];\n } else {\n mergedData[field] = derivedDoc[field];\n }\n }\n\n return strapi.documents(model).update({\n documentId,\n locale,\n fields: [],\n data: mergedData,\n });\n })\n );\n } catch (error) {\n await aiLocalizationJobsService.upsertJobForDocument({\n documentId,\n contentType: model,\n sourceLocale: document.locale,\n targetLocales,\n status: 'failed',\n });\n strapi.log.error('AI Localizations generation failed', error);\n }\n },\n setupMiddleware() {\n strapi.documents.use(async (context, next) => {\n const result = await next();\n\n // Only trigger on create/update actions\n if (!['create', 'update'].includes(context.action)) {\n return result;\n }\n\n // Check if AI localizations are enabled before triggering\n const isEnabled = await this.isEnabled();\n if (!isEnabled) {\n return result;\n }\n\n // Don't await since localizations should be done in the background without blocking the request\n strapi\n .plugin('i18n')\n .service('ai-localizations')\n .generateDocumentLocalizations({\n model: context.contentType.uid,\n document: result,\n })\n .catch((error: any) => {\n strapi.log.error('AI Localizations generation failed', error);\n });\n\n return result;\n });\n },\n };\n};\n\nexport { createAILocalizationsService };\n"],"names":["createAILocalizationsService","strapi","aiServerUrl","process","env","STRAPI_AI_URL","aiLocalizationJobsService","getService","isEnabled","isFutureFlagEnabled","features","future","isAIEnabled","config","get","hasAccess","ee","settings","aiSettings","getSettings","aiLocalizations","generateDocumentLocalizations","model","document","isFeatureEnabled","schema","getModel","localeService","isLocalizedContentType","defaultLocale","getDefaultLocale","locale","documentId","log","warn","uid","translateableContent","traverseEntity","key","attribute","remove","hasLocalizedOption","pluginOptions","i18n","localized","includes","type","bind","localesList","find","targetLocales","filter","l","code","map","length","info","upsertJobForDocument","contentType","sourceLocale","status","token","tokenData","service","getAiToken","error","Error","cause","undefined","http","response","fetch","method","headers","Authorization","body","JSON","stringify","content","ok","statusText","aiResult","json","mediaFields","Object","entries","attributes","_","attr","Promise","allSettled","localizations","localization","derivedDoc","documents","findOne","populate","mergedData","field","update","fields","data","setupMiddleware","use","context","next","result","action","plugin","catch"],"mappings":"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"}
@@ -0,0 +1,208 @@
1
+ import { traverseEntity } from '@strapi/utils';
2
+ import { getService } from '../utils/index.mjs';
3
+
4
+ const createAILocalizationsService = ({ strapi })=>{
5
+ // TODO: add a helper function to get the AI server URL
6
+ const aiServerUrl = process.env.STRAPI_AI_URL || 'https://strapi-ai.apps.strapi.io';
7
+ const aiLocalizationJobsService = getService('ai-localization-jobs');
8
+ return {
9
+ // Async to avoid changing the signature later (there will be a db check in the future)
10
+ async isEnabled () {
11
+ // Check if future flag is enabled
12
+ const isFutureFlagEnabled = strapi.features.future.isEnabled('unstableAILocalizations');
13
+ if (!isFutureFlagEnabled) {
14
+ return false;
15
+ }
16
+ // Check if user disabled AI features globally
17
+ const isAIEnabled = strapi.config.get('admin.ai.enabled', true);
18
+ if (!isAIEnabled) {
19
+ return false;
20
+ }
21
+ // Check if the user's license grants access to AI features
22
+ const hasAccess = strapi.ee.features.isEnabled('cms-ai');
23
+ if (!hasAccess) {
24
+ return false;
25
+ }
26
+ const settings = getService('settings');
27
+ const aiSettings = await settings.getSettings();
28
+ if (!aiSettings?.aiLocalizations) {
29
+ return false;
30
+ }
31
+ return true;
32
+ },
33
+ /**
34
+ * Checks if there are localizations that need to be generated for the given document,
35
+ * and if so, calls the AI service and saves the results to the database.
36
+ * Works for both single and collection types, on create and update.
37
+ */ async generateDocumentLocalizations ({ model, document }) {
38
+ const isFeatureEnabled = await this.isEnabled();
39
+ if (!isFeatureEnabled) {
40
+ return;
41
+ }
42
+ const schema = strapi.getModel(model);
43
+ const localeService = getService('locales');
44
+ // No localizations needed for content types with i18n disabled
45
+ const isLocalizedContentType = getService('content-types').isLocalizedContentType(schema);
46
+ if (!isLocalizedContentType) {
47
+ return;
48
+ }
49
+ // Don't trigger localizations if the update is on a derived locale, only do it on the default
50
+ const defaultLocale = await localeService.getDefaultLocale();
51
+ if (document?.locale !== defaultLocale) {
52
+ return;
53
+ }
54
+ const documentId = document.documentId;
55
+ if (!documentId) {
56
+ strapi.log.warn(`AI Localizations: missing documentId for ${schema.uid}`);
57
+ return;
58
+ }
59
+ // Extract only the localized content from the document
60
+ const translateableContent = await traverseEntity(({ key, attribute }, { remove })=>{
61
+ const hasLocalizedOption = attribute?.pluginOptions?.i18n?.localized === true;
62
+ // Only keep fields that actually need to be localized
63
+ // TODO: remove blocks from this list once the AI server can handle it reliably
64
+ if (!hasLocalizedOption || [
65
+ 'media',
66
+ 'blocks'
67
+ ].includes(attribute.type)) {
68
+ remove(key);
69
+ }
70
+ }, {
71
+ schema,
72
+ getModel: strapi.getModel.bind(strapi)
73
+ }, document);
74
+ // Call the AI server to get the localized content
75
+ const localesList = await localeService.find();
76
+ const targetLocales = localesList.filter((l)=>l.code !== document.locale).map((l)=>l.code);
77
+ if (targetLocales.length === 0) {
78
+ strapi.log.info(`AI Localizations: no target locales for ${schema.uid} document ${documentId}`);
79
+ return;
80
+ }
81
+ await aiLocalizationJobsService.upsertJobForDocument({
82
+ contentType: model,
83
+ documentId,
84
+ sourceLocale: document.locale,
85
+ targetLocales,
86
+ status: 'processing'
87
+ });
88
+ let token;
89
+ try {
90
+ const tokenData = await strapi.service('admin::user').getAiToken();
91
+ token = tokenData.token;
92
+ } catch (error) {
93
+ await aiLocalizationJobsService.upsertJobForDocument({
94
+ documentId,
95
+ contentType: model,
96
+ sourceLocale: document.locale,
97
+ targetLocales,
98
+ status: 'failed'
99
+ });
100
+ throw new Error('Failed to retrieve AI token', {
101
+ cause: error instanceof Error ? error : undefined
102
+ });
103
+ }
104
+ strapi.log.http('Contacting AI Server for localizations generation');
105
+ const response = await fetch(`${aiServerUrl}/i18n/generate-localizations`, {
106
+ method: 'POST',
107
+ headers: {
108
+ 'Content-Type': 'application/json',
109
+ Authorization: `Bearer ${token}`
110
+ },
111
+ body: JSON.stringify({
112
+ content: translateableContent,
113
+ sourceLocale: document.locale,
114
+ targetLocales
115
+ })
116
+ });
117
+ if (!response.ok) {
118
+ strapi.log.error(`AI Localizations request failed: ${response.status} ${response.statusText}`);
119
+ await aiLocalizationJobsService.upsertJobForDocument({
120
+ documentId,
121
+ contentType: model,
122
+ sourceLocale: document.locale,
123
+ targetLocales,
124
+ status: 'failed'
125
+ });
126
+ throw new Error(`AI Localizations request failed: ${response.statusText}`);
127
+ } else {
128
+ await aiLocalizationJobsService.upsertJobForDocument({
129
+ documentId,
130
+ contentType: model,
131
+ sourceLocale: document.locale,
132
+ targetLocales,
133
+ status: 'completed'
134
+ });
135
+ }
136
+ const aiResult = await response.json();
137
+ // Get all media field names dynamically from the schema
138
+ const mediaFields = Object.entries(schema.attributes)// eslint-disable-next-line @typescript-eslint/no-unused-vars
139
+ .filter(([_, attr])=>attr.type === 'media').map(([key])=>key);
140
+ try {
141
+ await Promise.allSettled(aiResult.localizations.map(async (localization)=>{
142
+ const { content, locale } = localization;
143
+ // Fetch the derived locale document
144
+ const derivedDoc = await strapi.documents(model).findOne({
145
+ documentId,
146
+ locale,
147
+ populate: mediaFields
148
+ });
149
+ // Merge AI content and media fields
150
+ const mergedData = {
151
+ ...content
152
+ };
153
+ for (const field of mediaFields){
154
+ // Only copy media if not already set in derived locale
155
+ if (!derivedDoc || !derivedDoc[field]) {
156
+ mergedData[field] = document[field];
157
+ } else {
158
+ mergedData[field] = derivedDoc[field];
159
+ }
160
+ }
161
+ return strapi.documents(model).update({
162
+ documentId,
163
+ locale,
164
+ fields: [],
165
+ data: mergedData
166
+ });
167
+ }));
168
+ } catch (error) {
169
+ await aiLocalizationJobsService.upsertJobForDocument({
170
+ documentId,
171
+ contentType: model,
172
+ sourceLocale: document.locale,
173
+ targetLocales,
174
+ status: 'failed'
175
+ });
176
+ strapi.log.error('AI Localizations generation failed', error);
177
+ }
178
+ },
179
+ setupMiddleware () {
180
+ strapi.documents.use(async (context, next)=>{
181
+ const result = await next();
182
+ // Only trigger on create/update actions
183
+ if (![
184
+ 'create',
185
+ 'update'
186
+ ].includes(context.action)) {
187
+ return result;
188
+ }
189
+ // Check if AI localizations are enabled before triggering
190
+ const isEnabled = await this.isEnabled();
191
+ if (!isEnabled) {
192
+ return result;
193
+ }
194
+ // Don't await since localizations should be done in the background without blocking the request
195
+ strapi.plugin('i18n').service('ai-localizations').generateDocumentLocalizations({
196
+ model: context.contentType.uid,
197
+ document: result
198
+ }).catch((error)=>{
199
+ strapi.log.error('AI Localizations generation failed', error);
200
+ });
201
+ return result;
202
+ });
203
+ }
204
+ };
205
+ };
206
+
207
+ export { createAILocalizationsService };
208
+ //# sourceMappingURL=ai-localizations.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ai-localizations.mjs","sources":["../../../server/src/services/ai-localizations.ts"],"sourcesContent":["import type { Core, Modules, UID } from '@strapi/types';\nimport { traverseEntity } from '@strapi/utils';\nimport { getService } from '../utils';\n\nconst createAILocalizationsService = ({ strapi }: { strapi: Core.Strapi }) => {\n // TODO: add a helper function to get the AI server URL\n const aiServerUrl = process.env.STRAPI_AI_URL || 'https://strapi-ai.apps.strapi.io';\n const aiLocalizationJobsService = getService('ai-localization-jobs');\n\n return {\n // Async to avoid changing the signature later (there will be a db check in the future)\n async isEnabled() {\n // Check if future flag is enabled\n const isFutureFlagEnabled = strapi.features.future.isEnabled('unstableAILocalizations');\n if (!isFutureFlagEnabled) {\n return false;\n }\n\n // Check if user disabled AI features globally\n const isAIEnabled = strapi.config.get('admin.ai.enabled', true);\n if (!isAIEnabled) {\n return false;\n }\n\n // Check if the user's license grants access to AI features\n const hasAccess = strapi.ee.features.isEnabled('cms-ai');\n if (!hasAccess) {\n return false;\n }\n\n const settings = getService('settings');\n const aiSettings = await settings.getSettings();\n if (!aiSettings?.aiLocalizations) {\n return false;\n }\n\n return true;\n },\n\n /**\n * Checks if there are localizations that need to be generated for the given document,\n * and if so, calls the AI service and saves the results to the database.\n * Works for both single and collection types, on create and update.\n */\n async generateDocumentLocalizations({\n model,\n document,\n }: {\n model: UID.ContentType;\n document: Modules.Documents.AnyDocument;\n }) {\n const isFeatureEnabled = await this.isEnabled();\n if (!isFeatureEnabled) {\n return;\n }\n\n const schema = strapi.getModel(model);\n const localeService = getService('locales');\n\n // No localizations needed for content types with i18n disabled\n const isLocalizedContentType = getService('content-types').isLocalizedContentType(schema);\n if (!isLocalizedContentType) {\n return;\n }\n\n // Don't trigger localizations if the update is on a derived locale, only do it on the default\n const defaultLocale = await localeService.getDefaultLocale();\n if (document?.locale !== defaultLocale) {\n return;\n }\n\n const documentId = document.documentId;\n\n if (!documentId) {\n strapi.log.warn(`AI Localizations: missing documentId for ${schema.uid}`);\n return;\n }\n\n // Extract only the localized content from the document\n const translateableContent = await traverseEntity(\n ({ key, attribute }, { remove }) => {\n const hasLocalizedOption = attribute?.pluginOptions?.i18n?.localized === true;\n // Only keep fields that actually need to be localized\n // TODO: remove blocks from this list once the AI server can handle it reliably\n if (!hasLocalizedOption || ['media', 'blocks'].includes(attribute.type)) {\n remove(key);\n }\n },\n { schema, getModel: strapi.getModel.bind(strapi) },\n document\n );\n\n // Call the AI server to get the localized content\n const localesList = await localeService.find();\n const targetLocales = localesList\n .filter((l) => l.code !== document.locale)\n .map((l) => l.code);\n\n if (targetLocales.length === 0) {\n strapi.log.info(\n `AI Localizations: no target locales for ${schema.uid} document ${documentId}`\n );\n return;\n }\n\n await aiLocalizationJobsService.upsertJobForDocument({\n contentType: model,\n documentId,\n sourceLocale: document.locale,\n targetLocales,\n status: 'processing',\n });\n\n let token: string;\n try {\n const tokenData = await strapi.service('admin::user').getAiToken();\n token = tokenData.token;\n } catch (error) {\n await aiLocalizationJobsService.upsertJobForDocument({\n documentId,\n contentType: model,\n sourceLocale: document.locale,\n targetLocales,\n status: 'failed',\n });\n\n throw new Error('Failed to retrieve AI token', {\n cause: error instanceof Error ? error : undefined,\n });\n }\n\n strapi.log.http('Contacting AI Server for localizations generation');\n const response = await fetch(`${aiServerUrl}/i18n/generate-localizations`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${token}`,\n },\n body: JSON.stringify({\n content: translateableContent,\n sourceLocale: document.locale,\n targetLocales,\n }),\n });\n\n if (!response.ok) {\n strapi.log.error(\n `AI Localizations request failed: ${response.status} ${response.statusText}`\n );\n\n await aiLocalizationJobsService.upsertJobForDocument({\n documentId,\n contentType: model,\n sourceLocale: document.locale,\n targetLocales,\n status: 'failed',\n });\n\n throw new Error(`AI Localizations request failed: ${response.statusText}`);\n } else {\n await aiLocalizationJobsService.upsertJobForDocument({\n documentId,\n contentType: model,\n sourceLocale: document.locale,\n targetLocales,\n status: 'completed',\n });\n }\n\n const aiResult = await response.json();\n\n // Get all media field names dynamically from the schema\n const mediaFields = Object.entries(schema.attributes)\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n .filter(([_, attr]) => attr.type === 'media')\n .map(([key]) => key);\n\n try {\n await Promise.allSettled(\n aiResult.localizations.map(async (localization: any) => {\n const { content, locale } = localization;\n\n // Fetch the derived locale document\n const derivedDoc = await strapi.documents(model).findOne({\n documentId,\n locale,\n populate: mediaFields,\n });\n\n // Merge AI content and media fields\n const mergedData = { ...content };\n for (const field of mediaFields) {\n // Only copy media if not already set in derived locale\n if (!derivedDoc || !derivedDoc[field]) {\n mergedData[field] = document[field];\n } else {\n mergedData[field] = derivedDoc[field];\n }\n }\n\n return strapi.documents(model).update({\n documentId,\n locale,\n fields: [],\n data: mergedData,\n });\n })\n );\n } catch (error) {\n await aiLocalizationJobsService.upsertJobForDocument({\n documentId,\n contentType: model,\n sourceLocale: document.locale,\n targetLocales,\n status: 'failed',\n });\n strapi.log.error('AI Localizations generation failed', error);\n }\n },\n setupMiddleware() {\n strapi.documents.use(async (context, next) => {\n const result = await next();\n\n // Only trigger on create/update actions\n if (!['create', 'update'].includes(context.action)) {\n return result;\n }\n\n // Check if AI localizations are enabled before triggering\n const isEnabled = await this.isEnabled();\n if (!isEnabled) {\n return result;\n }\n\n // Don't await since localizations should be done in the background without blocking the request\n strapi\n .plugin('i18n')\n .service('ai-localizations')\n .generateDocumentLocalizations({\n model: context.contentType.uid,\n document: result,\n })\n .catch((error: any) => {\n strapi.log.error('AI Localizations generation failed', error);\n });\n\n return result;\n });\n },\n };\n};\n\nexport { createAILocalizationsService };\n"],"names":["createAILocalizationsService","strapi","aiServerUrl","process","env","STRAPI_AI_URL","aiLocalizationJobsService","getService","isEnabled","isFutureFlagEnabled","features","future","isAIEnabled","config","get","hasAccess","ee","settings","aiSettings","getSettings","aiLocalizations","generateDocumentLocalizations","model","document","isFeatureEnabled","schema","getModel","localeService","isLocalizedContentType","defaultLocale","getDefaultLocale","locale","documentId","log","warn","uid","translateableContent","traverseEntity","key","attribute","remove","hasLocalizedOption","pluginOptions","i18n","localized","includes","type","bind","localesList","find","targetLocales","filter","l","code","map","length","info","upsertJobForDocument","contentType","sourceLocale","status","token","tokenData","service","getAiToken","error","Error","cause","undefined","http","response","fetch","method","headers","Authorization","body","JSON","stringify","content","ok","statusText","aiResult","json","mediaFields","Object","entries","attributes","_","attr","Promise","allSettled","localizations","localization","derivedDoc","documents","findOne","populate","mergedData","field","update","fields","data","setupMiddleware","use","context","next","result","action","plugin","catch"],"mappings":"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"}
@@ -0,0 +1,157 @@
1
+ 'use strict';
2
+
3
+ var _ = require('lodash');
4
+ var fp = require('lodash/fp');
5
+ var utils = require('@strapi/utils');
6
+ var index = require('../utils/index.js');
7
+
8
+ const { isRelationalAttribute, getVisibleAttributes, isTypedAttribute, getScalarAttributes, getRelationalAttributes } = utils.contentTypes;
9
+ const { ApplicationError } = utils.errors;
10
+ const hasLocalizedOption = (modelOrAttribute)=>{
11
+ return fp.prop('pluginOptions.i18n.localized', modelOrAttribute) === true;
12
+ };
13
+ const getValidLocale = async (locale)=>{
14
+ const localesService = index.getService('locales');
15
+ if (fp.isNil(locale)) {
16
+ return localesService.getDefaultLocale();
17
+ }
18
+ const foundLocale = await localesService.findByCode(locale);
19
+ if (!foundLocale) {
20
+ throw new ApplicationError('Locale not found');
21
+ }
22
+ return locale;
23
+ };
24
+ /**
25
+ * Returns whether an attribute is localized or not
26
+ * @param {*} attribute
27
+ * @returns
28
+ */ const isLocalizedAttribute = (attribute)=>{
29
+ return hasLocalizedOption(attribute) || isRelationalAttribute(attribute) || isTypedAttribute(attribute, 'uid');
30
+ };
31
+ /**
32
+ * Returns whether a model is localized or not
33
+ * @param {*} model
34
+ * @returns
35
+ */ const isLocalizedContentType = (model)=>{
36
+ return hasLocalizedOption(model);
37
+ };
38
+ /**
39
+ * Returns the list of attribute names that are not localized
40
+ * @param {object} model
41
+ * @returns {string[]}
42
+ */ const getNonLocalizedAttributes = (model)=>{
43
+ return getVisibleAttributes(model).filter((attrName)=>!isLocalizedAttribute(model.attributes[attrName]));
44
+ };
45
+ const removeId = (value)=>{
46
+ if (typeof value === 'object' && fp.has('id', value)) {
47
+ delete value.id;
48
+ }
49
+ };
50
+ const removeIds = (model)=>(entry)=>removeIdsMut(model, fp.cloneDeep(entry));
51
+ const removeIdsMut = (model, entry)=>{
52
+ if (fp.isNil(entry)) {
53
+ return entry;
54
+ }
55
+ removeId(entry);
56
+ _.forEach(model.attributes, (attr, attrName)=>{
57
+ const value = entry[attrName];
58
+ if (attr.type === 'dynamiczone' && fp.isArray(value)) {
59
+ value.forEach((compo)=>{
60
+ if (fp.has('__component', compo)) {
61
+ const model = strapi.components[compo.__component];
62
+ removeIdsMut(model, compo);
63
+ }
64
+ });
65
+ } else if (attr.type === 'component') {
66
+ const model = strapi.components[attr.component];
67
+ if (fp.isArray(value)) {
68
+ value.forEach((compo)=>removeIdsMut(model, compo));
69
+ } else {
70
+ removeIdsMut(model, value);
71
+ }
72
+ }
73
+ });
74
+ return entry;
75
+ };
76
+ /**
77
+ * Returns a copy of an entry picking only its non localized attributes
78
+ * @param {object} model
79
+ * @param {object} entry
80
+ * @returns {object}
81
+ */ const copyNonLocalizedAttributes = (model, entry)=>{
82
+ const nonLocalizedAttributes = getNonLocalizedAttributes(model);
83
+ return fp.pipe(fp.pick(nonLocalizedAttributes), removeIds(model))(entry);
84
+ };
85
+ /**
86
+ * Returns the list of attribute names that are localized
87
+ * @param {object} model
88
+ * @returns {string[]}
89
+ */ const getLocalizedAttributes = (model)=>{
90
+ return getVisibleAttributes(model).filter((attrName)=>isLocalizedAttribute(model.attributes[attrName]));
91
+ };
92
+ /**
93
+ * Fill non localized fields of an entry if there are nil
94
+ * @param {Object} entry entry to fill
95
+ * @param {Object} relatedEntry values used to fill
96
+ * @param {Object} options
97
+ * @param {Object} options.model corresponding model
98
+ */ const fillNonLocalizedAttributes = (entry, relatedEntry, { model })=>{
99
+ if (fp.isNil(relatedEntry)) {
100
+ return;
101
+ }
102
+ const modelDef = strapi.getModel(model);
103
+ const relatedEntryCopy = copyNonLocalizedAttributes(modelDef, relatedEntry);
104
+ _.forEach(relatedEntryCopy, (value, field)=>{
105
+ if (fp.isNil(entry[field])) {
106
+ entry[field] = value;
107
+ }
108
+ });
109
+ };
110
+ /**
111
+ * build the populate param to
112
+ * @param {String} modelUID uid of the model, could be of a content-type or a component
113
+ */ const getNestedPopulateOfNonLocalizedAttributes = (modelUID)=>{
114
+ const schema = strapi.getModel(modelUID);
115
+ const scalarAttributes = getScalarAttributes(schema);
116
+ const nonLocalizedAttributes = getNonLocalizedAttributes(schema);
117
+ const allAttributes = [
118
+ ...scalarAttributes,
119
+ ...nonLocalizedAttributes
120
+ ];
121
+ if (schema.modelType === 'component') {
122
+ // When called recursively on a non localized component we
123
+ // need to explicitly populate that components relations
124
+ allAttributes.push(...getRelationalAttributes(schema));
125
+ }
126
+ const currentAttributesToPopulate = allAttributes.filter((value, index, self)=>{
127
+ return self.indexOf(value) === index && self.lastIndexOf(value) === index;
128
+ });
129
+ const attributesToPopulate = [
130
+ ...currentAttributesToPopulate
131
+ ];
132
+ for (const attrName of currentAttributesToPopulate){
133
+ const attr = schema.attributes[attrName];
134
+ if (attr.type === 'component') {
135
+ const nestedPopulate = getNestedPopulateOfNonLocalizedAttributes(attr.component).map((nestedAttr)=>`${attrName}.${nestedAttr}`);
136
+ attributesToPopulate.push(...nestedPopulate);
137
+ } else if (attr.type === 'dynamiczone') {
138
+ attr.components.forEach((componentName)=>{
139
+ const nestedPopulate = getNestedPopulateOfNonLocalizedAttributes(componentName).map((nestedAttr)=>`${attrName}.${nestedAttr}`);
140
+ attributesToPopulate.push(...nestedPopulate);
141
+ });
142
+ }
143
+ }
144
+ return attributesToPopulate;
145
+ };
146
+ const contentTypes = ()=>({
147
+ isLocalizedContentType,
148
+ getValidLocale,
149
+ getLocalizedAttributes,
150
+ getNonLocalizedAttributes,
151
+ copyNonLocalizedAttributes,
152
+ fillNonLocalizedAttributes,
153
+ getNestedPopulateOfNonLocalizedAttributes
154
+ });
155
+
156
+ module.exports = contentTypes;
157
+ //# sourceMappingURL=content-types.js.map