{"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: Record<string, unknown> = { 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\n            const { maxLength, minLength } = attr as {\n              maxLength?: number;\n              minLength?: number;\n            };\n            if (typeof maxLength === 'number') {\n              minimalAttribute.maxLength = maxLength;\n            }\n            if (typeof minLength === 'number') {\n              minimalAttribute.minLength = minLength;\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()) as {\n        localizations: Array<{ content: Record<string, unknown>; locale: string }>;\n      };\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      const results = await Promise.allSettled(\n        aiResult.localizations.map(async (localization) => {\n          const { content, locale } = localization;\n\n          const derivedDoc = await strapi.documents(model).findOne({\n            documentId,\n            locale,\n            populate: deepPopulate,\n          });\n\n          let mergedData = structuredClone(content);\n\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      );\n\n      const failedLocales: string[] = [];\n      results.forEach((result, index) => {\n        if (result.status === 'rejected') {\n          const locale = aiResult.localizations[index]?.locale;\n          failedLocales.push(locale);\n          const reason =\n            result.reason instanceof Error ? result.reason.message : String(result.reason);\n          strapi.log.error(\n            `AI Localizations: failed to save locale \"${locale}\" for ${model} document ${documentId}: ${reason}`\n          );\n        }\n      });\n\n      await aiLocalizationJobsService.upsertJobForDocument({\n        documentId,\n        contentType: model,\n        sourceLocale: document.locale,\n        targetLocales,\n        status: failedLocales.length > 0 ? 'failed' : 'completed',\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","maxLength","minLength","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","results","Promise","allSettled","localizations","localization","derivedDoc","mergedData","structuredClone","sourceForUnsupportedFields","update","fields","data","failedLocales","forEach","index","push","reason","message","String","setupMiddleware","use","context","next","action","catch"],"mappings":"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"}