@strapi/i18n 5.28.0 → 5.30.0

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 (157) hide show
  1. package/dist/admin/components/CMHeaderActions.js +193 -4
  2. package/dist/admin/components/CMHeaderActions.js.map +1 -1
  3. package/dist/admin/components/CMHeaderActions.mjs +197 -9
  4. package/dist/admin/components/CMHeaderActions.mjs.map +1 -1
  5. package/dist/admin/components/LocaleListCell.js +65 -45
  6. package/dist/admin/components/LocaleListCell.js.map +1 -1
  7. package/dist/admin/components/LocaleListCell.mjs +66 -46
  8. package/dist/admin/components/LocaleListCell.mjs.map +1 -1
  9. package/dist/admin/components/LocalePicker.js +18 -11
  10. package/dist/admin/components/LocalePicker.js.map +1 -1
  11. package/dist/admin/components/LocalePicker.mjs +19 -12
  12. package/dist/admin/components/LocalePicker.mjs.map +1 -1
  13. package/dist/admin/contentManagerHooks/editView.js +6 -3
  14. package/dist/admin/contentManagerHooks/editView.js.map +1 -1
  15. package/dist/admin/contentManagerHooks/editView.mjs +7 -4
  16. package/dist/admin/contentManagerHooks/editView.mjs.map +1 -1
  17. package/dist/admin/contentManagerHooks/listView.js +2 -1
  18. package/dist/admin/contentManagerHooks/listView.js.map +1 -1
  19. package/dist/admin/contentManagerHooks/listView.mjs +2 -1
  20. package/dist/admin/contentManagerHooks/listView.mjs.map +1 -1
  21. package/dist/admin/hooks/useAILocalizationJobsPolling.js +110 -0
  22. package/dist/admin/hooks/useAILocalizationJobsPolling.js.map +1 -0
  23. package/dist/admin/hooks/useAILocalizationJobsPolling.mjs +89 -0
  24. package/dist/admin/hooks/useAILocalizationJobsPolling.mjs.map +1 -0
  25. package/dist/admin/hooks/useI18n.js +4 -4
  26. package/dist/admin/hooks/useI18n.js.map +1 -1
  27. package/dist/admin/hooks/useI18n.mjs +4 -4
  28. package/dist/admin/hooks/useI18n.mjs.map +1 -1
  29. package/dist/admin/index.js +1 -0
  30. package/dist/admin/index.js.map +1 -1
  31. package/dist/admin/index.mjs +2 -1
  32. package/dist/admin/index.mjs.map +1 -1
  33. package/dist/admin/pages/SettingsPage.js +121 -46
  34. package/dist/admin/pages/SettingsPage.js.map +1 -1
  35. package/dist/admin/pages/SettingsPage.mjs +124 -30
  36. package/dist/admin/pages/SettingsPage.mjs.map +1 -1
  37. package/dist/admin/services/aiLocalizationJobs.js +26 -0
  38. package/dist/admin/services/aiLocalizationJobs.js.map +1 -0
  39. package/dist/admin/services/aiLocalizationJobs.mjs +24 -0
  40. package/dist/admin/services/aiLocalizationJobs.mjs.map +1 -0
  41. package/dist/admin/services/api.js +3 -1
  42. package/dist/admin/services/api.js.map +1 -1
  43. package/dist/admin/services/api.mjs +3 -1
  44. package/dist/admin/services/api.mjs.map +1 -1
  45. package/dist/admin/services/settings.js +29 -0
  46. package/dist/admin/services/settings.js.map +1 -0
  47. package/dist/admin/services/settings.mjs +26 -0
  48. package/dist/admin/services/settings.mjs.map +1 -0
  49. package/dist/admin/src/components/CMHeaderActions.d.ts +17 -4
  50. package/dist/admin/src/components/LocaleListCell.d.ts +2 -1
  51. package/dist/admin/src/hooks/useAILocalizationJobsPolling.d.ts +9 -0
  52. package/dist/admin/src/services/aiLocalizationJobs.d.ts +6 -0
  53. package/dist/admin/src/services/api.d.ts +1 -1
  54. package/dist/admin/src/services/locales.d.ts +1 -1
  55. package/dist/admin/src/services/relations.d.ts +1 -1
  56. package/dist/admin/src/services/settings.d.ts +5 -0
  57. package/dist/admin/translations/en.json.js +10 -0
  58. package/dist/admin/translations/en.json.js.map +1 -1
  59. package/dist/admin/translations/en.json.mjs +10 -0
  60. package/dist/admin/translations/en.json.mjs.map +1 -1
  61. package/dist/admin/utils/clean.js +2 -2
  62. package/dist/admin/utils/clean.js.map +1 -1
  63. package/dist/admin/utils/clean.mjs +2 -2
  64. package/dist/admin/utils/clean.mjs.map +1 -1
  65. package/dist/server/bootstrap.js +2 -0
  66. package/dist/server/bootstrap.js.map +1 -1
  67. package/dist/server/bootstrap.mjs +2 -0
  68. package/dist/server/bootstrap.mjs.map +1 -1
  69. package/dist/server/constants/iso-locales.json.js +4 -0
  70. package/dist/server/constants/iso-locales.json.js.map +1 -1
  71. package/dist/server/constants/iso-locales.json.mjs +4 -0
  72. package/dist/server/constants/iso-locales.json.mjs.map +1 -1
  73. package/dist/server/controllers/ai-localization-jobs.js +47 -0
  74. package/dist/server/controllers/ai-localization-jobs.js.map +1 -0
  75. package/dist/server/controllers/ai-localization-jobs.mjs +45 -0
  76. package/dist/server/controllers/ai-localization-jobs.mjs.map +1 -0
  77. package/dist/server/controllers/index.js +5 -1
  78. package/dist/server/controllers/index.js.map +1 -1
  79. package/dist/server/controllers/index.mjs +5 -1
  80. package/dist/server/controllers/index.mjs.map +1 -1
  81. package/dist/server/controllers/settings.js +24 -0
  82. package/dist/server/controllers/settings.js.map +1 -0
  83. package/dist/server/controllers/settings.mjs +22 -0
  84. package/dist/server/controllers/settings.mjs.map +1 -0
  85. package/dist/server/models/ai-localization-job.js +60 -0
  86. package/dist/server/models/ai-localization-job.js.map +1 -0
  87. package/dist/server/models/ai-localization-job.mjs +57 -0
  88. package/dist/server/models/ai-localization-job.mjs.map +1 -0
  89. package/dist/server/register.js +3 -1
  90. package/dist/server/register.js.map +1 -1
  91. package/dist/server/register.mjs +3 -1
  92. package/dist/server/register.mjs.map +1 -1
  93. package/dist/server/routes/admin.js +40 -0
  94. package/dist/server/routes/admin.js.map +1 -1
  95. package/dist/server/routes/admin.mjs +40 -0
  96. package/dist/server/routes/admin.mjs.map +1 -1
  97. package/dist/server/services/ai-localization-jobs.js +64 -0
  98. package/dist/server/services/ai-localization-jobs.js.map +1 -0
  99. package/dist/server/services/ai-localization-jobs.mjs +62 -0
  100. package/dist/server/services/ai-localization-jobs.mjs.map +1 -0
  101. package/dist/server/services/ai-localizations.js +253 -5
  102. package/dist/server/services/ai-localizations.js.map +1 -1
  103. package/dist/server/services/ai-localizations.mjs +253 -5
  104. package/dist/server/services/ai-localizations.mjs.map +1 -1
  105. package/dist/server/services/index.js +5 -1
  106. package/dist/server/services/index.js.map +1 -1
  107. package/dist/server/services/index.mjs +5 -1
  108. package/dist/server/services/index.mjs.map +1 -1
  109. package/dist/server/services/metrics.js +12 -1
  110. package/dist/server/services/metrics.js.map +1 -1
  111. package/dist/server/services/metrics.mjs +12 -1
  112. package/dist/server/services/metrics.mjs.map +1 -1
  113. package/dist/server/services/settings.js +25 -0
  114. package/dist/server/services/settings.js.map +1 -0
  115. package/dist/server/services/settings.mjs +23 -0
  116. package/dist/server/services/settings.mjs.map +1 -0
  117. package/dist/server/src/bootstrap.d.ts.map +1 -1
  118. package/dist/server/src/controllers/ai-localization-jobs.d.ts +17 -0
  119. package/dist/server/src/controllers/ai-localization-jobs.d.ts.map +1 -0
  120. package/dist/server/src/controllers/index.d.ts +10 -0
  121. package/dist/server/src/controllers/index.d.ts.map +1 -1
  122. package/dist/server/src/controllers/settings.d.ts +7 -0
  123. package/dist/server/src/controllers/settings.d.ts.map +1 -0
  124. package/dist/server/src/index.d.ts +41 -2
  125. package/dist/server/src/index.d.ts.map +1 -1
  126. package/dist/server/src/models/ai-localization-job.d.ts +5 -0
  127. package/dist/server/src/models/ai-localization-job.d.ts.map +1 -0
  128. package/dist/server/src/models/index.d.ts +5 -0
  129. package/dist/server/src/models/index.d.ts.map +1 -0
  130. package/dist/server/src/register.d.ts +1 -1
  131. package/dist/server/src/register.d.ts.map +1 -1
  132. package/dist/server/src/routes/admin.d.ts.map +1 -1
  133. package/dist/server/src/services/ai-localization-jobs.d.ts +26 -0
  134. package/dist/server/src/services/ai-localization-jobs.d.ts.map +1 -0
  135. package/dist/server/src/services/ai-localizations.d.ts +11 -1
  136. package/dist/server/src/services/ai-localizations.d.ts.map +1 -1
  137. package/dist/server/src/services/index.d.ts +30 -1
  138. package/dist/server/src/services/index.d.ts.map +1 -1
  139. package/dist/server/src/services/metrics.d.ts +1 -0
  140. package/dist/server/src/services/metrics.d.ts.map +1 -1
  141. package/dist/server/src/services/settings.d.ts +13 -0
  142. package/dist/server/src/services/settings.d.ts.map +1 -0
  143. package/dist/server/src/utils/index.d.ts +7 -1
  144. package/dist/server/src/utils/index.d.ts.map +1 -1
  145. package/dist/server/src/validation/settings.d.ts +12 -0
  146. package/dist/server/src/validation/settings.d.ts.map +1 -0
  147. package/dist/server/utils/index.js.map +1 -1
  148. package/dist/server/utils/index.mjs.map +1 -1
  149. package/dist/server/validation/settings.js +11 -0
  150. package/dist/server/validation/settings.js.map +1 -0
  151. package/dist/server/validation/settings.mjs +9 -0
  152. package/dist/server/validation/settings.mjs.map +1 -0
  153. package/dist/shared/contracts/ai-localization-jobs.d.ts +27 -0
  154. package/dist/shared/contracts/ai-localization-jobs.d.ts.map +1 -0
  155. package/dist/shared/contracts/settings.d.ts +40 -0
  156. package/dist/shared/contracts/shared.d.ts.map +1 -0
  157. package/package.json +8 -6
@@ -1,12 +1,29 @@
1
+ import { traverseEntity } from '@strapi/utils';
2
+ import { getService } from '../utils/index.mjs';
3
+
4
+ const isLocalizedAttribute = (attribute)=>{
5
+ return attribute?.pluginOptions?.i18n?.localized === true;
6
+ };
1
7
  const createAILocalizationsService = ({ strapi })=>{
8
+ // TODO: add a helper function to get the AI server URL
9
+ const aiServerUrl = process.env.STRAPI_AI_URL || 'https://strapi-ai.apps.strapi.io';
10
+ const aiLocalizationJobsService = getService('ai-localization-jobs');
11
+ const UNSUPPORTED_ATTRIBUTE_TYPES = [
12
+ 'media',
13
+ 'relation',
14
+ 'boolean'
15
+ ];
16
+ const IGNORED_FIELDS = [
17
+ 'id',
18
+ 'documentId',
19
+ 'createdAt',
20
+ 'updatedAt',
21
+ 'updatedBy',
22
+ 'localizations'
23
+ ];
2
24
  return {
3
25
  // Async to avoid changing the signature later (there will be a db check in the future)
4
26
  async isEnabled () {
5
- // Check if future flag is enabled
6
- const isFutureFlagEnabled = strapi.features.future.isEnabled('unstableAILocalizations');
7
- if (!isFutureFlagEnabled) {
8
- return false;
9
- }
10
27
  // Check if user disabled AI features globally
11
28
  const isAIEnabled = strapi.config.get('admin.ai.enabled', true);
12
29
  if (!isAIEnabled) {
@@ -17,7 +34,238 @@ const createAILocalizationsService = ({ strapi })=>{
17
34
  if (!hasAccess) {
18
35
  return false;
19
36
  }
37
+ const settings = getService('settings');
38
+ const aiSettings = await settings.getSettings();
39
+ if (!aiSettings?.aiLocalizations) {
40
+ return false;
41
+ }
20
42
  return true;
43
+ },
44
+ /**
45
+ * Checks if there are localizations that need to be generated for the given document,
46
+ * and if so, calls the AI service and saves the results to the database.
47
+ * Works for both single and collection types, on create and update.
48
+ */ async generateDocumentLocalizations ({ model, document }) {
49
+ const isFeatureEnabled = await this.isEnabled();
50
+ if (!isFeatureEnabled) {
51
+ return;
52
+ }
53
+ const schema = strapi.getModel(model);
54
+ const localeService = getService('locales');
55
+ // No localizations needed for content types with i18n disabled
56
+ const isLocalizedContentType = getService('content-types').isLocalizedContentType(schema);
57
+ if (!isLocalizedContentType) {
58
+ return;
59
+ }
60
+ // Don't trigger localizations if the update is on a derived locale, only do it on the default
61
+ const defaultLocale = await localeService.getDefaultLocale();
62
+ if (document?.locale !== defaultLocale) {
63
+ return;
64
+ }
65
+ const documentId = document.documentId;
66
+ if (!documentId) {
67
+ strapi.log.warn(`AI Localizations: missing documentId for ${schema.uid}`);
68
+ return;
69
+ }
70
+ const localizedRoots = new Set();
71
+ const translateableContent = await traverseEntity(({ key, attribute, parent, path }, { remove })=>{
72
+ if (IGNORED_FIELDS.includes(key)) {
73
+ remove(key);
74
+ return;
75
+ }
76
+ const hasLocalizedOption = attribute && isLocalizedAttribute(attribute);
77
+ if (attribute && UNSUPPORTED_ATTRIBUTE_TYPES.includes(attribute.type)) {
78
+ remove(key);
79
+ return;
80
+ }
81
+ // If this field is localized, keep it (and mark as localized root if component/dz)
82
+ if (hasLocalizedOption) {
83
+ // If it's a component/dynamiczone, add to the set
84
+ if ([
85
+ 'component',
86
+ 'dynamiczone'
87
+ ].includes(attribute.type)) {
88
+ localizedRoots.add(path.raw);
89
+ }
90
+ return; // keep
91
+ }
92
+ if (parent && localizedRoots.has(parent.path.raw)) {
93
+ // If parent exists in the localized roots set, keep it
94
+ // If this is also a component/dz, propagate the localized root flag
95
+ if ([
96
+ 'component',
97
+ 'dynamiczone'
98
+ ].includes(attribute?.type ?? '')) {
99
+ localizedRoots.add(path.raw);
100
+ }
101
+ return; // keep
102
+ }
103
+ // Otherwise, remove the field
104
+ remove(key);
105
+ }, {
106
+ schema,
107
+ getModel: strapi.getModel.bind(strapi)
108
+ }, document);
109
+ if (Object.keys(translateableContent).length === 0) {
110
+ strapi.log.info(`AI Localizations: no translatable content for ${schema.uid} document ${documentId}`);
111
+ return;
112
+ }
113
+ const localesList = await localeService.find();
114
+ const targetLocales = localesList.filter((l)=>l.code !== document.locale).map((l)=>l.code);
115
+ if (targetLocales.length === 0) {
116
+ strapi.log.info(`AI Localizations: no target locales for ${schema.uid} document ${documentId}`);
117
+ return;
118
+ }
119
+ await aiLocalizationJobsService.upsertJobForDocument({
120
+ contentType: model,
121
+ documentId,
122
+ sourceLocale: document.locale,
123
+ targetLocales,
124
+ status: 'processing'
125
+ });
126
+ let token;
127
+ try {
128
+ const tokenData = await strapi.service('admin::user').getAiToken();
129
+ token = tokenData.token;
130
+ } catch (error) {
131
+ await aiLocalizationJobsService.upsertJobForDocument({
132
+ documentId,
133
+ contentType: model,
134
+ sourceLocale: document.locale,
135
+ targetLocales,
136
+ status: 'failed'
137
+ });
138
+ throw new Error('Failed to retrieve AI token', {
139
+ cause: error instanceof Error ? error : undefined
140
+ });
141
+ }
142
+ /**
143
+ * Provide a schema to the LLM so that we can give it instructions about how to handle each
144
+ * type of attribute. Only keep essential schema data to avoid cluttering the context.
145
+ * Ignore fields that don't need to be localized.
146
+ * TODO: also provide a schema of all the referenced components
147
+ */ const minimalContentTypeSchema = Object.fromEntries(Object.entries(schema.attributes)// eslint-disable-next-line @typescript-eslint/no-unused-vars
148
+ .filter(([_, attr])=>{
149
+ const isLocalized = isLocalizedAttribute(attr);
150
+ const isSupportedType = !UNSUPPORTED_ATTRIBUTE_TYPES.includes(attr.type);
151
+ return isLocalized && isSupportedType;
152
+ }).map(([key, attr])=>{
153
+ const minimalAttribute = {
154
+ type: attr.type
155
+ };
156
+ if (attr.type === 'component') {
157
+ minimalAttribute.repeatable = attr.repeatable ?? false;
158
+ }
159
+ return [
160
+ key,
161
+ minimalAttribute
162
+ ];
163
+ }));
164
+ strapi.log.http('Contacting AI Server for localizations generation');
165
+ const response = await fetch(`${aiServerUrl}/i18n/generate-localizations`, {
166
+ method: 'POST',
167
+ headers: {
168
+ 'Content-Type': 'application/json',
169
+ Authorization: `Bearer ${token}`
170
+ },
171
+ body: JSON.stringify({
172
+ content: translateableContent,
173
+ sourceLocale: document.locale,
174
+ targetLocales,
175
+ contentTypeSchema: minimalContentTypeSchema
176
+ })
177
+ });
178
+ if (!response.ok) {
179
+ strapi.log.error(`AI Localizations request failed: ${response.status} ${response.statusText}`);
180
+ await aiLocalizationJobsService.upsertJobForDocument({
181
+ documentId,
182
+ contentType: model,
183
+ sourceLocale: document.locale,
184
+ targetLocales,
185
+ status: 'failed'
186
+ });
187
+ throw new Error(`AI Localizations request failed: ${response.statusText}`);
188
+ }
189
+ const aiResult = await response.json();
190
+ // Get all media field names dynamically from the schema
191
+ const mediaFields = Object.entries(schema.attributes)// eslint-disable-next-line @typescript-eslint/no-unused-vars
192
+ .filter(([_, attr])=>attr.type === 'media').map(([key])=>key);
193
+ try {
194
+ await Promise.all(aiResult.localizations.map(async (localization)=>{
195
+ const { content, locale } = localization;
196
+ // Fetch the derived locale document
197
+ const derivedDoc = await strapi.documents(model).findOne({
198
+ documentId,
199
+ locale,
200
+ populate: mediaFields
201
+ });
202
+ // Merge AI content and media fields, works only on first level media fields (root level)
203
+ const mergedData = structuredClone(content);
204
+ for (const field of mediaFields){
205
+ // Only copy media if not already set in derived locale
206
+ if (!derivedDoc || !derivedDoc[field]) {
207
+ mergedData[field] = document[field];
208
+ } else {
209
+ mergedData[field] = derivedDoc[field];
210
+ }
211
+ }
212
+ await strapi.documents(model).update({
213
+ documentId,
214
+ locale,
215
+ fields: [],
216
+ data: mergedData
217
+ });
218
+ await aiLocalizationJobsService.upsertJobForDocument({
219
+ documentId,
220
+ contentType: model,
221
+ sourceLocale: document.locale,
222
+ targetLocales,
223
+ status: 'completed'
224
+ });
225
+ }));
226
+ } catch (error) {
227
+ await aiLocalizationJobsService.upsertJobForDocument({
228
+ documentId,
229
+ contentType: model,
230
+ sourceLocale: document.locale,
231
+ targetLocales,
232
+ status: 'failed'
233
+ });
234
+ strapi.log.error('AI Localizations generation failed', error);
235
+ }
236
+ },
237
+ setupMiddleware () {
238
+ strapi.documents.use(async (context, next)=>{
239
+ const result = await next();
240
+ const metricsService = strapi.plugin('i18n').service('metrics');
241
+ if (context.action === 'publish') {
242
+ metricsService.sendWithAIEventProperty('didPublishEntry');
243
+ return result;
244
+ }
245
+ if (context.action === 'update' || context.action === 'create') {
246
+ metricsService.sendWithAIEventProperty('didSaveEntry');
247
+ }
248
+ // Only trigger for the allowed actions
249
+ if (![
250
+ 'create',
251
+ 'update'
252
+ ].includes(context.action)) {
253
+ return result;
254
+ }
255
+ // Check if AI localizations are enabled before triggering
256
+ const isEnabled = await this.isEnabled();
257
+ if (!isEnabled) {
258
+ return result;
259
+ }
260
+ // Don't await since localizations should be done in the background without blocking the request
261
+ strapi.plugin('i18n').service('ai-localizations').generateDocumentLocalizations({
262
+ model: context.contentType.uid,
263
+ document: result
264
+ }).catch((error)=>{
265
+ strapi.log.error('AI Localizations generation failed', error);
266
+ });
267
+ return result;
268
+ });
21
269
  }
22
270
  };
23
271
  };
@@ -1 +1 @@
1
- {"version":3,"file":"ai-localizations.mjs","sources":["../../../server/src/services/ai-localizations.ts"],"sourcesContent":["import type { Core } from '@strapi/types';\n\nconst createAILocalizationsService = ({ strapi }: { strapi: Core.Strapi }) => {\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 return true;\n },\n };\n};\n\nexport { createAILocalizationsService };\n"],"names":["createAILocalizationsService","strapi","isEnabled","isFutureFlagEnabled","features","future","isAIEnabled","config","get","hasAccess","ee"],"mappings":"AAEA,MAAMA,4BAA+B,GAAA,CAAC,EAAEC,MAAM,EAA2B,GAAA;IACvE,OAAO;;QAEL,MAAMC,SAAAA,CAAAA,GAAAA;;AAEJ,YAAA,MAAMC,sBAAsBF,MAAOG,CAAAA,QAAQ,CAACC,MAAM,CAACH,SAAS,CAAC,yBAAA,CAAA;AAC7D,YAAA,IAAI,CAACC,mBAAqB,EAAA;gBACxB,OAAO,KAAA;AACT;;AAGA,YAAA,MAAMG,cAAcL,MAAOM,CAAAA,MAAM,CAACC,GAAG,CAAC,kBAAoB,EAAA,IAAA,CAAA;AAC1D,YAAA,IAAI,CAACF,WAAa,EAAA;gBAChB,OAAO,KAAA;AACT;;AAGA,YAAA,MAAMG,YAAYR,MAAOS,CAAAA,EAAE,CAACN,QAAQ,CAACF,SAAS,CAAC,QAAA,CAAA;AAC/C,YAAA,IAAI,CAACO,SAAW,EAAA;gBACd,OAAO,KAAA;AACT;YAEA,OAAO,IAAA;AACT;AACF,KAAA;AACF;;;;"}
1
+ {"version":3,"file":"ai-localizations.mjs","sources":["../../../server/src/services/ai-localizations.ts"],"sourcesContent":["import type { Core, Modules, Schema, UID } from '@strapi/types';\nimport { traverseEntity } from '@strapi/utils';\nimport { getService } from '../utils';\n\nconst isLocalizedAttribute = (attribute: Schema.Attribute.Attribute | undefined): boolean => {\n return (attribute?.pluginOptions as any)?.i18n?.localized === true;\n};\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 const UNSUPPORTED_ATTRIBUTE_TYPES: Schema.Attribute.Kind[] = ['media', 'relation', 'boolean'];\n const IGNORED_FIELDS = [\n 'id',\n 'documentId',\n 'createdAt',\n 'updatedAt',\n 'updatedBy',\n 'localizations',\n ];\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 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 const localizedRoots = new Set();\n\n const translateableContent = await traverseEntity(\n ({ key, attribute, parent, path }, { remove }) => {\n if (IGNORED_FIELDS.includes(key)) {\n remove(key);\n return;\n }\n const hasLocalizedOption = attribute && isLocalizedAttribute(attribute);\n if (attribute && UNSUPPORTED_ATTRIBUTE_TYPES.includes(attribute.type)) {\n remove(key);\n return;\n }\n\n // If this field is localized, keep it (and mark as localized root if component/dz)\n if (hasLocalizedOption) {\n // If it's a component/dynamiczone, add to the set\n if (['component', 'dynamiczone'].includes(attribute.type)) {\n localizedRoots.add(path.raw);\n }\n return; // keep\n }\n\n if (parent && localizedRoots.has(parent.path.raw)) {\n // If parent exists in the localized roots set, keep it\n // If this is also a component/dz, propagate the localized root flag\n if (['component', 'dynamiczone'].includes(attribute?.type ?? '')) {\n localizedRoots.add(path.raw);\n }\n return; // keep\n }\n\n // Otherwise, remove the field\n remove(key);\n },\n { schema, getModel: strapi.getModel.bind(strapi) },\n document\n );\n\n if (Object.keys(translateableContent).length === 0) {\n strapi.log.info(\n `AI Localizations: no translatable content for ${schema.uid} document ${documentId}`\n );\n return;\n }\n\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 /**\n * Provide a schema to the LLM so that we can give it instructions about how to handle each\n * type of attribute. Only keep essential schema data to avoid cluttering the context.\n * Ignore fields that don't need to be localized.\n * TODO: also provide a schema of all the referenced components\n */\n const minimalContentTypeSchema = Object.fromEntries(\n Object.entries(schema.attributes)\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n .filter(([_, attr]) => {\n const isLocalized = isLocalizedAttribute(attr);\n const isSupportedType = !UNSUPPORTED_ATTRIBUTE_TYPES.includes(attr.type);\n return isLocalized && isSupportedType;\n })\n .map(([key, attr]) => {\n const minimalAttribute = { type: attr.type };\n if (attr.type === 'component') {\n (\n minimalAttribute as Schema.Attribute.Component<`${string}.${string}`, boolean>\n ).repeatable = attr.repeatable ?? false;\n }\n return [key, minimalAttribute];\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 contentTypeSchema: minimalContentTypeSchema,\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 }\n\n const aiResult = await response.json();\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.all(\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, works only on first level media fields (root level)\n const mergedData = structuredClone(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 await strapi.documents(model).update({\n documentId,\n locale,\n fields: [],\n data: mergedData,\n });\n\n await aiLocalizationJobsService.upsertJobForDocument({\n documentId,\n contentType: model,\n sourceLocale: document.locale,\n targetLocales,\n status: 'completed',\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 const metricsService = strapi.plugin('i18n').service('metrics');\n if (context.action === 'publish') {\n metricsService.sendWithAIEventProperty('didPublishEntry');\n return result;\n }\n\n if (context.action === 'update' || context.action === 'create') {\n metricsService.sendWithAIEventProperty('didSaveEntry');\n }\n\n // Only trigger for the allowed 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":["isLocalizedAttribute","attribute","pluginOptions","i18n","localized","createAILocalizationsService","strapi","aiServerUrl","process","env","STRAPI_AI_URL","aiLocalizationJobsService","getService","UNSUPPORTED_ATTRIBUTE_TYPES","IGNORED_FIELDS","isEnabled","isAIEnabled","config","get","hasAccess","ee","features","settings","aiSettings","getSettings","aiLocalizations","generateDocumentLocalizations","model","document","isFeatureEnabled","schema","getModel","localeService","isLocalizedContentType","defaultLocale","getDefaultLocale","locale","documentId","log","warn","uid","localizedRoots","Set","translateableContent","traverseEntity","key","parent","path","remove","includes","hasLocalizedOption","type","add","raw","has","bind","Object","keys","length","info","localesList","find","targetLocales","filter","l","code","map","upsertJobForDocument","contentType","sourceLocale","status","token","tokenData","service","getAiToken","error","Error","cause","undefined","minimalContentTypeSchema","fromEntries","entries","attributes","_","attr","isLocalized","isSupportedType","minimalAttribute","repeatable","http","response","fetch","method","headers","Authorization","body","JSON","stringify","content","contentTypeSchema","ok","statusText","aiResult","json","mediaFields","Promise","all","localizations","localization","derivedDoc","documents","findOne","populate","mergedData","structuredClone","field","update","fields","data","setupMiddleware","use","context","next","result","metricsService","plugin","action","sendWithAIEventProperty","catch"],"mappings":"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"}
@@ -7,7 +7,9 @@ var locales = require('./locales.js');
7
7
  var isoLocales = require('./iso-locales.js');
8
8
  var contentTypes = require('./content-types.js');
9
9
  var index = require('./sanitize/index.js');
10
+ var settings = require('./settings.js');
10
11
  var aiLocalizations = require('./ai-localizations.js');
12
+ var aiLocalizationJobs = require('./ai-localization-jobs.js');
11
13
 
12
14
  var services = {
13
15
  permissions,
@@ -17,7 +19,9 @@ var services = {
17
19
  sanitize: index,
18
20
  'iso-locales': isoLocales,
19
21
  'content-types': contentTypes,
20
- aiLocalizations: aiLocalizations.createAILocalizationsService
22
+ 'ai-localizations': aiLocalizations.createAILocalizationsService,
23
+ 'ai-localization-jobs': aiLocalizationJobs.createAILocalizationJobsService,
24
+ settings: settings.createSettingsService
21
25
  };
22
26
 
23
27
  module.exports = services;
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../../../server/src/services/index.ts"],"sourcesContent":["import permissions from './permissions';\nimport metrics from './metrics';\nimport localizations from './localizations';\nimport locales from './locales';\nimport isoLocales from './iso-locales';\nimport contentTypes from './content-types';\nimport sanitize from './sanitize';\nimport { createAILocalizationsService } from './ai-localizations';\n\nexport default {\n permissions,\n metrics,\n localizations,\n locales,\n sanitize,\n 'iso-locales': isoLocales,\n 'content-types': contentTypes,\n aiLocalizations: createAILocalizationsService,\n};\n"],"names":["permissions","metrics","localizations","locales","sanitize","isoLocales","contentTypes","aiLocalizations","createAILocalizationsService"],"mappings":";;;;;;;;;;;AASA,eAAe;AACbA,IAAAA,WAAAA;AACAC,IAAAA,OAAAA;AACAC,IAAAA,aAAAA;AACAC,IAAAA,OAAAA;AACAC,cAAAA,KAAAA;IACA,aAAeC,EAAAA,UAAAA;IACf,eAAiBC,EAAAA,YAAAA;IACjBC,eAAiBC,EAAAA;AACnB,CAAE;;;;"}
1
+ {"version":3,"file":"index.js","sources":["../../../server/src/services/index.ts"],"sourcesContent":["import permissions from './permissions';\nimport metrics from './metrics';\nimport localizations from './localizations';\nimport locales from './locales';\nimport isoLocales from './iso-locales';\nimport contentTypes from './content-types';\nimport sanitize from './sanitize';\nimport { createSettingsService } from './settings';\nimport { createAILocalizationsService } from './ai-localizations';\nimport { createAILocalizationJobsService } from './ai-localization-jobs';\n\nexport default {\n permissions,\n metrics,\n localizations,\n locales,\n sanitize,\n 'iso-locales': isoLocales,\n 'content-types': contentTypes,\n 'ai-localizations': createAILocalizationsService,\n 'ai-localization-jobs': createAILocalizationJobsService,\n settings: createSettingsService,\n};\n"],"names":["permissions","metrics","localizations","locales","sanitize","isoLocales","contentTypes","createAILocalizationsService","createAILocalizationJobsService","settings","createSettingsService"],"mappings":";;;;;;;;;;;;;AAWA,eAAe;AACbA,IAAAA,WAAAA;AACAC,IAAAA,OAAAA;AACAC,IAAAA,aAAAA;AACAC,IAAAA,OAAAA;AACAC,cAAAA,KAAAA;IACA,aAAeC,EAAAA,UAAAA;IACf,eAAiBC,EAAAA,YAAAA;IACjB,kBAAoBC,EAAAA,4CAAAA;IACpB,sBAAwBC,EAAAA,kDAAAA;IACxBC,QAAUC,EAAAA;AACZ,CAAE;;;;"}
@@ -5,7 +5,9 @@ import locales from './locales.mjs';
5
5
  import isoLocalesService from './iso-locales.mjs';
6
6
  import contentTypes from './content-types.mjs';
7
7
  import sanitize from './sanitize/index.mjs';
8
+ import { createSettingsService } from './settings.mjs';
8
9
  import { createAILocalizationsService } from './ai-localizations.mjs';
10
+ import { createAILocalizationJobsService } from './ai-localization-jobs.mjs';
9
11
 
10
12
  var services = {
11
13
  permissions,
@@ -15,7 +17,9 @@ var services = {
15
17
  sanitize,
16
18
  'iso-locales': isoLocalesService,
17
19
  'content-types': contentTypes,
18
- aiLocalizations: createAILocalizationsService
20
+ 'ai-localizations': createAILocalizationsService,
21
+ 'ai-localization-jobs': createAILocalizationJobsService,
22
+ settings: createSettingsService
19
23
  };
20
24
 
21
25
  export { services as default };
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","sources":["../../../server/src/services/index.ts"],"sourcesContent":["import permissions from './permissions';\nimport metrics from './metrics';\nimport localizations from './localizations';\nimport locales from './locales';\nimport isoLocales from './iso-locales';\nimport contentTypes from './content-types';\nimport sanitize from './sanitize';\nimport { createAILocalizationsService } from './ai-localizations';\n\nexport default {\n permissions,\n metrics,\n localizations,\n locales,\n sanitize,\n 'iso-locales': isoLocales,\n 'content-types': contentTypes,\n aiLocalizations: createAILocalizationsService,\n};\n"],"names":["permissions","metrics","localizations","locales","sanitize","isoLocales","contentTypes","aiLocalizations","createAILocalizationsService"],"mappings":";;;;;;;;;AASA,eAAe;AACbA,IAAAA,WAAAA;AACAC,IAAAA,OAAAA;AACAC,IAAAA,aAAAA;AACAC,IAAAA,OAAAA;AACAC,IAAAA,QAAAA;IACA,aAAeC,EAAAA,iBAAAA;IACf,eAAiBC,EAAAA,YAAAA;IACjBC,eAAiBC,EAAAA;AACnB,CAAE;;;;"}
1
+ {"version":3,"file":"index.mjs","sources":["../../../server/src/services/index.ts"],"sourcesContent":["import permissions from './permissions';\nimport metrics from './metrics';\nimport localizations from './localizations';\nimport locales from './locales';\nimport isoLocales from './iso-locales';\nimport contentTypes from './content-types';\nimport sanitize from './sanitize';\nimport { createSettingsService } from './settings';\nimport { createAILocalizationsService } from './ai-localizations';\nimport { createAILocalizationJobsService } from './ai-localization-jobs';\n\nexport default {\n permissions,\n metrics,\n localizations,\n locales,\n sanitize,\n 'iso-locales': isoLocales,\n 'content-types': contentTypes,\n 'ai-localizations': createAILocalizationsService,\n 'ai-localization-jobs': createAILocalizationJobsService,\n settings: createSettingsService,\n};\n"],"names":["permissions","metrics","localizations","locales","sanitize","isoLocales","contentTypes","createAILocalizationsService","createAILocalizationJobsService","settings","createSettingsService"],"mappings":";;;;;;;;;;;AAWA,eAAe;AACbA,IAAAA,WAAAA;AACAC,IAAAA,OAAAA;AACAC,IAAAA,aAAAA;AACAC,IAAAA,OAAAA;AACAC,IAAAA,QAAAA;IACA,aAAeC,EAAAA,iBAAAA;IACf,eAAiBC,EAAAA,YAAAA;IACjB,kBAAoBC,EAAAA,4BAAAA;IACpB,sBAAwBC,EAAAA,+BAAAA;IACxBC,QAAUC,EAAAA;AACZ,CAAE;;;;"}
@@ -21,9 +21,20 @@ const sendDidUpdateI18nLocalesEvent = async ()=>{
21
21
  }
22
22
  });
23
23
  };
24
+ const sendWithAIEventProperty = async (event, payload = {})=>{
25
+ const settings = await index.getService('settings').getSettings();
26
+ strapi.telemetry.send(event, {
27
+ ...payload,
28
+ eventProperties: {
29
+ ...payload?.eventProperties,
30
+ isAIi18nConfigured: Boolean(settings?.aiLocalizations)
31
+ }
32
+ });
33
+ };
24
34
  const metrics = ()=>({
25
35
  sendDidInitializeEvent,
26
- sendDidUpdateI18nLocalesEvent
36
+ sendDidUpdateI18nLocalesEvent,
37
+ sendWithAIEventProperty
27
38
  });
28
39
 
29
40
  module.exports = metrics;
@@ -1 +1 @@
1
- {"version":3,"file":"metrics.js","sources":["../../../server/src/services/metrics.ts"],"sourcesContent":["import { reduce } from 'lodash/fp';\nimport { getService } from '../utils';\n\nconst sendDidInitializeEvent = async () => {\n const { isLocalizedContentType } = getService('content-types');\n\n // TODO: V5: This event should be renamed numberOfContentTypes in V5 as the name is already taken to describe the number of content types using i18n.\n const numberOfContentTypes = reduce(\n (sum, contentType) => (isLocalizedContentType(contentType) ? sum + 1 : sum),\n 0\n )(strapi.contentTypes as any);\n\n await strapi.telemetry.send('didInitializeI18n', { groupProperties: { numberOfContentTypes } });\n};\n\nconst sendDidUpdateI18nLocalesEvent = async () => {\n const numberOfLocales = await getService('locales').count();\n\n await strapi.telemetry.send('didUpdateI18nLocales', {\n groupProperties: { numberOfLocales },\n });\n};\n\nconst metrics = () => ({\n sendDidInitializeEvent,\n sendDidUpdateI18nLocalesEvent,\n});\n\ntype MetricsService = typeof metrics;\n\nexport default metrics;\nexport type { MetricsService };\n"],"names":["sendDidInitializeEvent","isLocalizedContentType","getService","numberOfContentTypes","reduce","sum","contentType","strapi","contentTypes","telemetry","send","groupProperties","sendDidUpdateI18nLocalesEvent","numberOfLocales","count","metrics"],"mappings":";;;;;AAGA,MAAMA,sBAAyB,GAAA,UAAA;AAC7B,IAAA,MAAM,EAAEC,sBAAsB,EAAE,GAAGC,gBAAW,CAAA,eAAA,CAAA;;AAG9C,IAAA,MAAMC,oBAAuBC,GAAAA,SAAAA,CAC3B,CAACC,GAAAA,EAAKC,WAAiBL,GAAAA,sBAAAA,CAAuBK,WAAeD,CAAAA,GAAAA,GAAAA,GAAM,CAAIA,GAAAA,GAAAA,EACvE,CACAE,CAAAA,CAAAA,MAAAA,CAAOC,YAAY,CAAA;AAErB,IAAA,MAAMD,MAAOE,CAAAA,SAAS,CAACC,IAAI,CAAC,mBAAqB,EAAA;QAAEC,eAAiB,EAAA;AAAER,YAAAA;AAAqB;AAAE,KAAA,CAAA;AAC/F,CAAA;AAEA,MAAMS,6BAAgC,GAAA,UAAA;AACpC,IAAA,MAAMC,eAAkB,GAAA,MAAMX,gBAAW,CAAA,SAAA,CAAA,CAAWY,KAAK,EAAA;AAEzD,IAAA,MAAMP,MAAOE,CAAAA,SAAS,CAACC,IAAI,CAAC,sBAAwB,EAAA;QAClDC,eAAiB,EAAA;AAAEE,YAAAA;AAAgB;AACrC,KAAA,CAAA;AACF,CAAA;AAEME,MAAAA,OAAAA,GAAU,KAAO;AACrBf,QAAAA,sBAAAA;AACAY,QAAAA;KACF;;;;"}
1
+ {"version":3,"file":"metrics.js","sources":["../../../server/src/services/metrics.ts"],"sourcesContent":["import { reduce } from 'lodash/fp';\nimport { getService } from '../utils';\n\nconst sendDidInitializeEvent = async () => {\n const { isLocalizedContentType } = getService('content-types');\n\n // TODO: V5: This event should be renamed numberOfContentTypes in V5 as the name is already taken to describe the number of content types using i18n.\n const numberOfContentTypes = reduce(\n (sum, contentType) => (isLocalizedContentType(contentType) ? sum + 1 : sum),\n 0\n )(strapi.contentTypes as any);\n\n await strapi.telemetry.send('didInitializeI18n', { groupProperties: { numberOfContentTypes } });\n};\n\nconst sendDidUpdateI18nLocalesEvent = async () => {\n const numberOfLocales = await getService('locales').count();\n\n await strapi.telemetry.send('didUpdateI18nLocales', {\n groupProperties: { numberOfLocales },\n });\n};\n\nconst sendWithAIEventProperty = async (event: string, payload: Record<string, any> = {}) => {\n const settings = await getService('settings').getSettings();\n\n strapi.telemetry.send(event, {\n ...payload,\n eventProperties: {\n ...payload?.eventProperties,\n isAIi18nConfigured: Boolean(settings?.aiLocalizations),\n },\n });\n};\n\nconst metrics = () => ({\n sendDidInitializeEvent,\n sendDidUpdateI18nLocalesEvent,\n sendWithAIEventProperty,\n});\n\ntype MetricsService = typeof metrics;\n\nexport default metrics;\nexport type { MetricsService };\n"],"names":["sendDidInitializeEvent","isLocalizedContentType","getService","numberOfContentTypes","reduce","sum","contentType","strapi","contentTypes","telemetry","send","groupProperties","sendDidUpdateI18nLocalesEvent","numberOfLocales","count","sendWithAIEventProperty","event","payload","settings","getSettings","eventProperties","isAIi18nConfigured","Boolean","aiLocalizations","metrics"],"mappings":";;;;;AAGA,MAAMA,sBAAyB,GAAA,UAAA;AAC7B,IAAA,MAAM,EAAEC,sBAAsB,EAAE,GAAGC,gBAAW,CAAA,eAAA,CAAA;;AAG9C,IAAA,MAAMC,oBAAuBC,GAAAA,SAAAA,CAC3B,CAACC,GAAAA,EAAKC,WAAiBL,GAAAA,sBAAAA,CAAuBK,WAAeD,CAAAA,GAAAA,GAAAA,GAAM,CAAIA,GAAAA,GAAAA,EACvE,CACAE,CAAAA,CAAAA,MAAAA,CAAOC,YAAY,CAAA;AAErB,IAAA,MAAMD,MAAOE,CAAAA,SAAS,CAACC,IAAI,CAAC,mBAAqB,EAAA;QAAEC,eAAiB,EAAA;AAAER,YAAAA;AAAqB;AAAE,KAAA,CAAA;AAC/F,CAAA;AAEA,MAAMS,6BAAgC,GAAA,UAAA;AACpC,IAAA,MAAMC,eAAkB,GAAA,MAAMX,gBAAW,CAAA,SAAA,CAAA,CAAWY,KAAK,EAAA;AAEzD,IAAA,MAAMP,MAAOE,CAAAA,SAAS,CAACC,IAAI,CAAC,sBAAwB,EAAA;QAClDC,eAAiB,EAAA;AAAEE,YAAAA;AAAgB;AACrC,KAAA,CAAA;AACF,CAAA;AAEA,MAAME,uBAA0B,GAAA,OAAOC,KAAeC,EAAAA,OAAAA,GAA+B,EAAE,GAAA;AACrF,IAAA,MAAMC,QAAW,GAAA,MAAMhB,gBAAW,CAAA,UAAA,CAAA,CAAYiB,WAAW,EAAA;AAEzDZ,IAAAA,MAAAA,CAAOE,SAAS,CAACC,IAAI,CAACM,KAAO,EAAA;AAC3B,QAAA,GAAGC,OAAO;QACVG,eAAiB,EAAA;AACf,YAAA,GAAGH,SAASG,eAAe;AAC3BC,YAAAA,kBAAAA,EAAoBC,QAAQJ,QAAUK,EAAAA,eAAAA;AACxC;AACF,KAAA,CAAA;AACF,CAAA;AAEMC,MAAAA,OAAAA,GAAU,KAAO;AACrBxB,QAAAA,sBAAAA;AACAY,QAAAA,6BAAAA;AACAG,QAAAA;KACF;;;;"}
@@ -19,9 +19,20 @@ const sendDidUpdateI18nLocalesEvent = async ()=>{
19
19
  }
20
20
  });
21
21
  };
22
+ const sendWithAIEventProperty = async (event, payload = {})=>{
23
+ const settings = await getService('settings').getSettings();
24
+ strapi.telemetry.send(event, {
25
+ ...payload,
26
+ eventProperties: {
27
+ ...payload?.eventProperties,
28
+ isAIi18nConfigured: Boolean(settings?.aiLocalizations)
29
+ }
30
+ });
31
+ };
22
32
  const metrics = ()=>({
23
33
  sendDidInitializeEvent,
24
- sendDidUpdateI18nLocalesEvent
34
+ sendDidUpdateI18nLocalesEvent,
35
+ sendWithAIEventProperty
25
36
  });
26
37
 
27
38
  export { metrics as default };
@@ -1 +1 @@
1
- {"version":3,"file":"metrics.mjs","sources":["../../../server/src/services/metrics.ts"],"sourcesContent":["import { reduce } from 'lodash/fp';\nimport { getService } from '../utils';\n\nconst sendDidInitializeEvent = async () => {\n const { isLocalizedContentType } = getService('content-types');\n\n // TODO: V5: This event should be renamed numberOfContentTypes in V5 as the name is already taken to describe the number of content types using i18n.\n const numberOfContentTypes = reduce(\n (sum, contentType) => (isLocalizedContentType(contentType) ? sum + 1 : sum),\n 0\n )(strapi.contentTypes as any);\n\n await strapi.telemetry.send('didInitializeI18n', { groupProperties: { numberOfContentTypes } });\n};\n\nconst sendDidUpdateI18nLocalesEvent = async () => {\n const numberOfLocales = await getService('locales').count();\n\n await strapi.telemetry.send('didUpdateI18nLocales', {\n groupProperties: { numberOfLocales },\n });\n};\n\nconst metrics = () => ({\n sendDidInitializeEvent,\n sendDidUpdateI18nLocalesEvent,\n});\n\ntype MetricsService = typeof metrics;\n\nexport default metrics;\nexport type { MetricsService };\n"],"names":["sendDidInitializeEvent","isLocalizedContentType","getService","numberOfContentTypes","reduce","sum","contentType","strapi","contentTypes","telemetry","send","groupProperties","sendDidUpdateI18nLocalesEvent","numberOfLocales","count","metrics"],"mappings":";;;AAGA,MAAMA,sBAAyB,GAAA,UAAA;AAC7B,IAAA,MAAM,EAAEC,sBAAsB,EAAE,GAAGC,UAAW,CAAA,eAAA,CAAA;;AAG9C,IAAA,MAAMC,oBAAuBC,GAAAA,MAAAA,CAC3B,CAACC,GAAAA,EAAKC,WAAiBL,GAAAA,sBAAAA,CAAuBK,WAAeD,CAAAA,GAAAA,GAAAA,GAAM,CAAIA,GAAAA,GAAAA,EACvE,CACAE,CAAAA,CAAAA,MAAAA,CAAOC,YAAY,CAAA;AAErB,IAAA,MAAMD,MAAOE,CAAAA,SAAS,CAACC,IAAI,CAAC,mBAAqB,EAAA;QAAEC,eAAiB,EAAA;AAAER,YAAAA;AAAqB;AAAE,KAAA,CAAA;AAC/F,CAAA;AAEA,MAAMS,6BAAgC,GAAA,UAAA;AACpC,IAAA,MAAMC,eAAkB,GAAA,MAAMX,UAAW,CAAA,SAAA,CAAA,CAAWY,KAAK,EAAA;AAEzD,IAAA,MAAMP,MAAOE,CAAAA,SAAS,CAACC,IAAI,CAAC,sBAAwB,EAAA;QAClDC,eAAiB,EAAA;AAAEE,YAAAA;AAAgB;AACrC,KAAA,CAAA;AACF,CAAA;AAEME,MAAAA,OAAAA,GAAU,KAAO;AACrBf,QAAAA,sBAAAA;AACAY,QAAAA;KACF;;;;"}
1
+ {"version":3,"file":"metrics.mjs","sources":["../../../server/src/services/metrics.ts"],"sourcesContent":["import { reduce } from 'lodash/fp';\nimport { getService } from '../utils';\n\nconst sendDidInitializeEvent = async () => {\n const { isLocalizedContentType } = getService('content-types');\n\n // TODO: V5: This event should be renamed numberOfContentTypes in V5 as the name is already taken to describe the number of content types using i18n.\n const numberOfContentTypes = reduce(\n (sum, contentType) => (isLocalizedContentType(contentType) ? sum + 1 : sum),\n 0\n )(strapi.contentTypes as any);\n\n await strapi.telemetry.send('didInitializeI18n', { groupProperties: { numberOfContentTypes } });\n};\n\nconst sendDidUpdateI18nLocalesEvent = async () => {\n const numberOfLocales = await getService('locales').count();\n\n await strapi.telemetry.send('didUpdateI18nLocales', {\n groupProperties: { numberOfLocales },\n });\n};\n\nconst sendWithAIEventProperty = async (event: string, payload: Record<string, any> = {}) => {\n const settings = await getService('settings').getSettings();\n\n strapi.telemetry.send(event, {\n ...payload,\n eventProperties: {\n ...payload?.eventProperties,\n isAIi18nConfigured: Boolean(settings?.aiLocalizations),\n },\n });\n};\n\nconst metrics = () => ({\n sendDidInitializeEvent,\n sendDidUpdateI18nLocalesEvent,\n sendWithAIEventProperty,\n});\n\ntype MetricsService = typeof metrics;\n\nexport default metrics;\nexport type { MetricsService };\n"],"names":["sendDidInitializeEvent","isLocalizedContentType","getService","numberOfContentTypes","reduce","sum","contentType","strapi","contentTypes","telemetry","send","groupProperties","sendDidUpdateI18nLocalesEvent","numberOfLocales","count","sendWithAIEventProperty","event","payload","settings","getSettings","eventProperties","isAIi18nConfigured","Boolean","aiLocalizations","metrics"],"mappings":";;;AAGA,MAAMA,sBAAyB,GAAA,UAAA;AAC7B,IAAA,MAAM,EAAEC,sBAAsB,EAAE,GAAGC,UAAW,CAAA,eAAA,CAAA;;AAG9C,IAAA,MAAMC,oBAAuBC,GAAAA,MAAAA,CAC3B,CAACC,GAAAA,EAAKC,WAAiBL,GAAAA,sBAAAA,CAAuBK,WAAeD,CAAAA,GAAAA,GAAAA,GAAM,CAAIA,GAAAA,GAAAA,EACvE,CACAE,CAAAA,CAAAA,MAAAA,CAAOC,YAAY,CAAA;AAErB,IAAA,MAAMD,MAAOE,CAAAA,SAAS,CAACC,IAAI,CAAC,mBAAqB,EAAA;QAAEC,eAAiB,EAAA;AAAER,YAAAA;AAAqB;AAAE,KAAA,CAAA;AAC/F,CAAA;AAEA,MAAMS,6BAAgC,GAAA,UAAA;AACpC,IAAA,MAAMC,eAAkB,GAAA,MAAMX,UAAW,CAAA,SAAA,CAAA,CAAWY,KAAK,EAAA;AAEzD,IAAA,MAAMP,MAAOE,CAAAA,SAAS,CAACC,IAAI,CAAC,sBAAwB,EAAA;QAClDC,eAAiB,EAAA;AAAEE,YAAAA;AAAgB;AACrC,KAAA,CAAA;AACF,CAAA;AAEA,MAAME,uBAA0B,GAAA,OAAOC,KAAeC,EAAAA,OAAAA,GAA+B,EAAE,GAAA;AACrF,IAAA,MAAMC,QAAW,GAAA,MAAMhB,UAAW,CAAA,UAAA,CAAA,CAAYiB,WAAW,EAAA;AAEzDZ,IAAAA,MAAAA,CAAOE,SAAS,CAACC,IAAI,CAACM,KAAO,EAAA;AAC3B,QAAA,GAAGC,OAAO;QACVG,eAAiB,EAAA;AACf,YAAA,GAAGH,SAASG,eAAe;AAC3BC,YAAAA,kBAAAA,EAAoBC,QAAQJ,QAAUK,EAAAA,eAAAA;AACxC;AACF,KAAA,CAAA;AACF,CAAA;AAEMC,MAAAA,OAAAA,GAAU,KAAO;AACrBxB,QAAAA,sBAAAA;AACAY,QAAAA,6BAAAA;AACAG,QAAAA;KACF;;;;"}
@@ -0,0 +1,25 @@
1
+ 'use strict';
2
+
3
+ const createSettingsService = ({ strapi })=>{
4
+ const settings = strapi.store({
5
+ type: 'plugin',
6
+ name: 'i18n',
7
+ key: 'settings'
8
+ });
9
+ async function getSettings() {
10
+ const res = await settings.get({});
11
+ return res;
12
+ }
13
+ function setSettings(value) {
14
+ return settings.set({
15
+ value
16
+ });
17
+ }
18
+ return {
19
+ getSettings,
20
+ setSettings
21
+ };
22
+ };
23
+
24
+ exports.createSettingsService = createSettingsService;
25
+ //# sourceMappingURL=settings.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"settings.js","sources":["../../../server/src/services/settings.ts"],"sourcesContent":["import type { Core } from '@strapi/types';\nimport type { Settings } from '../validation/settings';\n\nconst createSettingsService = ({ strapi }: { strapi: Core.Strapi }) => {\n const settings = strapi.store!({ type: 'plugin', name: 'i18n', key: 'settings' });\n\n async function getSettings() {\n const res = (await settings.get({})) as Settings | null;\n\n return res;\n }\n\n function setSettings(value: Settings) {\n return settings.set({ value });\n }\n\n return {\n getSettings,\n setSettings,\n };\n};\n\nexport { createSettingsService };\nexport type SettingsService = ReturnType<typeof createSettingsService>;\n"],"names":["createSettingsService","strapi","settings","store","type","name","key","getSettings","res","get","setSettings","value","set"],"mappings":";;AAGA,MAAMA,qBAAwB,GAAA,CAAC,EAAEC,MAAM,EAA2B,GAAA;IAChE,MAAMC,QAAAA,GAAWD,MAAOE,CAAAA,KAAK,CAAE;QAAEC,IAAM,EAAA,QAAA;QAAUC,IAAM,EAAA,MAAA;QAAQC,GAAK,EAAA;AAAW,KAAA,CAAA;IAE/E,eAAeC,WAAAA,GAAAA;AACb,QAAA,MAAMC,GAAO,GAAA,MAAMN,QAASO,CAAAA,GAAG,CAAC,EAAC,CAAA;QAEjC,OAAOD,GAAAA;AACT;AAEA,IAAA,SAASE,YAAYC,KAAe,EAAA;QAClC,OAAOT,QAAAA,CAASU,GAAG,CAAC;AAAED,YAAAA;AAAM,SAAA,CAAA;AAC9B;IAEA,OAAO;AACLJ,QAAAA,WAAAA;AACAG,QAAAA;AACF,KAAA;AACF;;;;"}
@@ -0,0 +1,23 @@
1
+ const createSettingsService = ({ strapi })=>{
2
+ const settings = strapi.store({
3
+ type: 'plugin',
4
+ name: 'i18n',
5
+ key: 'settings'
6
+ });
7
+ async function getSettings() {
8
+ const res = await settings.get({});
9
+ return res;
10
+ }
11
+ function setSettings(value) {
12
+ return settings.set({
13
+ value
14
+ });
15
+ }
16
+ return {
17
+ getSettings,
18
+ setSettings
19
+ };
20
+ };
21
+
22
+ export { createSettingsService };
23
+ //# sourceMappingURL=settings.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"settings.mjs","sources":["../../../server/src/services/settings.ts"],"sourcesContent":["import type { Core } from '@strapi/types';\nimport type { Settings } from '../validation/settings';\n\nconst createSettingsService = ({ strapi }: { strapi: Core.Strapi }) => {\n const settings = strapi.store!({ type: 'plugin', name: 'i18n', key: 'settings' });\n\n async function getSettings() {\n const res = (await settings.get({})) as Settings | null;\n\n return res;\n }\n\n function setSettings(value: Settings) {\n return settings.set({ value });\n }\n\n return {\n getSettings,\n setSettings,\n };\n};\n\nexport { createSettingsService };\nexport type SettingsService = ReturnType<typeof createSettingsService>;\n"],"names":["createSettingsService","strapi","settings","store","type","name","key","getSettings","res","get","setSettings","value","set"],"mappings":"AAGA,MAAMA,qBAAwB,GAAA,CAAC,EAAEC,MAAM,EAA2B,GAAA;IAChE,MAAMC,QAAAA,GAAWD,MAAOE,CAAAA,KAAK,CAAE;QAAEC,IAAM,EAAA,QAAA;QAAUC,IAAM,EAAA,MAAA;QAAQC,GAAK,EAAA;AAAW,KAAA,CAAA;IAE/E,eAAeC,WAAAA,GAAAA;AACb,QAAA,MAAMC,GAAO,GAAA,MAAMN,QAASO,CAAAA,GAAG,CAAC,EAAC,CAAA;QAEjC,OAAOD,GAAAA;AACT;AAEA,IAAA,SAASE,YAAYC,KAAe,EAAA;QAClC,OAAOT,QAAAA,CAASU,GAAG,CAAC;AAAED,YAAAA;AAAM,SAAA,CAAA;AAC9B;IAEA,OAAO;AACLJ,QAAAA,WAAAA;AACAG,QAAAA;AACF,KAAA;AACF;;;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"bootstrap.d.ts","sourceRoot":"","sources":["../../../server/src/bootstrap.ts"],"names":[],"mappings":";AA4DA,wBAuBE"}
1
+ {"version":3,"file":"bootstrap.d.ts","sourceRoot":"","sources":["../../../server/src/bootstrap.ts"],"names":[],"mappings":";AA4DA,wBA0BE"}
@@ -0,0 +1,17 @@
1
+ import type { Core } from '@strapi/types';
2
+ declare const createAILocalizationJobsController: ({ strapi }: {
3
+ strapi: Core.Strapi;
4
+ }) => {
5
+ /**
6
+ * Get a job for a singleType using the contentType
7
+ * There is only 1 job per contentType
8
+ */
9
+ getJobForSingleType(ctx: any): Promise<any>;
10
+ /**
11
+ * Get a job for a collectionType using the documentId
12
+ * There is only 1 job per documentId
13
+ */
14
+ getJobForCollectionType(ctx: any): Promise<any>;
15
+ };
16
+ export default createAILocalizationJobsController;
17
+ //# sourceMappingURL=ai-localization-jobs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ai-localization-jobs.d.ts","sourceRoot":"","sources":["../../../../server/src/controllers/ai-localization-jobs.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AAE1C,QAAA,MAAM,kCAAkC,eAAgB;IAAE,MAAM,EAAE,KAAK,MAAM,CAAA;CAAE;IAK3E;;;OAGG;6BAC4B,GAAG;IAkBlC;;;OAGG;iCACgC,GAAG;CAmBzC,CAAC;AAEF,eAAe,kCAAkC,CAAC"}
@@ -5,6 +5,16 @@ declare const _default: {
5
5
  'content-types': {
6
6
  getNonLocalizedAttributes(ctx: import("koa").Context): Promise<import("koa").Context | undefined>;
7
7
  };
8
+ settings: {
9
+ updateSettings(ctx: import("koa").Context): Promise<void>;
10
+ getSettings(ctx: import("koa").Context): Promise<void>;
11
+ };
12
+ 'ai-localization-jobs': ({ strapi }: {
13
+ strapi: import("@strapi/types/dist/core").Strapi;
14
+ }) => {
15
+ getJobForSingleType(ctx: any): Promise<any>;
16
+ getJobForCollectionType(ctx: any): Promise<any>;
17
+ };
8
18
  };
9
19
  export default _default;
10
20
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../server/src/controllers/index.ts"],"names":[],"mappings":";;;;;;;;AAIA,wBAIE"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../server/src/controllers/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;AAMA,wBAME"}
@@ -0,0 +1,7 @@
1
+ import type { Context } from 'koa';
2
+ declare const _default: {
3
+ updateSettings(ctx: Context): Promise<void>;
4
+ getSettings(ctx: Context): Promise<void>;
5
+ };
6
+ export default _default;
7
+ //# sourceMappingURL=settings.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"settings.d.ts","sourceRoot":"","sources":["../../../../server/src/controllers/settings.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,KAAK,CAAC;;wBAMP,OAAO;qBAYV,OAAO;;AAbhC,wBAkBE"}