@strapi/i18n 5.42.1 → 5.44.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.
- package/dist/admin/index.js +2 -0
- package/dist/admin/index.js.map +1 -1
- package/dist/admin/index.mjs +2 -0
- package/dist/admin/index.mjs.map +1 -1
- package/dist/admin/services/settings.js +1 -1
- package/dist/admin/services/settings.js.map +1 -1
- package/dist/admin/services/settings.mjs +1 -1
- package/dist/admin/services/settings.mjs.map +1 -1
- package/dist/admin/src/services/aiLocalizationJobs.d.ts +1 -1
- package/dist/admin/src/services/api.d.ts +1 -1
- package/dist/admin/src/services/fillFromLocale.d.ts +1 -1
- package/dist/admin/src/services/locales.d.ts +1 -1
- package/dist/admin/src/services/relations.d.ts +1 -1
- package/dist/admin/src/services/settings.d.ts +2 -2
- package/dist/admin/translations/cs.json.js +91 -0
- package/dist/admin/translations/cs.json.js.map +1 -0
- package/dist/admin/translations/cs.json.mjs +89 -0
- package/dist/admin/translations/cs.json.mjs.map +1 -0
- package/dist/admin/translations/nl.json.js +91 -0
- package/dist/admin/translations/nl.json.js.map +1 -0
- package/dist/admin/translations/nl.json.mjs +89 -0
- package/dist/admin/translations/nl.json.mjs.map +1 -0
- package/dist/server/bootstrap.js +3 -1
- package/dist/server/bootstrap.js.map +1 -1
- package/dist/server/bootstrap.mjs +3 -1
- package/dist/server/bootstrap.mjs.map +1 -1
- package/dist/server/controllers/ai-localization-jobs.js +8 -0
- package/dist/server/controllers/ai-localization-jobs.js.map +1 -1
- package/dist/server/controllers/ai-localization-jobs.mjs +8 -0
- package/dist/server/controllers/ai-localization-jobs.mjs.map +1 -1
- package/dist/server/services/ai-localizations.js +3 -13
- package/dist/server/services/ai-localizations.js.map +1 -1
- package/dist/server/services/ai-localizations.mjs +3 -13
- package/dist/server/services/ai-localizations.mjs.map +1 -1
- package/dist/server/services/localizations.js +42 -2
- package/dist/server/services/localizations.js.map +1 -1
- package/dist/server/services/localizations.mjs +42 -2
- package/dist/server/services/localizations.mjs.map +1 -1
- package/dist/server/src/bootstrap.d.ts.map +1 -1
- package/dist/server/src/controllers/ai-localization-jobs.d.ts.map +1 -1
- package/dist/server/src/services/ai-localizations.d.ts.map +1 -1
- package/dist/server/src/services/localizations.d.ts.map +1 -1
- package/package.json +7 -7
|
@@ -109,22 +109,12 @@ const createAILocalizationsService = ({ strapi })=>{
|
|
|
109
109
|
return {
|
|
110
110
|
// Async to avoid changing the signature later (there will be a db check in the future)
|
|
111
111
|
async isEnabled () {
|
|
112
|
-
|
|
113
|
-
const isAIEnabled = strapi.config.get('admin.ai.enabled', true);
|
|
114
|
-
if (!isAIEnabled) {
|
|
115
|
-
return false;
|
|
116
|
-
}
|
|
117
|
-
// Check if the user's license grants access to AI features
|
|
118
|
-
const hasAccess = strapi.ee.features.isEnabled('cms-ai');
|
|
119
|
-
if (!hasAccess) {
|
|
112
|
+
if (strapi.ai.admin.isEnabled() === false) {
|
|
120
113
|
return false;
|
|
121
114
|
}
|
|
122
115
|
const settings = getService('settings');
|
|
123
116
|
const aiSettings = await settings.getSettings();
|
|
124
|
-
|
|
125
|
-
return false;
|
|
126
|
-
}
|
|
127
|
-
return true;
|
|
117
|
+
return aiSettings?.aiLocalizations === true;
|
|
128
118
|
},
|
|
129
119
|
/**
|
|
130
120
|
* Checks if there are localizations that need to be generated for the given document,
|
|
@@ -210,7 +200,7 @@ const createAILocalizationsService = ({ strapi })=>{
|
|
|
210
200
|
});
|
|
211
201
|
let token;
|
|
212
202
|
try {
|
|
213
|
-
const tokenData = await strapi.
|
|
203
|
+
const tokenData = await strapi.ai.admin.getAiToken();
|
|
214
204
|
token = tokenData.token;
|
|
215
205
|
} catch (error) {
|
|
216
206
|
await aiLocalizationJobsService.upsertJobForDocument({
|
|
@@ -1 +1 @@
|
|
|
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 UNSUPPORTED_ATTRIBUTE_TYPES: Schema.Attribute.Kind[] = [\n 'media',\n 'relation',\n 'boolean',\n 'enumeration',\n];\n\nconst IGNORED_FIELDS = [\n 'id',\n 'documentId',\n 'createdAt',\n 'updatedAt',\n 'publishedAt',\n 'locale',\n 'updatedBy',\n 'createdBy',\n 'localizations',\n];\n\n/**\n * Deep merge where target values take priority over source values.\n * Arrays are merged by index to align repeatable component / dynamic zone items.\n */\nconst deepMerge = (\n source: Record<string, any>,\n target: Record<string, any>\n): Record<string, any> => {\n const result = { ...source };\n\n for (const key of Object.keys(target)) {\n const sourceVal = source[key];\n const targetVal = target[key];\n\n if (Array.isArray(targetVal) && Array.isArray(sourceVal)) {\n result[key] = targetVal.map((item, i) => {\n if (item && typeof item === 'object' && sourceVal[i] && typeof sourceVal[i] === 'object') {\n return deepMerge(sourceVal[i], item);\n }\n return item;\n });\n } else if (\n targetVal &&\n typeof targetVal === 'object' &&\n !Array.isArray(targetVal) &&\n sourceVal &&\n typeof sourceVal === 'object' &&\n !Array.isArray(sourceVal)\n ) {\n result[key] = deepMerge(sourceVal, targetVal);\n } else {\n result[key] = targetVal;\n }\n }\n\n return result;\n};\n\n/**\n * Merges unsupported field types (media, boolean, enumeration, relation)\n * from a source document into the target data object.\n *\n * Uses traverseEntity to walk the source document and extract only unsupported fields,\n * then deep-merges the AI-translated target data on top so translated values take priority.\n */\nconst mergeUnsupportedFields = async (\n targetData: Record<string, any>,\n sourceDoc: Record<string, any> | null,\n schema: Schema.Schema,\n getModel: (uid: UID.Schema) => Schema.Schema | undefined\n): Promise<Record<string, any>> => {\n if (!sourceDoc) {\n return targetData;\n }\n\n // Track paths of relation/media fields so traverseEntity's recursion\n // into those fields doesn't strip internal fields like `id` or `url`.\n const preservedPaths = new Set<string>();\n\n // Use traverseEntity to extract only unsupported fields from the source document.\n // traverseEntity handles component and dynamic zone recursion automatically.\n const unsupportedFieldsOnly = await traverseEntity(\n ({ key, attribute, path }, { remove }) => {\n // If we're inside a relation or media subtree, preserve everything.\n // Use path-based prefix check instead of parent-based check because\n // traverseEntity mutates `parent` across siblings at the same level,\n // which would incorrectly mark sibling fields as inside a preserved subtree.\n const isInsidePreservedSubtree =\n path.raw && Array.from(preservedPaths).some((pp) => path.raw!.startsWith(`${pp}.`));\n if (isInsidePreservedSubtree) {\n preservedPaths.add(path.raw!);\n return;\n }\n\n if (IGNORED_FIELDS.includes(key)) {\n remove(key);\n return;\n }\n\n // Keep fields with no schema attribute (e.g. __component in dynamic zones)\n if (!attribute) {\n return;\n }\n\n // Mark relation and media subtrees as preserved so their internal\n // fields (id, url, etc.) are not removed during recursion\n if (attribute.type === 'media' || attribute.type === 'relation') {\n preservedPaths.add(path.raw!);\n return;\n }\n\n // Keep other unsupported attribute types (boolean, enumeration)\n if (UNSUPPORTED_ATTRIBUTE_TYPES.includes(attribute.type)) {\n return;\n }\n\n // Keep components and dynamic zones — traverseEntity recurses into them\n if (attribute.type === 'component' || attribute.type === 'dynamiczone') {\n return;\n }\n\n // Remove supported (translatable) fields\n remove(key);\n },\n { schema, getModel: getModel as (uid: string) => Schema.Schema },\n sourceDoc\n );\n\n // Deep merge: AI-translated target takes priority over source unsupported fields\n return deepMerge(unsupportedFieldsOnly, targetData);\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 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.get('ai').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\n // Use populate-builder service for deep populate to fetch all nested fields\n const populateBuilderService = strapi.plugin('content-manager').service('populate-builder');\n // @ts-expect-error - populate-builder service returns a callable function\n const deepPopulate = await populateBuilderService(model).populateDeep(Infinity).build();\n const getModelBound = strapi.getModel.bind(strapi);\n\n // Fetch the source document with all fields populated (for new locales that don't exist yet)\n const sourceDocWithAllFields = await strapi.documents(model).findOne({\n documentId,\n locale: document.locale,\n populate: deepPopulate,\n });\n\n try {\n await Promise.all(\n aiResult.localizations.map(async (localization: any) => {\n const { content, locale } = localization;\n\n // Fetch the existing derived locale document with all fields populated\n const derivedDoc = await strapi.documents(model).findOne({\n documentId,\n locale,\n populate: deepPopulate,\n });\n\n // Start with AI-translated content\n let mergedData = structuredClone(content);\n\n // Merge unsupported fields from existing derived doc (if exists) or source doc\n // This preserves media, booleans, enumerations, and relations at all levels\n const sourceForUnsupportedFields = derivedDoc || sourceDocWithAllFields;\n mergedData = await mergeUnsupportedFields(\n mergedData,\n sourceForUnsupportedFields,\n schema,\n getModelBound\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 // 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, mergeUnsupportedFields };\n"],"names":["isLocalizedAttribute","attribute","pluginOptions","i18n","localized","UNSUPPORTED_ATTRIBUTE_TYPES","IGNORED_FIELDS","deepMerge","source","target","result","key","Object","keys","sourceVal","targetVal","Array","isArray","map","item","i","mergeUnsupportedFields","targetData","sourceDoc","schema","getModel","preservedPaths","Set","unsupportedFieldsOnly","traverseEntity","path","remove","isInsidePreservedSubtree","raw","from","some","pp","startsWith","add","includes","type","createAILocalizationsService","strapi","aiServerUrl","process","env","STRAPI_AI_URL","aiLocalizationJobsService","getService","isEnabled","isAIEnabled","config","get","hasAccess","ee","features","settings","aiSettings","getSettings","aiLocalizations","generateDocumentLocalizations","model","document","isFeatureEnabled","localeService","isLocalizedContentType","defaultLocale","getDefaultLocale","locale","documentId","log","warn","uid","localizedRoots","translateableContent","parent","hasLocalizedOption","has","bind","length","info","localesList","find","targetLocales","filter","l","code","upsertJobForDocument","contentType","sourceLocale","status","token","tokenData","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","populateBuilderService","plugin","service","deepPopulate","populateDeep","Infinity","build","getModelBound","sourceDocWithAllFields","documents","findOne","populate","Promise","all","localizations","localization","derivedDoc","mergedData","structuredClone","sourceForUnsupportedFields","update","fields","data","setupMiddleware","use","context","next","action","catch"],"mappings":"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"}
|
|
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 UNSUPPORTED_ATTRIBUTE_TYPES: Schema.Attribute.Kind[] = [\n 'media',\n 'relation',\n 'boolean',\n 'enumeration',\n];\n\nconst IGNORED_FIELDS = [\n 'id',\n 'documentId',\n 'createdAt',\n 'updatedAt',\n 'publishedAt',\n 'locale',\n 'updatedBy',\n 'createdBy',\n 'localizations',\n];\n\n/**\n * Deep merge where target values take priority over source values.\n * Arrays are merged by index to align repeatable component / dynamic zone items.\n */\nconst deepMerge = (\n source: Record<string, any>,\n target: Record<string, any>\n): Record<string, any> => {\n const result = { ...source };\n\n for (const key of Object.keys(target)) {\n const sourceVal = source[key];\n const targetVal = target[key];\n\n if (Array.isArray(targetVal) && Array.isArray(sourceVal)) {\n result[key] = targetVal.map((item, i) => {\n if (item && typeof item === 'object' && sourceVal[i] && typeof sourceVal[i] === 'object') {\n return deepMerge(sourceVal[i], item);\n }\n return item;\n });\n } else if (\n targetVal &&\n typeof targetVal === 'object' &&\n !Array.isArray(targetVal) &&\n sourceVal &&\n typeof sourceVal === 'object' &&\n !Array.isArray(sourceVal)\n ) {\n result[key] = deepMerge(sourceVal, targetVal);\n } else {\n result[key] = targetVal;\n }\n }\n\n return result;\n};\n\n/**\n * Merges unsupported field types (media, boolean, enumeration, relation)\n * from a source document into the target data object.\n *\n * Uses traverseEntity to walk the source document and extract only unsupported fields,\n * then deep-merges the AI-translated target data on top so translated values take priority.\n */\nconst mergeUnsupportedFields = async (\n targetData: Record<string, any>,\n sourceDoc: Record<string, any> | null,\n schema: Schema.Schema,\n getModel: (uid: UID.Schema) => Schema.Schema | undefined\n): Promise<Record<string, any>> => {\n if (!sourceDoc) {\n return targetData;\n }\n\n // Track paths of relation/media fields so traverseEntity's recursion\n // into those fields doesn't strip internal fields like `id` or `url`.\n const preservedPaths = new Set<string>();\n\n // Use traverseEntity to extract only unsupported fields from the source document.\n // traverseEntity handles component and dynamic zone recursion automatically.\n const unsupportedFieldsOnly = await traverseEntity(\n ({ key, attribute, path }, { remove }) => {\n // If we're inside a relation or media subtree, preserve everything.\n // Use path-based prefix check instead of parent-based check because\n // traverseEntity mutates `parent` across siblings at the same level,\n // which would incorrectly mark sibling fields as inside a preserved subtree.\n const isInsidePreservedSubtree =\n path.raw && Array.from(preservedPaths).some((pp) => path.raw!.startsWith(`${pp}.`));\n if (isInsidePreservedSubtree) {\n preservedPaths.add(path.raw!);\n return;\n }\n\n if (IGNORED_FIELDS.includes(key)) {\n remove(key);\n return;\n }\n\n // Keep fields with no schema attribute (e.g. __component in dynamic zones)\n if (!attribute) {\n return;\n }\n\n // Mark relation and media subtrees as preserved so their internal\n // fields (id, url, etc.) are not removed during recursion\n if (attribute.type === 'media' || attribute.type === 'relation') {\n preservedPaths.add(path.raw!);\n return;\n }\n\n // Keep other unsupported attribute types (boolean, enumeration)\n if (UNSUPPORTED_ATTRIBUTE_TYPES.includes(attribute.type)) {\n return;\n }\n\n // Keep components and dynamic zones — traverseEntity recurses into them\n if (attribute.type === 'component' || attribute.type === 'dynamiczone') {\n return;\n }\n\n // Remove supported (translatable) fields\n remove(key);\n },\n { schema, getModel: getModel as (uid: string) => Schema.Schema },\n sourceDoc\n );\n\n // Deep merge: AI-translated target takes priority over source unsupported fields\n return deepMerge(unsupportedFieldsOnly, targetData);\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 return {\n // Async to avoid changing the signature later (there will be a db check in the future)\n async isEnabled() {\n if (strapi.ai.admin.isEnabled() === false) {\n return false;\n }\n const settings = getService('settings');\n const aiSettings = await settings.getSettings();\n return aiSettings?.aiLocalizations === 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.ai.admin.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 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\n // Use populate-builder service for deep populate to fetch all nested fields\n const populateBuilderService = strapi.plugin('content-manager').service('populate-builder');\n // @ts-expect-error - populate-builder service returns a callable function\n const deepPopulate = await populateBuilderService(model).populateDeep(Infinity).build();\n const getModelBound = strapi.getModel.bind(strapi);\n\n // Fetch the source document with all fields populated (for new locales that don't exist yet)\n const sourceDocWithAllFields = await strapi.documents(model).findOne({\n documentId,\n locale: document.locale,\n populate: deepPopulate,\n });\n\n try {\n await Promise.all(\n aiResult.localizations.map(async (localization: any) => {\n const { content, locale } = localization;\n\n // Fetch the existing derived locale document with all fields populated\n const derivedDoc = await strapi.documents(model).findOne({\n documentId,\n locale,\n populate: deepPopulate,\n });\n\n // Start with AI-translated content\n let mergedData = structuredClone(content);\n\n // Merge unsupported fields from existing derived doc (if exists) or source doc\n // This preserves media, booleans, enumerations, and relations at all levels\n const sourceForUnsupportedFields = derivedDoc || sourceDocWithAllFields;\n mergedData = await mergeUnsupportedFields(\n mergedData,\n sourceForUnsupportedFields,\n schema,\n getModelBound\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 // 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, mergeUnsupportedFields };\n"],"names":["isLocalizedAttribute","attribute","pluginOptions","i18n","localized","UNSUPPORTED_ATTRIBUTE_TYPES","IGNORED_FIELDS","deepMerge","source","target","result","key","Object","keys","sourceVal","targetVal","Array","isArray","map","item","i","mergeUnsupportedFields","targetData","sourceDoc","schema","getModel","preservedPaths","Set","unsupportedFieldsOnly","traverseEntity","path","remove","isInsidePreservedSubtree","raw","from","some","pp","startsWith","add","includes","type","createAILocalizationsService","strapi","aiServerUrl","process","env","STRAPI_AI_URL","aiLocalizationJobsService","getService","isEnabled","ai","admin","settings","aiSettings","getSettings","aiLocalizations","generateDocumentLocalizations","model","document","isFeatureEnabled","localeService","isLocalizedContentType","defaultLocale","getDefaultLocale","locale","documentId","log","warn","uid","localizedRoots","translateableContent","parent","hasLocalizedOption","has","bind","length","info","localesList","find","targetLocales","filter","l","code","upsertJobForDocument","contentType","sourceLocale","status","token","tokenData","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","populateBuilderService","plugin","service","deepPopulate","populateDeep","Infinity","build","getModelBound","sourceDocWithAllFields","documents","findOne","populate","Promise","all","localizations","localization","derivedDoc","mergedData","structuredClone","sourceForUnsupportedFields","update","fields","data","setupMiddleware","use","context","next","action","catch"],"mappings":"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"}
|
|
@@ -4,6 +4,45 @@ var fp = require('lodash/fp');
|
|
|
4
4
|
var utils = require('@strapi/utils');
|
|
5
5
|
var index = require('../utils/index.js');
|
|
6
6
|
|
|
7
|
+
/**
|
|
8
|
+
* Mutates the provided data object in place and returns the same reference
|
|
9
|
+
* with populated media values replaced by their upload file IDs.
|
|
10
|
+
*/ const normalizeMediaIds = (schema, data)=>{
|
|
11
|
+
if (!schema?.attributes || !data || typeof data !== 'object') {
|
|
12
|
+
return data;
|
|
13
|
+
}
|
|
14
|
+
Object.entries(schema.attributes).forEach(([attributeName, attribute])=>{
|
|
15
|
+
const value = data[attributeName];
|
|
16
|
+
if (value == null) {
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
if (attribute.type === 'media') {
|
|
20
|
+
if (attribute.multiple) {
|
|
21
|
+
data[attributeName] = Array.isArray(value) ? value.map((file)=>file && typeof file === 'object' && 'id' in file ? file.id : file) : value;
|
|
22
|
+
} else {
|
|
23
|
+
data[attributeName] = value && typeof value === 'object' && 'id' in value ? value.id : value;
|
|
24
|
+
}
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
if (attribute.type === 'component') {
|
|
28
|
+
const componentSchema = strapi.getModel(attribute.component);
|
|
29
|
+
if (attribute.repeatable && Array.isArray(value)) {
|
|
30
|
+
value.forEach((componentValue)=>normalizeMediaIds(componentSchema, componentValue));
|
|
31
|
+
} else {
|
|
32
|
+
normalizeMediaIds(componentSchema, value);
|
|
33
|
+
}
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
if (attribute.type === 'dynamiczone' && Array.isArray(value)) {
|
|
37
|
+
value.forEach((componentValue)=>{
|
|
38
|
+
if (componentValue?.__component) {
|
|
39
|
+
normalizeMediaIds(strapi.getModel(componentValue.__component), componentValue);
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
return data;
|
|
45
|
+
};
|
|
7
46
|
/**
|
|
8
47
|
* Update non localized fields of all the related localizations of an entry with the entry values
|
|
9
48
|
*/ const syncNonLocalizedAttributes = async (sourceEntry, model)=>{
|
|
@@ -12,6 +51,7 @@ var index = require('../utils/index.js');
|
|
|
12
51
|
if (fp.isEmpty(nonLocalizedAttributes)) {
|
|
13
52
|
return;
|
|
14
53
|
}
|
|
54
|
+
const normalizedNonLocalizedAttributes = normalizeMediaIds(model, nonLocalizedAttributes);
|
|
15
55
|
const uid = model.uid;
|
|
16
56
|
const documentId = sourceEntry.documentId;
|
|
17
57
|
const locale = sourceEntry.locale;
|
|
@@ -33,9 +73,9 @@ var index = require('../utils/index.js');
|
|
|
33
73
|
'id'
|
|
34
74
|
]
|
|
35
75
|
});
|
|
36
|
-
const entryData = await strapi.documents(uid).omitComponentData(
|
|
76
|
+
const entryData = await strapi.documents(uid).omitComponentData(normalizedNonLocalizedAttributes);
|
|
37
77
|
await utils.async.map(localeEntriesToUpdate, async (entry)=>{
|
|
38
|
-
const transformedData = await strapi.documents.utils.transformData(fp.cloneDeep(
|
|
78
|
+
const transformedData = await strapi.documents.utils.transformData(fp.cloneDeep(normalizedNonLocalizedAttributes), {
|
|
39
79
|
uid,
|
|
40
80
|
status,
|
|
41
81
|
locale: entry.locale,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"localizations.js","sources":["../../../server/src/services/localizations.ts"],"sourcesContent":["import { cloneDeep, isEmpty } from 'lodash/fp';\n\nimport type { Schema } from '@strapi/types';\nimport { async } from '@strapi/utils';\nimport { getService } from '../utils';\n\n/**\n * Update non localized fields of all the related localizations of an entry with the entry values\n */\nconst syncNonLocalizedAttributes = async (sourceEntry: any, model: Schema.ContentType) => {\n const { copyNonLocalizedAttributes } = getService('content-types');\n\n const nonLocalizedAttributes = copyNonLocalizedAttributes(model, sourceEntry);\n if (isEmpty(nonLocalizedAttributes)) {\n return;\n }\n\n const uid = model.uid;\n const documentId = sourceEntry.documentId;\n const locale = sourceEntry.locale;\n const status = sourceEntry?.publishedAt ? 'published' : 'draft';\n\n // Find all the entries that need to be updated\n // this is every other entry of the document in the same status but a different locale\n const localeEntriesToUpdate = await strapi.db.query(uid).findMany({\n where: {\n documentId,\n publishedAt: status === 'published' ? { $ne: null } : null,\n locale: { $ne: locale },\n },\n select: ['locale', 'id'],\n });\n\n const entryData = await strapi.documents(uid).omitComponentData(
|
|
1
|
+
{"version":3,"file":"localizations.js","sources":["../../../server/src/services/localizations.ts"],"sourcesContent":["import { cloneDeep, isEmpty } from 'lodash/fp';\n\nimport type { Schema } from '@strapi/types';\nimport { async } from '@strapi/utils';\nimport { getService } from '../utils';\n\n/**\n * Mutates the provided data object in place and returns the same reference\n * with populated media values replaced by their upload file IDs.\n */\nconst normalizeMediaIds = (\n schema: Schema.ContentType | Schema.Component,\n data: Record<string, any>\n) => {\n if (!schema?.attributes || !data || typeof data !== 'object') {\n return data;\n }\n\n Object.entries(schema.attributes).forEach(([attributeName, attribute]) => {\n const value = data[attributeName];\n\n if (value == null) {\n return;\n }\n\n if (attribute.type === 'media') {\n if (attribute.multiple) {\n data[attributeName] = Array.isArray(value)\n ? value.map((file: unknown) =>\n file && typeof file === 'object' && 'id' in file ? file.id : file\n )\n : value;\n } else {\n data[attributeName] =\n value && typeof value === 'object' && 'id' in value ? value.id : value;\n }\n\n return;\n }\n\n if (attribute.type === 'component') {\n const componentSchema = strapi.getModel(attribute.component);\n\n if (attribute.repeatable && Array.isArray(value)) {\n value.forEach((componentValue: Record<string, any>) =>\n normalizeMediaIds(componentSchema, componentValue)\n );\n } else {\n normalizeMediaIds(componentSchema, value);\n }\n\n return;\n }\n\n if (attribute.type === 'dynamiczone' && Array.isArray(value)) {\n value.forEach((componentValue: Record<string, any>) => {\n if (componentValue?.__component) {\n normalizeMediaIds(strapi.getModel(componentValue.__component), componentValue);\n }\n });\n }\n });\n\n return data;\n};\n\n/**\n * Update non localized fields of all the related localizations of an entry with the entry values\n */\nconst syncNonLocalizedAttributes = async (sourceEntry: any, model: Schema.ContentType) => {\n const { copyNonLocalizedAttributes } = getService('content-types');\n\n const nonLocalizedAttributes = copyNonLocalizedAttributes(model, sourceEntry);\n if (isEmpty(nonLocalizedAttributes)) {\n return;\n }\n\n const normalizedNonLocalizedAttributes = normalizeMediaIds(model, nonLocalizedAttributes);\n\n const uid = model.uid;\n const documentId = sourceEntry.documentId;\n const locale = sourceEntry.locale;\n const status = sourceEntry?.publishedAt ? 'published' : 'draft';\n\n // Find all the entries that need to be updated\n // this is every other entry of the document in the same status but a different locale\n const localeEntriesToUpdate = await strapi.db.query(uid).findMany({\n where: {\n documentId,\n publishedAt: status === 'published' ? { $ne: null } : null,\n locale: { $ne: locale },\n },\n select: ['locale', 'id'],\n });\n\n const entryData = await strapi.documents(uid).omitComponentData(normalizedNonLocalizedAttributes);\n\n await async.map(localeEntriesToUpdate, async (entry: any) => {\n const transformedData = await strapi.documents.utils.transformData(\n cloneDeep(normalizedNonLocalizedAttributes),\n {\n uid,\n status,\n locale: entry.locale,\n allowMissingId: true,\n }\n );\n\n // Update or create non localized components for the entry\n const componentData = await strapi\n .documents(uid)\n .updateComponents(entry, transformedData as any);\n\n // Update every other locale entry of this documentId in the same status\n await strapi.db.query(uid).update({\n where: {\n documentId,\n publishedAt: status === 'published' ? { $ne: null } : null,\n locale: { $eq: entry.locale },\n },\n // The data we send to the update function is the entry data merged with\n // the updated component data\n data: Object.assign(cloneDeep(entryData), componentData),\n });\n });\n};\n\nconst localizations = () => ({\n syncNonLocalizedAttributes,\n});\n\ntype LocalizationsService = typeof localizations;\n\nexport default localizations;\nexport type { LocalizationsService };\n"],"names":["normalizeMediaIds","schema","data","attributes","Object","entries","forEach","attributeName","attribute","value","type","multiple","Array","isArray","map","file","id","componentSchema","strapi","getModel","component","repeatable","componentValue","__component","syncNonLocalizedAttributes","sourceEntry","model","copyNonLocalizedAttributes","getService","nonLocalizedAttributes","isEmpty","normalizedNonLocalizedAttributes","uid","documentId","locale","status","publishedAt","localeEntriesToUpdate","db","query","findMany","where","$ne","select","entryData","documents","omitComponentData","async","entry","transformedData","utils","transformData","cloneDeep","allowMissingId","componentData","updateComponents","update","$eq","assign","localizations"],"mappings":"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"}
|
|
@@ -2,6 +2,45 @@ import { isEmpty, cloneDeep } from 'lodash/fp';
|
|
|
2
2
|
import { async } from '@strapi/utils';
|
|
3
3
|
import { getService } from '../utils/index.mjs';
|
|
4
4
|
|
|
5
|
+
/**
|
|
6
|
+
* Mutates the provided data object in place and returns the same reference
|
|
7
|
+
* with populated media values replaced by their upload file IDs.
|
|
8
|
+
*/ const normalizeMediaIds = (schema, data)=>{
|
|
9
|
+
if (!schema?.attributes || !data || typeof data !== 'object') {
|
|
10
|
+
return data;
|
|
11
|
+
}
|
|
12
|
+
Object.entries(schema.attributes).forEach(([attributeName, attribute])=>{
|
|
13
|
+
const value = data[attributeName];
|
|
14
|
+
if (value == null) {
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
if (attribute.type === 'media') {
|
|
18
|
+
if (attribute.multiple) {
|
|
19
|
+
data[attributeName] = Array.isArray(value) ? value.map((file)=>file && typeof file === 'object' && 'id' in file ? file.id : file) : value;
|
|
20
|
+
} else {
|
|
21
|
+
data[attributeName] = value && typeof value === 'object' && 'id' in value ? value.id : value;
|
|
22
|
+
}
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
if (attribute.type === 'component') {
|
|
26
|
+
const componentSchema = strapi.getModel(attribute.component);
|
|
27
|
+
if (attribute.repeatable && Array.isArray(value)) {
|
|
28
|
+
value.forEach((componentValue)=>normalizeMediaIds(componentSchema, componentValue));
|
|
29
|
+
} else {
|
|
30
|
+
normalizeMediaIds(componentSchema, value);
|
|
31
|
+
}
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
if (attribute.type === 'dynamiczone' && Array.isArray(value)) {
|
|
35
|
+
value.forEach((componentValue)=>{
|
|
36
|
+
if (componentValue?.__component) {
|
|
37
|
+
normalizeMediaIds(strapi.getModel(componentValue.__component), componentValue);
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
return data;
|
|
43
|
+
};
|
|
5
44
|
/**
|
|
6
45
|
* Update non localized fields of all the related localizations of an entry with the entry values
|
|
7
46
|
*/ const syncNonLocalizedAttributes = async (sourceEntry, model)=>{
|
|
@@ -10,6 +49,7 @@ import { getService } from '../utils/index.mjs';
|
|
|
10
49
|
if (isEmpty(nonLocalizedAttributes)) {
|
|
11
50
|
return;
|
|
12
51
|
}
|
|
52
|
+
const normalizedNonLocalizedAttributes = normalizeMediaIds(model, nonLocalizedAttributes);
|
|
13
53
|
const uid = model.uid;
|
|
14
54
|
const documentId = sourceEntry.documentId;
|
|
15
55
|
const locale = sourceEntry.locale;
|
|
@@ -31,9 +71,9 @@ import { getService } from '../utils/index.mjs';
|
|
|
31
71
|
'id'
|
|
32
72
|
]
|
|
33
73
|
});
|
|
34
|
-
const entryData = await strapi.documents(uid).omitComponentData(
|
|
74
|
+
const entryData = await strapi.documents(uid).omitComponentData(normalizedNonLocalizedAttributes);
|
|
35
75
|
await async.map(localeEntriesToUpdate, async (entry)=>{
|
|
36
|
-
const transformedData = await strapi.documents.utils.transformData(cloneDeep(
|
|
76
|
+
const transformedData = await strapi.documents.utils.transformData(cloneDeep(normalizedNonLocalizedAttributes), {
|
|
37
77
|
uid,
|
|
38
78
|
status,
|
|
39
79
|
locale: entry.locale,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"localizations.mjs","sources":["../../../server/src/services/localizations.ts"],"sourcesContent":["import { cloneDeep, isEmpty } from 'lodash/fp';\n\nimport type { Schema } from '@strapi/types';\nimport { async } from '@strapi/utils';\nimport { getService } from '../utils';\n\n/**\n * Update non localized fields of all the related localizations of an entry with the entry values\n */\nconst syncNonLocalizedAttributes = async (sourceEntry: any, model: Schema.ContentType) => {\n const { copyNonLocalizedAttributes } = getService('content-types');\n\n const nonLocalizedAttributes = copyNonLocalizedAttributes(model, sourceEntry);\n if (isEmpty(nonLocalizedAttributes)) {\n return;\n }\n\n const uid = model.uid;\n const documentId = sourceEntry.documentId;\n const locale = sourceEntry.locale;\n const status = sourceEntry?.publishedAt ? 'published' : 'draft';\n\n // Find all the entries that need to be updated\n // this is every other entry of the document in the same status but a different locale\n const localeEntriesToUpdate = await strapi.db.query(uid).findMany({\n where: {\n documentId,\n publishedAt: status === 'published' ? { $ne: null } : null,\n locale: { $ne: locale },\n },\n select: ['locale', 'id'],\n });\n\n const entryData = await strapi.documents(uid).omitComponentData(
|
|
1
|
+
{"version":3,"file":"localizations.mjs","sources":["../../../server/src/services/localizations.ts"],"sourcesContent":["import { cloneDeep, isEmpty } from 'lodash/fp';\n\nimport type { Schema } from '@strapi/types';\nimport { async } from '@strapi/utils';\nimport { getService } from '../utils';\n\n/**\n * Mutates the provided data object in place and returns the same reference\n * with populated media values replaced by their upload file IDs.\n */\nconst normalizeMediaIds = (\n schema: Schema.ContentType | Schema.Component,\n data: Record<string, any>\n) => {\n if (!schema?.attributes || !data || typeof data !== 'object') {\n return data;\n }\n\n Object.entries(schema.attributes).forEach(([attributeName, attribute]) => {\n const value = data[attributeName];\n\n if (value == null) {\n return;\n }\n\n if (attribute.type === 'media') {\n if (attribute.multiple) {\n data[attributeName] = Array.isArray(value)\n ? value.map((file: unknown) =>\n file && typeof file === 'object' && 'id' in file ? file.id : file\n )\n : value;\n } else {\n data[attributeName] =\n value && typeof value === 'object' && 'id' in value ? value.id : value;\n }\n\n return;\n }\n\n if (attribute.type === 'component') {\n const componentSchema = strapi.getModel(attribute.component);\n\n if (attribute.repeatable && Array.isArray(value)) {\n value.forEach((componentValue: Record<string, any>) =>\n normalizeMediaIds(componentSchema, componentValue)\n );\n } else {\n normalizeMediaIds(componentSchema, value);\n }\n\n return;\n }\n\n if (attribute.type === 'dynamiczone' && Array.isArray(value)) {\n value.forEach((componentValue: Record<string, any>) => {\n if (componentValue?.__component) {\n normalizeMediaIds(strapi.getModel(componentValue.__component), componentValue);\n }\n });\n }\n });\n\n return data;\n};\n\n/**\n * Update non localized fields of all the related localizations of an entry with the entry values\n */\nconst syncNonLocalizedAttributes = async (sourceEntry: any, model: Schema.ContentType) => {\n const { copyNonLocalizedAttributes } = getService('content-types');\n\n const nonLocalizedAttributes = copyNonLocalizedAttributes(model, sourceEntry);\n if (isEmpty(nonLocalizedAttributes)) {\n return;\n }\n\n const normalizedNonLocalizedAttributes = normalizeMediaIds(model, nonLocalizedAttributes);\n\n const uid = model.uid;\n const documentId = sourceEntry.documentId;\n const locale = sourceEntry.locale;\n const status = sourceEntry?.publishedAt ? 'published' : 'draft';\n\n // Find all the entries that need to be updated\n // this is every other entry of the document in the same status but a different locale\n const localeEntriesToUpdate = await strapi.db.query(uid).findMany({\n where: {\n documentId,\n publishedAt: status === 'published' ? { $ne: null } : null,\n locale: { $ne: locale },\n },\n select: ['locale', 'id'],\n });\n\n const entryData = await strapi.documents(uid).omitComponentData(normalizedNonLocalizedAttributes);\n\n await async.map(localeEntriesToUpdate, async (entry: any) => {\n const transformedData = await strapi.documents.utils.transformData(\n cloneDeep(normalizedNonLocalizedAttributes),\n {\n uid,\n status,\n locale: entry.locale,\n allowMissingId: true,\n }\n );\n\n // Update or create non localized components for the entry\n const componentData = await strapi\n .documents(uid)\n .updateComponents(entry, transformedData as any);\n\n // Update every other locale entry of this documentId in the same status\n await strapi.db.query(uid).update({\n where: {\n documentId,\n publishedAt: status === 'published' ? { $ne: null } : null,\n locale: { $eq: entry.locale },\n },\n // The data we send to the update function is the entry data merged with\n // the updated component data\n data: Object.assign(cloneDeep(entryData), componentData),\n });\n });\n};\n\nconst localizations = () => ({\n syncNonLocalizedAttributes,\n});\n\ntype LocalizationsService = typeof localizations;\n\nexport default localizations;\nexport type { LocalizationsService };\n"],"names":["normalizeMediaIds","schema","data","attributes","Object","entries","forEach","attributeName","attribute","value","type","multiple","Array","isArray","map","file","id","componentSchema","strapi","getModel","component","repeatable","componentValue","__component","syncNonLocalizedAttributes","sourceEntry","model","copyNonLocalizedAttributes","getService","nonLocalizedAttributes","isEmpty","normalizedNonLocalizedAttributes","uid","documentId","locale","status","publishedAt","localeEntriesToUpdate","db","query","findMany","where","$ne","select","entryData","documents","omitComponentData","async","entry","transformedData","utils","transformData","cloneDeep","allowMissingId","componentData","updateComponents","update","$eq","assign","localizations"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bootstrap.d.ts","sourceRoot":"","sources":["../../../server/src/bootstrap.ts"],"names":[],"mappings":";AAiFA,
|
|
1
|
+
{"version":3,"file":"bootstrap.d.ts","sourceRoot":"","sources":["../../../server/src/bootstrap.ts"],"names":[],"mappings":";AAiFA,wBA4BE"}
|
|
@@ -1 +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;
|
|
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;IAuBlC;;;OAGG;iCACgC,GAAG;CAwBzC,CAAC;AAEF,eAAe,kCAAkC,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ai-localizations.d.ts","sourceRoot":"","sources":["../../../../server/src/services/ai-localizations.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,eAAe,CAAC;AAiEhE;;;;;;GAMG;AACH,QAAA,MAAM,sBAAsB,eACd,OAAO,MAAM,EAAE,GAAG,CAAC,aACpB,OAAO,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI,UAC7B,OAAO,MAAM,YACX,CAAC,GAAG,EAAE,IAAI,MAAM,KAAK,OAAO,MAAM,GAAG,SAAS,KACvD,QAAQ,OAAO,MAAM,EAAE,GAAG,CAAC,CA4D7B,CAAC;AAEF,QAAA,MAAM,4BAA4B,eAAgB;IAAE,MAAM,EAAE,KAAK,MAAM,CAAA;CAAE;;
|
|
1
|
+
{"version":3,"file":"ai-localizations.d.ts","sourceRoot":"","sources":["../../../../server/src/services/ai-localizations.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,eAAe,CAAC;AAiEhE;;;;;;GAMG;AACH,QAAA,MAAM,sBAAsB,eACd,OAAO,MAAM,EAAE,GAAG,CAAC,aACpB,OAAO,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI,UAC7B,OAAO,MAAM,YACX,CAAC,GAAG,EAAE,IAAI,MAAM,KAAK,OAAO,MAAM,GAAG,SAAS,KACvD,QAAQ,OAAO,MAAM,EAAE,GAAG,CAAC,CA4D7B,CAAC;AAEF,QAAA,MAAM,4BAA4B,eAAgB;IAAE,MAAM,EAAE,KAAK,MAAM,CAAA;CAAE;;IAgBrE;;;;OAIG;wDAIA;QACD,KAAK,EAAE,IAAI,WAAW,CAAC;QACvB,QAAQ,EAAE,QAAQ,SAAS,CAAC,WAAW,CAAC;KACzC;;CAyQJ,CAAC;AAEF,OAAO,EAAE,4BAA4B,EAAE,sBAAsB,EAAE,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"localizations.d.ts","sourceRoot":"","sources":["../../../../server/src/services/localizations.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"localizations.d.ts","sourceRoot":"","sources":["../../../../server/src/services/localizations.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AA6H5C,QAAA,MAAM,aAAa;8CA1DoC,GAAG,SAAS,OAAO,WAAW;CA4DnF,CAAC;AAEH,KAAK,oBAAoB,GAAG,OAAO,aAAa,CAAC;AAEjD,eAAe,aAAa,CAAC;AAC7B,YAAY,EAAE,oBAAoB,EAAE,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@strapi/i18n",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.44.0",
|
|
4
4
|
"description": "Create read and update content in different languages, both from the Admin Panel and from the API",
|
|
5
5
|
"homepage": "https://strapi.io",
|
|
6
6
|
"bugs": {
|
|
@@ -63,7 +63,7 @@
|
|
|
63
63
|
"@reduxjs/toolkit": "1.9.7",
|
|
64
64
|
"@strapi/design-system": "2.2.0",
|
|
65
65
|
"@strapi/icons": "2.2.0",
|
|
66
|
-
"@strapi/utils": "5.
|
|
66
|
+
"@strapi/utils": "5.44.0",
|
|
67
67
|
"lodash": "4.18.1",
|
|
68
68
|
"qs": "6.15.0",
|
|
69
69
|
"react-intl": "6.6.2",
|
|
@@ -72,11 +72,11 @@
|
|
|
72
72
|
"zod": "3.25.67"
|
|
73
73
|
},
|
|
74
74
|
"devDependencies": {
|
|
75
|
-
"@strapi/admin": "5.
|
|
76
|
-
"@strapi/admin-test-utils": "5.
|
|
77
|
-
"@strapi/content-manager": "5.
|
|
78
|
-
"@strapi/database": "5.
|
|
79
|
-
"@strapi/types": "5.
|
|
75
|
+
"@strapi/admin": "5.44.0",
|
|
76
|
+
"@strapi/admin-test-utils": "5.44.0",
|
|
77
|
+
"@strapi/content-manager": "5.44.0",
|
|
78
|
+
"@strapi/database": "5.44.0",
|
|
79
|
+
"@strapi/types": "5.44.0",
|
|
80
80
|
"@testing-library/react": "16.3.0",
|
|
81
81
|
"@testing-library/user-event": "14.6.1",
|
|
82
82
|
"koa": "2.16.4",
|