@pigment/auto-translate 1.6.0 → 1.6.1

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 (27) hide show
  1. package/README.md +15 -8
  2. package/dist/collections/translationExclusions.js +101 -4
  3. package/dist/collections/translationExclusions.js.map +1 -1
  4. package/dist/components/LockTranslation/actions/lockTranslations.d.ts +1 -1
  5. package/dist/components/LockTranslation/actions/lockTranslations.js +2 -2
  6. package/dist/components/LockTranslation/actions/lockTranslations.js.map +1 -1
  7. package/dist/components/LockTranslation/index.js +6 -3
  8. package/dist/components/LockTranslation/index.js.map +1 -1
  9. package/dist/components/OpenAiModelField.js +7 -4
  10. package/dist/components/OpenAiModelField.js.map +1 -1
  11. package/dist/components/TranslationControl.js +45 -51
  12. package/dist/components/TranslationControl.js.map +1 -1
  13. package/dist/globals/translationSettings.js +10 -10
  14. package/dist/globals/translationSettings.js.map +1 -1
  15. package/dist/services/translationService.js +4 -7
  16. package/dist/services/translationService.js.map +1 -1
  17. package/dist/utilities/fieldHelpers.d.ts +0 -29
  18. package/dist/utilities/fieldHelpers.js +0 -152
  19. package/dist/utilities/fieldHelpers.js.map +1 -1
  20. package/dist/utilities/injectTranslationControls.d.ts +1 -1
  21. package/dist/utilities/injectTranslationControls.js +16 -11
  22. package/dist/utilities/injectTranslationControls.js.map +1 -1
  23. package/package.json +36 -65
  24. package/dist/components/TranslationSettingsLock.css +0 -87
  25. package/dist/components/TranslationSettingsLock.d.ts +0 -9
  26. package/dist/components/TranslationSettingsLock.js +0 -155
  27. package/dist/components/TranslationSettingsLock.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/components/TranslationControl.tsx"],"sourcesContent":["'use client'\n\nimport { useDocumentInfo, useLocale } from '@payloadcms/ui'\nimport React, { useCallback, useEffect, useState } from 'react'\n\nimport './TranslationControl.css'\n\ntype TranslationControlProps = {\n collectionSlug?: string\n defaultLocale: string\n fieldPath?: string // Optional - will be inferred from Payload's path prop if not provided\n path?: string // Payload provides this at runtime with array/block indices\n}\n\n/**\n * UI component that allows users to toggle \"do not translate\" for specific fields\n * Only shows on secondary locales (not the default locale)\n * \n * The component can receive the field path in two ways:\n * 1. From Payload's `path` prop (preferred - includes runtime array/block indices)\n * 2. From the `fieldPath` clientProp (fallback - static path from field definition)\n */\nexport const TranslationControl: React.FC<TranslationControlProps> = ({\n collectionSlug,\n defaultLocale,\n fieldPath: clientFieldPath,\n path: payloadPath,\n}) => {\n // Use Payload's runtime path if available (includes array/block indices like \"layout.0.heading\")\n // Otherwise fall back to the static path from clientProps\n const fieldPath = payloadPath || clientFieldPath\n const { id, collectionSlug: docCollectionSlug } = useDocumentInfo()\n const { code: currentLocale } = useLocale()\n const [isExcluded, setIsExcluded] = useState(false)\n const [isLoading, setIsLoading] = useState(false)\n\n // Use collectionSlug from props or from document context\n const effectiveCollectionSlug = collectionSlug || docCollectionSlug\n\n // Don't show on default locale - you can only lock fields in secondary locales\n if (currentLocale === defaultLocale) {\n return null\n }\n\n // Don't show if we don't have a valid field path\n if (!fieldPath) {\n console.warn('[TranslationControl] No field path available')\n return null\n }\n\n // Load exclusion state on mount and when locale changes\n useEffect(() => {\n // Reset state when switching documents or when there's no ID (new document)\n if (!id || !effectiveCollectionSlug) {\n setIsExcluded(false) // Reset to default state\n return\n }\n\n const loadExclusionState = async () => {\n try {\n console.log('[TranslationControl] Loading exclusion state for:', {\n collection: effectiveCollectionSlug,\n documentId: id,\n fieldPath,\n locale: currentLocale,\n })\n\n // Build query for this specific locale AND document ID\n const whereQuery = {\n and: [\n { collection: { equals: effectiveCollectionSlug } },\n { documentId: { equals: id } }, // This ensures we only get exclusions for THIS document\n { locale: { equals: currentLocale } },\n ],\n }\n\n const queryString = new URLSearchParams({\n limit: '1',\n where: JSON.stringify(whereQuery),\n }).toString()\n\n const fullUrl = `/api/translation-exclusions?${queryString}`\n console.log('[TranslationControl] Query URL:', fullUrl)\n console.log('[TranslationControl] Where clause:', whereQuery)\n\n const response = await fetch(fullUrl)\n\n if (response.ok) {\n const data = await response.json()\n\n if (data.docs && data.docs.length > 0) {\n const exclusion = data.docs[0]\n\n // CRITICAL: Verify this exclusion belongs to THIS document AND locale\n if (exclusion.locale === currentLocale && exclusion.documentId === id) {\n const excludedPaths = exclusion.excludedPaths?.map((item: any) => item.path) || []\n const isFieldExcluded = excludedPaths.includes(fieldPath)\n\n console.log('[TranslationControl] Loaded exclusions for document', id, 'locale', currentLocale, ':', {\n excludedPaths,\n fieldPath,\n isFieldExcluded,\n })\n\n setIsExcluded(isFieldExcluded)\n } else {\n console.warn('[TranslationControl] Document/Locale mismatch in loaded exclusion!', {\n expectedLocale: currentLocale,\n expectedDocId: id,\n gotLocale: exclusion.locale,\n gotDocId: exclusion.documentId,\n })\n // This exclusion is for a different document - ignore it\n setIsExcluded(false)\n }\n } else {\n // No exclusions found for this document/locale - that's fine\n console.log('[TranslationControl] No exclusions found for document', id, 'locale', currentLocale)\n setIsExcluded(false)\n }\n }\n } catch (error) {\n console.error('[TranslationControl] Failed to load exclusion state:', error)\n }\n }\n\n loadExclusionState()\n }, [id, effectiveCollectionSlug, currentLocale, fieldPath])\n\n const toggleExclusion = useCallback(async () => {\n if (!id || !effectiveCollectionSlug) {\n return\n }\n\n setIsLoading(true)\n try {\n // Build query parameters for Payload REST API\n const whereQuery = {\n and: [\n { collection: { equals: effectiveCollectionSlug } },\n { documentId: { equals: id } },\n { locale: { equals: currentLocale } },\n ],\n }\n\n // Debug: Log the query we're making\n console.log('[TranslationControl] Fetching exclusions for:', {\n collection: effectiveCollectionSlug,\n documentId: id,\n fieldPath,\n locale: currentLocale,\n })\n\n // Properly format the where clause for Payload's REST API\n const queryString = new URLSearchParams({\n limit: '1',\n where: JSON.stringify(whereQuery),\n }).toString()\n\n const fullUrl = `/api/translation-exclusions?${queryString}`\n console.log('[TranslationControl] Toggle - Query URL:', fullUrl)\n console.log('[TranslationControl] Toggle - Where clause:', whereQuery)\n\n const findResponse = await fetch(fullUrl)\n\n let currentExcludedPaths: string[] = []\n let existingId: null | string = null\n\n if (findResponse.ok) {\n const data = await findResponse.json()\n console.log('[TranslationControl] Found exclusions:', data.docs)\n\n if (data.docs && data.docs.length > 0) {\n const exclusion = data.docs[0]\n\n // CRITICAL: Verify this exclusion belongs to THIS document AND locale\n if (exclusion.locale === currentLocale && exclusion.documentId === id) {\n existingId = exclusion.id\n currentExcludedPaths = exclusion.excludedPaths?.map((item: any) => item.path) || []\n console.log(\n '[TranslationControl] Current excluded paths for document',\n id,\n 'locale',\n currentLocale,\n ':',\n currentExcludedPaths,\n )\n } else {\n console.warn('[TranslationControl] Found exclusion for wrong document/locale!', {\n expectedLocale: currentLocale,\n expectedDocId: id,\n gotLocale: exclusion.locale,\n gotDocId: exclusion.documentId,\n })\n // Don't use this record - it's for a different document\n existingId = null\n currentExcludedPaths = []\n }\n }\n }\n\n // Update excluded paths for THIS locale only\n if (!isExcluded) {\n // Add path if not already excluded\n if (!currentExcludedPaths.includes(fieldPath)) {\n currentExcludedPaths.push(fieldPath)\n }\n } else {\n // Remove path from exclusions\n currentExcludedPaths = currentExcludedPaths.filter((path) => path !== fieldPath)\n }\n\n // Create the exclusion data - ALWAYS include the current locale\n const exclusionsData = {\n collection: effectiveCollectionSlug,\n documentId: id,\n excludedPaths: currentExcludedPaths.map((path) => ({ path })),\n locale: currentLocale, // Ensure this is the CURRENT locale\n }\n\n console.log('[TranslationControl] Saving exclusions:', exclusionsData)\n\n // Update or create record using Payload's REST API\n if (existingId) {\n const updateResponse = await fetch(`/api/translation-exclusions/${existingId}`, {\n body: JSON.stringify(exclusionsData),\n headers: {\n 'Content-Type': 'application/json',\n },\n method: 'PATCH',\n })\n\n if (updateResponse.ok) {\n const result = await updateResponse.json()\n console.log('[TranslationControl] Updated exclusions:', result.doc)\n }\n } else {\n const createResponse = await fetch('/api/translation-exclusions', {\n body: JSON.stringify(exclusionsData),\n headers: {\n 'Content-Type': 'application/json',\n },\n method: 'POST',\n })\n\n if (createResponse.ok) {\n const result = await createResponse.json()\n console.log('[TranslationControl] Created exclusions:', result.doc)\n }\n }\n\n setIsExcluded(!isExcluded)\n } catch (error) {\n console.error('[TranslationControl] Error toggling exclusion:', error)\n } finally {\n setIsLoading(false)\n }\n }, [id, effectiveCollectionSlug, currentLocale, fieldPath, isExcluded])\n\n // Don't show on create (no id yet)\n if (!id) {\n return null\n }\n\n return (\n <div className={`translation-control ${isExcluded ? 'is-excluded' : ''}`}>\n <button\n className=\"translation-control__button\"\n disabled={isLoading}\n onClick={toggleExclusion}\n title={\n isExcluded\n ? 'This field is locked and will not be auto-translated from the default language'\n : 'Click to lock this field from auto-translation'\n }\n type=\"button\"\n >\n <span className=\"translation-control__icon\">{isExcluded ? '🔒' : '🌐'}</span>\n <span className=\"translation-control__label\">\n {isExcluded ? 'Locked' : 'Auto-translate'}\n </span>\n </button>\n {isExcluded && (\n <span className=\"translation-control__status\">\n This field will not be overwritten when the default language version is updated.\n </span>\n )}\n </div>\n )\n}\n"],"names":["useDocumentInfo","useLocale","React","useCallback","useEffect","useState","TranslationControl","collectionSlug","defaultLocale","fieldPath","clientFieldPath","path","payloadPath","id","docCollectionSlug","code","currentLocale","isExcluded","setIsExcluded","isLoading","setIsLoading","effectiveCollectionSlug","console","warn","loadExclusionState","log","collection","documentId","locale","whereQuery","and","equals","queryString","URLSearchParams","limit","where","JSON","stringify","toString","fullUrl","response","fetch","ok","data","json","docs","length","exclusion","excludedPaths","map","item","isFieldExcluded","includes","expectedLocale","expectedDocId","gotLocale","gotDocId","error","toggleExclusion","findResponse","currentExcludedPaths","existingId","push","filter","exclusionsData","updateResponse","body","headers","method","result","doc","createResponse","div","className","button","disabled","onClick","title","type","span"],"mappings":"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"}
1
+ {"version":3,"sources":["../../src/components/TranslationControl.tsx"],"sourcesContent":["'use client'\n\nimport { useConfig, useDocumentInfo, useLocale } from '@payloadcms/ui'\nimport React, { useCallback, useEffect, useState } from 'react'\n\nimport './TranslationControl.css'\n\ntype TranslationControlProps = {\n collectionSlug?: string\n defaultLocale: string\n fieldPath?: string // Optional - will be inferred from Payload's path prop if not provided\n path?: string // Payload provides this at runtime with array/block indices\n}\n\n/**\n * UI component that allows users to toggle \"do not translate\" for specific fields\n * Only shows on secondary locales (not the default locale)\n * \n * The component can receive the field path in two ways:\n * 1. From Payload's `path` prop (preferred - includes runtime array/block indices)\n * 2. From the `fieldPath` clientProp (fallback - static path from field definition)\n */\nexport const TranslationControl: React.FC<TranslationControlProps> = ({\n collectionSlug,\n defaultLocale,\n fieldPath: clientFieldPath,\n path: payloadPath,\n}) => {\n // Use Payload's runtime path if available (includes array/block indices like \"layout.0.heading\")\n // Otherwise fall back to the static path from clientProps\n const fieldPath = payloadPath || clientFieldPath\n const { id, collectionSlug: docCollectionSlug } = useDocumentInfo()\n const { code: currentLocale } = useLocale()\n const {\n config: { routes, serverURL },\n } = useConfig()\n const exclusionsURL = `${serverURL}${routes.api}/translation-exclusions`\n const [isExcluded, setIsExcluded] = useState(false)\n const [isLoading, setIsLoading] = useState(false)\n\n // Use collectionSlug from props or from document context\n const effectiveCollectionSlug = collectionSlug || docCollectionSlug\n\n // Load exclusion state on mount and when locale changes\n useEffect(() => {\n // Reset state when switching documents, on create (no ID), or on the default\n // locale where the control is hidden anyway\n if (!id || !effectiveCollectionSlug || currentLocale === defaultLocale) {\n setIsExcluded(false) // Reset to default state\n return\n }\n\n const loadExclusionState = async () => {\n try {\n console.log('[TranslationControl] Loading exclusion state for:', {\n collection: effectiveCollectionSlug,\n documentId: id,\n fieldPath,\n locale: currentLocale,\n })\n\n // Build query for this specific locale AND document ID\n const whereQuery = {\n and: [\n { collectionSlug: { equals: effectiveCollectionSlug } },\n { documentId: { equals: String(id) } }, // This ensures we only get exclusions for THIS document\n { locale: { equals: currentLocale } },\n ],\n }\n\n const queryString = new URLSearchParams({\n limit: '1',\n where: JSON.stringify(whereQuery),\n }).toString()\n\n const fullUrl = `${exclusionsURL}?${queryString}`\n console.log('[TranslationControl] Query URL:', fullUrl)\n console.log('[TranslationControl] Where clause:', whereQuery)\n\n const response = await fetch(fullUrl)\n\n if (response.ok) {\n const data = await response.json()\n\n if (data.docs && data.docs.length > 0) {\n const exclusion = data.docs[0]\n\n // CRITICAL: Verify this exclusion belongs to THIS document AND locale\n if (exclusion.locale === currentLocale && exclusion.documentId === String(id)) {\n const excludedPaths = exclusion.excludedPaths?.map((item: any) => item.path) || []\n const isFieldExcluded = excludedPaths.includes(fieldPath)\n\n console.log('[TranslationControl] Loaded exclusions for document', id, 'locale', currentLocale, ':', {\n excludedPaths,\n fieldPath,\n isFieldExcluded,\n })\n\n setIsExcluded(isFieldExcluded)\n } else {\n console.warn('[TranslationControl] Document/Locale mismatch in loaded exclusion!', {\n expectedLocale: currentLocale,\n expectedDocId: id,\n gotLocale: exclusion.locale,\n gotDocId: exclusion.documentId,\n })\n // This exclusion is for a different document - ignore it\n setIsExcluded(false)\n }\n } else {\n // No exclusions found for this document/locale - that's fine\n console.log('[TranslationControl] No exclusions found for document', id, 'locale', currentLocale)\n setIsExcluded(false)\n }\n }\n } catch (error) {\n console.error('[TranslationControl] Failed to load exclusion state:', error)\n }\n }\n\n loadExclusionState()\n }, [id, effectiveCollectionSlug, currentLocale, defaultLocale, fieldPath, exclusionsURL])\n\n const toggleExclusion = useCallback(async () => {\n if (!id || !effectiveCollectionSlug || !fieldPath) {\n return\n }\n\n setIsLoading(true)\n try {\n // Build query parameters for Payload REST API\n const whereQuery = {\n and: [\n { collectionSlug: { equals: effectiveCollectionSlug } },\n { documentId: { equals: String(id) } },\n { locale: { equals: currentLocale } },\n ],\n }\n\n // Debug: Log the query we're making\n console.log('[TranslationControl] Fetching exclusions for:', {\n collection: effectiveCollectionSlug,\n documentId: id,\n fieldPath,\n locale: currentLocale,\n })\n\n // Properly format the where clause for Payload's REST API\n const queryString = new URLSearchParams({\n limit: '1',\n where: JSON.stringify(whereQuery),\n }).toString()\n\n const fullUrl = `${exclusionsURL}?${queryString}`\n console.log('[TranslationControl] Toggle - Query URL:', fullUrl)\n console.log('[TranslationControl] Toggle - Where clause:', whereQuery)\n\n const findResponse = await fetch(fullUrl)\n\n let currentExcludedPaths: string[] = []\n let existingId: null | string = null\n\n if (findResponse.ok) {\n const data = await findResponse.json()\n console.log('[TranslationControl] Found exclusions:', data.docs)\n\n if (data.docs && data.docs.length > 0) {\n const exclusion = data.docs[0]\n\n // CRITICAL: Verify this exclusion belongs to THIS document AND locale\n if (exclusion.locale === currentLocale && exclusion.documentId === String(id)) {\n existingId = exclusion.id\n currentExcludedPaths = exclusion.excludedPaths?.map((item: any) => item.path) || []\n console.log(\n '[TranslationControl] Current excluded paths for document',\n id,\n 'locale',\n currentLocale,\n ':',\n currentExcludedPaths,\n )\n } else {\n console.warn('[TranslationControl] Found exclusion for wrong document/locale!', {\n expectedLocale: currentLocale,\n expectedDocId: id,\n gotLocale: exclusion.locale,\n gotDocId: exclusion.documentId,\n })\n // Don't use this record - it's for a different document\n existingId = null\n currentExcludedPaths = []\n }\n }\n }\n\n // Update excluded paths for THIS locale only\n if (!isExcluded) {\n // Add path if not already excluded\n if (!currentExcludedPaths.includes(fieldPath)) {\n currentExcludedPaths.push(fieldPath)\n }\n } else {\n // Remove path from exclusions\n currentExcludedPaths = currentExcludedPaths.filter((path) => path !== fieldPath)\n }\n\n // Create the exclusion data - ALWAYS include the current locale\n const exclusionsData = {\n collectionSlug: effectiveCollectionSlug,\n documentId: String(id),\n excludedPaths: currentExcludedPaths.map((path) => ({ path })),\n locale: currentLocale, // Ensure this is the CURRENT locale\n }\n\n console.log('[TranslationControl] Saving exclusions:', exclusionsData)\n\n // Update or create record using Payload's REST API\n const saveResponse = existingId\n ? await fetch(`${exclusionsURL}/${existingId}`, {\n body: JSON.stringify(exclusionsData),\n headers: {\n 'Content-Type': 'application/json',\n },\n method: 'PATCH',\n })\n : await fetch(exclusionsURL, {\n body: JSON.stringify(exclusionsData),\n headers: {\n 'Content-Type': 'application/json',\n },\n method: 'POST',\n })\n\n if (!saveResponse.ok) {\n const errorBody = await saveResponse.text()\n throw new Error(`Save failed (${saveResponse.status}): ${errorBody}`)\n }\n\n const result = await saveResponse.json()\n console.log('[TranslationControl] Saved exclusions:', result.doc)\n\n // Only flip the displayed state once the save is confirmed — otherwise\n // the button would show \"Locked\" for a field that was never persisted.\n setIsExcluded(!isExcluded)\n } catch (error) {\n console.error('[TranslationControl] Error toggling exclusion:', error)\n } finally {\n setIsLoading(false)\n }\n }, [id, effectiveCollectionSlug, currentLocale, fieldPath, isExcluded, exclusionsURL])\n\n // Don't show on default locale (you can only lock fields in secondary locales),\n // without a valid field path, or on create (no id yet)\n if (currentLocale === defaultLocale || !fieldPath || !id) {\n return null\n }\n\n return (\n <div className={`translation-control ${isExcluded ? 'is-excluded' : ''}`}>\n <button\n className=\"translation-control__button\"\n disabled={isLoading}\n onClick={toggleExclusion}\n title={\n isExcluded\n ? 'This field is locked and will not be auto-translated from the default language'\n : 'Click to lock this field from auto-translation'\n }\n type=\"button\"\n >\n <span className=\"translation-control__icon\">{isExcluded ? '🔒' : '🌐'}</span>\n <span className=\"translation-control__label\">\n {isExcluded ? 'Locked' : 'Auto-translate'}\n </span>\n </button>\n {isExcluded && (\n <span className=\"translation-control__status\">\n This field will not be overwritten when the default language version is updated.\n </span>\n )}\n </div>\n )\n}\n"],"names":["useConfig","useDocumentInfo","useLocale","React","useCallback","useEffect","useState","TranslationControl","collectionSlug","defaultLocale","fieldPath","clientFieldPath","path","payloadPath","id","docCollectionSlug","code","currentLocale","config","routes","serverURL","exclusionsURL","api","isExcluded","setIsExcluded","isLoading","setIsLoading","effectiveCollectionSlug","loadExclusionState","console","log","collection","documentId","locale","whereQuery","and","equals","String","queryString","URLSearchParams","limit","where","JSON","stringify","toString","fullUrl","response","fetch","ok","data","json","docs","length","exclusion","excludedPaths","map","item","isFieldExcluded","includes","warn","expectedLocale","expectedDocId","gotLocale","gotDocId","error","toggleExclusion","findResponse","currentExcludedPaths","existingId","push","filter","exclusionsData","saveResponse","body","headers","method","errorBody","text","Error","status","result","doc","div","className","button","disabled","onClick","title","type","span"],"mappings":"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"}
@@ -32,8 +32,8 @@ export const getTranslationSettingsGlobal = (slug = 'translation-settings')=>({
32
32
  type: 'textarea',
33
33
  access: {
34
34
  read: ()=>true,
35
- update: ({ data })=>{
36
- return !data?.lockTranslationSettings;
35
+ update: ({ doc })=>{
36
+ return !doc?.lockTranslationSettings;
37
37
  }
38
38
  },
39
39
  admin: {
@@ -49,8 +49,8 @@ export const getTranslationSettingsGlobal = (slug = 'translation-settings')=>({
49
49
  type: 'textarea',
50
50
  access: {
51
51
  read: ()=>true,
52
- update: ({ data })=>{
53
- return !data?.lockTranslationSettings;
52
+ update: ({ doc })=>{
53
+ return !doc?.lockTranslationSettings;
54
54
  }
55
55
  },
56
56
  admin: {
@@ -72,8 +72,8 @@ export const getTranslationSettingsGlobal = (slug = 'translation-settings')=>({
72
72
  type: 'text',
73
73
  access: {
74
74
  read: ()=>true,
75
- update: ({ data })=>{
76
- return !data?.lockTranslationSettings;
75
+ update: ({ doc })=>{
76
+ return !doc?.lockTranslationSettings;
77
77
  }
78
78
  },
79
79
  admin: {
@@ -91,8 +91,8 @@ export const getTranslationSettingsGlobal = (slug = 'translation-settings')=>({
91
91
  type: 'number',
92
92
  access: {
93
93
  read: ()=>true,
94
- update: ({ data })=>{
95
- return !data?.lockTranslationSettings;
94
+ update: ({ doc })=>{
95
+ return !doc?.lockTranslationSettings;
96
96
  }
97
97
  },
98
98
  admin: {
@@ -114,8 +114,8 @@ export const getTranslationSettingsGlobal = (slug = 'translation-settings')=>({
114
114
  type: 'number',
115
115
  access: {
116
116
  read: ()=>true,
117
- update: ({ data })=>{
118
- return !data?.lockTranslationSettings;
117
+ update: ({ doc })=>{
118
+ return !doc?.lockTranslationSettings;
119
119
  }
120
120
  },
121
121
  admin: {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/globals/translationSettings.ts"],"sourcesContent":["import type { GlobalConfig } from 'payload'\n\nimport { listOpenAiModelsEndpoint, supportsCustomTemperature } from '../endpoints/listOpenAiModels.js'\n\nexport const getTranslationSettingsGlobal = (\n slug: string = 'translation-settings',\n): GlobalConfig => ({\n slug,\n admin: {\n description: 'Configure translation settings including the system prompt and model parameters',\n group: 'Auto-Translate Settings',\n },\n endpoints: [listOpenAiModelsEndpoint],\n fields: [\n {\n name: 'settingsLock',\n type: 'ui',\n admin: {\n components: {\n Field: '@pigment/auto-translate/client#LockTranslation',\n },\n position: 'sidebar',\n },\n },\n {\n name: 'lockTranslationSettings',\n type: 'checkbox',\n admin: {\n hidden: true,\n },\n defaultValue: true,\n },\n {\n name: 'systemPrompt',\n type: 'textarea',\n access: {\n read: () => true,\n update: ({ data }) => {\n return !data?.lockTranslationSettings\n },\n },\n admin: {\n description:\n 'The main instruction for the AI translator. Use {fromLocale} and {toLocale} as placeholders.',\n rows: 3,\n },\n defaultValue: `You are a professional translator. Translate the JSON object values from {fromLocale} to {toLocale}.`,\n label: 'System Prompt',\n required: true,\n },\n {\n name: 'translationRules',\n type: 'textarea',\n access: {\n read: () => true,\n update: ({ data }) => {\n return !data?.lockTranslationSettings\n },\n },\n admin: {\n description:\n \"⚠️ Do not edit if you don't know what you are doing. These rules ensure proper JSON translation behavior.\",\n rows: 8,\n },\n defaultValue: `Rules:\n- Only translate the values, never the keys\n- Preserve the exact JSON structure\n- Do not translate field names like 'id', 'createdAt', 'updatedAt', etc.\n- Maintain formatting, HTML tags, and special characters\n- Return only valid JSON without any markdown formatting or code blocks\n- If a value is already in the target language or is a proper noun, keep it as is`,\n label: 'Translation Rules',\n required: true,\n },\n {\n name: 'model',\n type: 'text',\n access: {\n read: () => true,\n update: ({ data }) => {\n return !data?.lockTranslationSettings\n },\n },\n admin: {\n components: {\n Field: '@pigment/auto-translate/client#OpenAiModelField',\n },\n description: 'The OpenAI model to use for translations',\n },\n defaultValue: 'gpt-4o',\n label: 'Model',\n required: true,\n },\n {\n name: 'temperature',\n type: 'number',\n access: {\n read: () => true,\n update: ({ data }) => {\n return !data?.lockTranslationSettings\n },\n },\n admin: {\n description:\n 'Controls randomness in translation (0.0-2.0). Lower values are more deterministic. Not applied for GPT-5+ or o-series models.',\n step: 0.1,\n condition: (_data, siblingData) => {\n const model = typeof siblingData?.model === 'string' ? siblingData.model : ''\n return supportsCustomTemperature(model)\n },\n },\n defaultValue: 0.3,\n label: 'Temperature',\n max: 2,\n min: 0,\n required: true,\n },\n {\n name: 'maxTokens',\n type: 'number',\n access: {\n read: () => true,\n update: ({ data }) => {\n return !data?.lockTranslationSettings\n },\n },\n admin: {\n description: 'Maximum tokens for the response. Leave empty for automatic.',\n },\n label: 'Max Tokens',\n min: 1,\n },\n ],\n hooks: {\n afterChange: [\n async ({ data, req }) => {\n if (!data?.lockTranslationSettings) {\n const result = await req.payload.updateGlobal({\n slug: 'translation-settings',\n data: { lockTranslationSettings: true },\n req,\n })\n\n return result\n }\n },\n ],\n },\n label: 'Translation Settings',\n})\n"],"names":["listOpenAiModelsEndpoint","supportsCustomTemperature","getTranslationSettingsGlobal","slug","admin","description","group","endpoints","fields","name","type","components","Field","position","hidden","defaultValue","access","read","update","data","lockTranslationSettings","rows","label","required","step","condition","_data","siblingData","model","max","min","hooks","afterChange","req","result","payload","updateGlobal"],"mappings":"AAEA,SAASA,wBAAwB,EAAEC,yBAAyB,QAAQ,mCAAkC;AAEtG,OAAO,MAAMC,+BAA+B,CAC1CC,OAAe,sBAAsB,GACnB,CAAA;QAClBA;QACAC,OAAO;YACLC,aAAa;YACbC,OAAO;QACT;QACAC,WAAW;YAACP;SAAyB;QACrCQ,QAAQ;YACN;gBACEC,MAAM;gBACNC,MAAM;gBACNN,OAAO;oBACLO,YAAY;wBACVC,OAAO;oBACT;oBACAC,UAAU;gBACZ;YACF;YACA;gBACEJ,MAAM;gBACNC,MAAM;gBACNN,OAAO;oBACLU,QAAQ;gBACV;gBACAC,cAAc;YAChB;YACA;gBACEN,MAAM;gBACNC,MAAM;gBACNM,QAAQ;oBACNC,MAAM,IAAM;oBACZC,QAAQ,CAAC,EAAEC,IAAI,EAAE;wBACf,OAAO,CAACA,MAAMC;oBAChB;gBACF;gBACAhB,OAAO;oBACLC,aACE;oBACFgB,MAAM;gBACR;gBACAN,cAAc,CAAC,oGAAoG,CAAC;gBACpHO,OAAO;gBACPC,UAAU;YACZ;YACA;gBACEd,MAAM;gBACNC,MAAM;gBACNM,QAAQ;oBACNC,MAAM,IAAM;oBACZC,QAAQ,CAAC,EAAEC,IAAI,EAAE;wBACf,OAAO,CAACA,MAAMC;oBAChB;gBACF;gBACAhB,OAAO;oBACLC,aACE;oBACFgB,MAAM;gBACR;gBACAN,cAAc,CAAC;;;;;;iFAM4D,CAAC;gBAC5EO,OAAO;gBACPC,UAAU;YACZ;YACA;gBACEd,MAAM;gBACNC,MAAM;gBACNM,QAAQ;oBACNC,MAAM,IAAM;oBACZC,QAAQ,CAAC,EAAEC,IAAI,EAAE;wBACf,OAAO,CAACA,MAAMC;oBAChB;gBACF;gBACAhB,OAAO;oBACLO,YAAY;wBACVC,OAAO;oBACT;oBACAP,aAAa;gBACf;gBACAU,cAAc;gBACdO,OAAO;gBACPC,UAAU;YACZ;YACA;gBACEd,MAAM;gBACNC,MAAM;gBACNM,QAAQ;oBACNC,MAAM,IAAM;oBACZC,QAAQ,CAAC,EAAEC,IAAI,EAAE;wBACf,OAAO,CAACA,MAAMC;oBAChB;gBACF;gBACAhB,OAAO;oBACLC,aACE;oBACFmB,MAAM;oBACNC,WAAW,CAACC,OAAOC;wBACjB,MAAMC,QAAQ,OAAOD,aAAaC,UAAU,WAAWD,YAAYC,KAAK,GAAG;wBAC3E,OAAO3B,0BAA0B2B;oBACnC;gBACF;gBACAb,cAAc;gBACdO,OAAO;gBACPO,KAAK;gBACLC,KAAK;gBACLP,UAAU;YACZ;YACA;gBACEd,MAAM;gBACNC,MAAM;gBACNM,QAAQ;oBACNC,MAAM,IAAM;oBACZC,QAAQ,CAAC,EAAEC,IAAI,EAAE;wBACf,OAAO,CAACA,MAAMC;oBAChB;gBACF;gBACAhB,OAAO;oBACLC,aAAa;gBACf;gBACAiB,OAAO;gBACPQ,KAAK;YACP;SACD;QACDC,OAAO;YACLC,aAAa;gBACX,OAAO,EAAEb,IAAI,EAAEc,GAAG,EAAE;oBAClB,IAAI,CAACd,MAAMC,yBAAyB;wBAClC,MAAMc,SAAS,MAAMD,IAAIE,OAAO,CAACC,YAAY,CAAC;4BAC5CjC,MAAM;4BACNgB,MAAM;gCAAEC,yBAAyB;4BAAK;4BACtCa;wBACF;wBAEA,OAAOC;oBACT;gBACF;aACD;QACH;QACAZ,OAAO;IACT,CAAA,EAAE"}
1
+ {"version":3,"sources":["../../src/globals/translationSettings.ts"],"sourcesContent":["import type { GlobalConfig } from 'payload'\n\nimport { listOpenAiModelsEndpoint, supportsCustomTemperature } from '../endpoints/listOpenAiModels.js'\n\nexport const getTranslationSettingsGlobal = (\n slug: string = 'translation-settings',\n): GlobalConfig => ({\n slug,\n admin: {\n description: 'Configure translation settings including the system prompt and model parameters',\n group: 'Auto-Translate Settings',\n },\n endpoints: [listOpenAiModelsEndpoint],\n fields: [\n {\n name: 'settingsLock',\n type: 'ui',\n admin: {\n components: {\n Field: '@pigment/auto-translate/client#LockTranslation',\n },\n position: 'sidebar',\n },\n },\n {\n name: 'lockTranslationSettings',\n type: 'checkbox',\n admin: {\n hidden: true,\n },\n defaultValue: true,\n },\n {\n name: 'systemPrompt',\n type: 'textarea',\n access: {\n read: () => true,\n update: ({ doc }) => {\n return !doc?.lockTranslationSettings\n },\n },\n admin: {\n description:\n 'The main instruction for the AI translator. Use {fromLocale} and {toLocale} as placeholders.',\n rows: 3,\n },\n defaultValue: `You are a professional translator. Translate the JSON object values from {fromLocale} to {toLocale}.`,\n label: 'System Prompt',\n required: true,\n },\n {\n name: 'translationRules',\n type: 'textarea',\n access: {\n read: () => true,\n update: ({ doc }) => {\n return !doc?.lockTranslationSettings\n },\n },\n admin: {\n description:\n \"⚠️ Do not edit if you don't know what you are doing. These rules ensure proper JSON translation behavior.\",\n rows: 8,\n },\n defaultValue: `Rules:\n- Only translate the values, never the keys\n- Preserve the exact JSON structure\n- Do not translate field names like 'id', 'createdAt', 'updatedAt', etc.\n- Maintain formatting, HTML tags, and special characters\n- Return only valid JSON without any markdown formatting or code blocks\n- If a value is already in the target language or is a proper noun, keep it as is`,\n label: 'Translation Rules',\n required: true,\n },\n {\n name: 'model',\n type: 'text',\n access: {\n read: () => true,\n update: ({ doc }) => {\n return !doc?.lockTranslationSettings\n },\n },\n admin: {\n components: {\n Field: '@pigment/auto-translate/client#OpenAiModelField',\n },\n description: 'The OpenAI model to use for translations',\n },\n defaultValue: 'gpt-4o',\n label: 'Model',\n required: true,\n },\n {\n name: 'temperature',\n type: 'number',\n access: {\n read: () => true,\n update: ({ doc }) => {\n return !doc?.lockTranslationSettings\n },\n },\n admin: {\n description:\n 'Controls randomness in translation (0.0-2.0). Lower values are more deterministic. Not applied for GPT-5+ or o-series models.',\n step: 0.1,\n condition: (_data, siblingData) => {\n const model = typeof siblingData?.model === 'string' ? siblingData.model : ''\n return supportsCustomTemperature(model)\n },\n },\n defaultValue: 0.3,\n label: 'Temperature',\n max: 2,\n min: 0,\n required: true,\n },\n {\n name: 'maxTokens',\n type: 'number',\n access: {\n read: () => true,\n update: ({ doc }) => {\n return !doc?.lockTranslationSettings\n },\n },\n admin: {\n description: 'Maximum tokens for the response. Leave empty for automatic.',\n },\n label: 'Max Tokens',\n min: 1,\n },\n ],\n hooks: {\n afterChange: [\n async ({ data, req }) => {\n if (!data?.lockTranslationSettings) {\n const result = await req.payload.updateGlobal({\n slug: 'translation-settings',\n data: { lockTranslationSettings: true },\n req,\n })\n\n return result\n }\n },\n ],\n },\n label: 'Translation Settings',\n})\n"],"names":["listOpenAiModelsEndpoint","supportsCustomTemperature","getTranslationSettingsGlobal","slug","admin","description","group","endpoints","fields","name","type","components","Field","position","hidden","defaultValue","access","read","update","doc","lockTranslationSettings","rows","label","required","step","condition","_data","siblingData","model","max","min","hooks","afterChange","data","req","result","payload","updateGlobal"],"mappings":"AAEA,SAASA,wBAAwB,EAAEC,yBAAyB,QAAQ,mCAAkC;AAEtG,OAAO,MAAMC,+BAA+B,CAC1CC,OAAe,sBAAsB,GACnB,CAAA;QAClBA;QACAC,OAAO;YACLC,aAAa;YACbC,OAAO;QACT;QACAC,WAAW;YAACP;SAAyB;QACrCQ,QAAQ;YACN;gBACEC,MAAM;gBACNC,MAAM;gBACNN,OAAO;oBACLO,YAAY;wBACVC,OAAO;oBACT;oBACAC,UAAU;gBACZ;YACF;YACA;gBACEJ,MAAM;gBACNC,MAAM;gBACNN,OAAO;oBACLU,QAAQ;gBACV;gBACAC,cAAc;YAChB;YACA;gBACEN,MAAM;gBACNC,MAAM;gBACNM,QAAQ;oBACNC,MAAM,IAAM;oBACZC,QAAQ,CAAC,EAAEC,GAAG,EAAE;wBACd,OAAO,CAACA,KAAKC;oBACf;gBACF;gBACAhB,OAAO;oBACLC,aACE;oBACFgB,MAAM;gBACR;gBACAN,cAAc,CAAC,oGAAoG,CAAC;gBACpHO,OAAO;gBACPC,UAAU;YACZ;YACA;gBACEd,MAAM;gBACNC,MAAM;gBACNM,QAAQ;oBACNC,MAAM,IAAM;oBACZC,QAAQ,CAAC,EAAEC,GAAG,EAAE;wBACd,OAAO,CAACA,KAAKC;oBACf;gBACF;gBACAhB,OAAO;oBACLC,aACE;oBACFgB,MAAM;gBACR;gBACAN,cAAc,CAAC;;;;;;iFAM4D,CAAC;gBAC5EO,OAAO;gBACPC,UAAU;YACZ;YACA;gBACEd,MAAM;gBACNC,MAAM;gBACNM,QAAQ;oBACNC,MAAM,IAAM;oBACZC,QAAQ,CAAC,EAAEC,GAAG,EAAE;wBACd,OAAO,CAACA,KAAKC;oBACf;gBACF;gBACAhB,OAAO;oBACLO,YAAY;wBACVC,OAAO;oBACT;oBACAP,aAAa;gBACf;gBACAU,cAAc;gBACdO,OAAO;gBACPC,UAAU;YACZ;YACA;gBACEd,MAAM;gBACNC,MAAM;gBACNM,QAAQ;oBACNC,MAAM,IAAM;oBACZC,QAAQ,CAAC,EAAEC,GAAG,EAAE;wBACd,OAAO,CAACA,KAAKC;oBACf;gBACF;gBACAhB,OAAO;oBACLC,aACE;oBACFmB,MAAM;oBACNC,WAAW,CAACC,OAAOC;wBACjB,MAAMC,QAAQ,OAAOD,aAAaC,UAAU,WAAWD,YAAYC,KAAK,GAAG;wBAC3E,OAAO3B,0BAA0B2B;oBACnC;gBACF;gBACAb,cAAc;gBACdO,OAAO;gBACPO,KAAK;gBACLC,KAAK;gBACLP,UAAU;YACZ;YACA;gBACEd,MAAM;gBACNC,MAAM;gBACNM,QAAQ;oBACNC,MAAM,IAAM;oBACZC,QAAQ,CAAC,EAAEC,GAAG,EAAE;wBACd,OAAO,CAACA,KAAKC;oBACf;gBACF;gBACAhB,OAAO;oBACLC,aAAa;gBACf;gBACAiB,OAAO;gBACPQ,KAAK;YACP;SACD;QACDC,OAAO;YACLC,aAAa;gBACX,OAAO,EAAEC,IAAI,EAAEC,GAAG,EAAE;oBAClB,IAAI,CAACD,MAAMb,yBAAyB;wBAClC,MAAMe,SAAS,MAAMD,IAAIE,OAAO,CAACC,YAAY,CAAC;4BAC5ClC,MAAM;4BACN8B,MAAM;gCAAEb,yBAAyB;4BAAK;4BACtCc;wBACF;wBAEA,OAAOC;oBACT;gBACF;aACD;QACH;QACAb,OAAO;IACT,CAAA,EAAE"}
@@ -408,10 +408,8 @@ export class TranslationService {
408
408
  }
409
409
  return [];
410
410
  } catch (error) {
411
- if (this.config.debugging) {
412
- payload.logger.error(`[Auto-Translate] Error fetching exclusions: ${error}`);
413
- }
414
- return [];
411
+ payload.logger.error(`[Auto-Translate] Error fetching exclusions: ${error}`);
412
+ throw error;
415
413
  }
416
414
  }
417
415
  /**
@@ -638,9 +636,8 @@ export class TranslationService {
638
636
  payload.logger.info(`[Auto-Translate] Updated exclusions for ${collection}:${documentId}:${locale}`);
639
637
  }
640
638
  } catch (error) {
641
- if (this.config.debugging) {
642
- payload.logger.error(`[Auto-Translate] Error updating exclusions: ${error}`);
643
- }
639
+ payload.logger.error(`[Auto-Translate] Error updating exclusions: ${error}`);
640
+ throw error;
644
641
  }
645
642
  }
646
643
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/services/translationService.ts"],"sourcesContent":["import type { CollectionSlug, Field, GlobalSlug, Payload } from 'payload'\n\nimport OpenAI from 'openai'\n\nimport type { AutoTranslateConfig, TranslateOptions } from '../types/index.js'\n\nimport { supportsCustomTemperature } from '../endpoints/listOpenAiModels.js'\nimport { filterExcludedPaths, overlayNonTranslatableValues } from '../utilities/fieldHelpers.js'\n\nexport class TranslationService {\n private client?: OpenAI\n private config: AutoTranslateConfig\n\n constructor(config: AutoTranslateConfig) {\n this.config = config\n }\n\n /**\n * Extracts translatable text from lexical editor nodes\n */\n private extractFromLexicalNode(\n node: any,\n path: string,\n strings: Map<string, string>,\n deduplicationMap: Map<string, string[]>,\n ): any {\n const enableDeduplication = this.config.enableDeduplication !== false // Default to true\n\n // Handle text nodes - skip whitespace-only or very short text\n if (node.type === 'text' && node.text && typeof node.text === 'string') {\n const trimmed = node.text.trim()\n\n // Skip if empty, whitespace-only, or too short\n if (trimmed.length === 0 || this.shouldSkipString(node.text, `${path}.text`)) {\n return node\n }\n\n const textPath = `${path}.text`\n\n if (enableDeduplication) {\n // Check for deduplication\n if (deduplicationMap.has(trimmed)) {\n // This string already exists, just store the path mapping\n const existingPaths = deduplicationMap.get(trimmed)!\n existingPaths.push(textPath)\n return { ...node, text: `__TRANSLATE_${textPath}__` }\n } else {\n // New unique string\n strings.set(textPath, node.text)\n deduplicationMap.set(trimmed, [textPath])\n return { ...node, text: `__TRANSLATE_${textPath}__` }\n }\n } else {\n // No deduplication - add every string\n strings.set(textPath, node.text)\n deduplicationMap.set(trimmed, [textPath])\n return { ...node, text: `__TRANSLATE_${textPath}__` }\n }\n }\n\n // Handle nodes with children\n if (node.children && Array.isArray(node.children)) {\n return {\n ...node,\n children: node.children.map((child: any, index: number) =>\n this.extractFromLexicalNode(\n child,\n `${path}.children[${index}]`,\n strings,\n deduplicationMap,\n ),\n ),\n }\n }\n\n return node\n }\n\n /**\n * Extracts translatable strings from data structure\n * Returns a map of paths to translatable values and metadata for reconstruction\n */\n private extractTranslatableStrings(\n data: any,\n path: string = '',\n ): { deduplicationMap: Map<string, string[]>; metadata: any; strings: Map<string, string> } {\n const strings = new Map<string, string>()\n const deduplicationMap = new Map<string, string[]>() // value -> [paths]\n const enableDeduplication = this.config.enableDeduplication !== false // Default to true\n\n const extract = (obj: any, currentPath: string): any => {\n if (obj === null || obj === undefined) {\n return obj\n }\n\n // Handle lexical editor format\n if (this.isLexicalEditorNode(obj)) {\n return this.extractFromLexicalNode(obj, currentPath, strings, deduplicationMap)\n }\n\n // Handle arrays\n if (Array.isArray(obj)) {\n return obj.map((item, index) => extract(item, `${currentPath}[${index}]`))\n }\n\n // Handle objects\n if (typeof obj === 'object') {\n const result: any = {}\n for (const [key, value] of Object.entries(obj)) {\n const newPath = currentPath ? `${currentPath}.${key}` : key\n result[key] = extract(value, newPath)\n }\n return result\n }\n\n // Handle strings\n if (typeof obj === 'string' && obj.trim().length > 0) {\n // Skip IDs and other non-translatable strings\n if (!this.shouldSkipString(obj, currentPath)) {\n if (enableDeduplication) {\n // Check for deduplication\n const trimmedValue = obj.trim()\n if (deduplicationMap.has(trimmedValue)) {\n // This string already exists, just store the path mapping\n const existingPaths = deduplicationMap.get(trimmedValue)!\n existingPaths.push(currentPath)\n return `__TRANSLATE_${currentPath}__`\n } else {\n // New unique string\n strings.set(currentPath, obj)\n deduplicationMap.set(trimmedValue, [currentPath])\n return `__TRANSLATE_${currentPath}__`\n }\n } else {\n // No deduplication - add every string\n strings.set(currentPath, obj)\n deduplicationMap.set(obj.trim(), [currentPath])\n return `__TRANSLATE_${currentPath}__`\n }\n }\n }\n\n return obj\n }\n\n const metadata = extract(data, path)\n return { deduplicationMap, metadata, strings }\n }\n\n /**\n * Lazily initialize OpenAI client only when needed\n */\n private getOpenAIClient(): OpenAI {\n if (!this.client) {\n const apiKey = this.config.provider?.apiKey || process.env.OPENAI_API_KEY\n if (!apiKey) {\n throw new Error(\n 'OpenAI API key is required. Set OPENAI_API_KEY environment variable or provide it in plugin config.',\n )\n }\n\n this.client = new OpenAI({\n apiKey,\n baseURL: this.config.provider?.baseURL || process.env.OPENAI_BASE_URL,\n })\n }\n return this.client\n }\n\n /**\n * Gets the original value at a path in metadata (helper for deduplication)\n */\n private getOriginalValue(metadata: any, path: string): null | string {\n try {\n const parts = path.split(/[.[\\]]/).filter(Boolean)\n let current = metadata\n for (const part of parts) {\n if (current === null || current === undefined) {\n return null\n }\n current = current[part]\n }\n return typeof current === 'string' ? current : null\n } catch {\n return null\n }\n }\n\n /**\n * Gets translation settings from the global or returns defaults\n */\n private async getTranslationSettings(payload: Payload): Promise<{\n maxTokens?: number\n model: string\n systemPrompt: string\n temperature: number\n translationRules: string\n }> {\n const settingsSlug = this.config.translationSettingsSlug || 'translation-settings'\n\n // Default values\n const defaults = {\n maxTokens: undefined,\n model: this.config.provider?.model || 'gpt-4o',\n systemPrompt:\n 'You are a professional translator. Translate the JSON object values from {fromLocale} to {toLocale}.',\n temperature: 0.3,\n translationRules: `Rules:\n - Only translate the values, never the keys\n - Preserve the exact JSON structure\n - Maintain formatting, HTML tags, and special characters\n - Return only valid JSON without any markdown formatting or code blocks\n - If a value is already in the target language or is a proper noun, keep it as is`,\n }\n\n try {\n const settings = await payload.findGlobal({\n slug: settingsSlug as GlobalSlug,\n })\n\n if (settings) {\n return {\n maxTokens: settings.maxTokens || defaults.maxTokens,\n model: settings.model || defaults.model,\n systemPrompt: settings.systemPrompt || defaults.systemPrompt,\n temperature:\n typeof settings.temperature === 'number' ? settings.temperature : defaults.temperature,\n translationRules: settings.translationRules || defaults.translationRules,\n }\n }\n } catch (error) {\n if (this.config.debugging) {\n console.warn(\n '[Auto-Translate] Could not fetch translation settings, using defaults:',\n error,\n )\n }\n }\n\n return defaults\n }\n\n /**\n * Checks if an object is a lexical editor node\n */\n private isLexicalEditorNode(obj: any): boolean {\n return (\n obj &&\n typeof obj === 'object' &&\n 'type' in obj &&\n 'version' in obj &&\n ('children' in obj || 'text' in obj)\n )\n }\n\n /**\n * Reconstructs data with translated strings, applying deduplicated translations\n */\n private reconstructWithTranslations(\n metadata: any,\n translations: Map<string, string>,\n deduplicationMap: Map<string, string[]>,\n ): any {\n // Build a comprehensive translation map including deduplicated paths\n const fullTranslations = new Map<string, string>()\n\n // For each unique string that was translated\n translations.forEach((translatedValue, originalPath) => {\n fullTranslations.set(originalPath, translatedValue)\n\n // Find all paths that had the same original value\n const originalValue = this.getOriginalValue(metadata, originalPath)\n if (originalValue) {\n const trimmed = originalValue.replace(/^__TRANSLATE_(.+)__$/, '$1')\n // Look through deduplication map to find all paths with same value\n for (const [value, paths] of deduplicationMap.entries()) {\n if (paths.includes(originalPath)) {\n // Apply the same translation to all paths with this value\n paths.forEach((path) => {\n fullTranslations.set(path, translatedValue)\n })\n break\n }\n }\n }\n })\n\n const reconstruct = (obj: any): any => {\n if (obj === null || obj === undefined) {\n return obj\n }\n\n // Handle arrays\n if (Array.isArray(obj)) {\n return obj.map((item) => reconstruct(item))\n }\n\n // Handle objects\n if (typeof obj === 'object') {\n const result: any = {}\n for (const [key, value] of Object.entries(obj)) {\n result[key] = reconstruct(value)\n }\n return result\n }\n\n // Replace translation placeholders\n if (typeof obj === 'string' && obj.startsWith('__TRANSLATE_')) {\n const path = obj.slice(12, -2) // Remove __TRANSLATE_ prefix and __ suffix\n return fullTranslations.get(path) || obj\n }\n\n return obj\n }\n\n return reconstruct(metadata)\n }\n\n /**\n * Determines if a string should be skipped from translation\n */\n private shouldSkipString(str: string, path: string): boolean {\n // Skip IDs (MongoDB ObjectIds and similar)\n if (/^[a-f0-9]{24}$/i.test(str)) {\n return true\n }\n\n // Skip URLs\n if (/^https?:\\/\\//.test(str)) {\n return true\n }\n\n // Skip file paths\n if (/^\\/\\S*\\.(jpg|jpeg|png|gif|webp|svg|pdf|mp4|webm|ogg|mp3|wav)$/i.test(str)) {\n return true\n }\n\n // Skip email addresses\n if (/^[^\\s@]+@[^\\s@][^\\s.@]*\\.[^\\s@]+$/.test(str)) {\n return true\n }\n\n // Skip ISO date strings\n if (/^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}/.test(str)) {\n return true\n }\n\n // Skip date-time strings like \"2019-01-31 12:05:04\"\n if (/^\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}$/.test(str)) {\n return true\n }\n\n // Skip percentages like \"100%\"\n if (/^\\d+%$/.test(str)) {\n return true\n }\n\n // Skip pure numbers\n if (/^\\d+$/.test(str)) {\n return true\n }\n\n // Skip whitespace-only strings (including single spaces)\n if (str.trim().length === 0) {\n return true\n }\n\n // Skip very short strings based on config (default: 3 characters)\n const minLength = this.config.minStringLength !== undefined ? this.config.minStringLength : 3\n if (str.trim().length < minLength) {\n return true\n }\n\n // Skip status values\n if (['archived', 'draft', 'pending', 'published'].includes(str.toLowerCase())) {\n return true\n }\n\n // Skip paths ending with id, createdAt, updatedAt, etc.\n const pathLower = path.toLowerCase()\n if (\n pathLower.endsWith('id') ||\n pathLower.endsWith('_id') ||\n pathLower.includes('createdat') ||\n pathLower.includes('updatedat')\n ) {\n return true\n }\n\n return false\n }\n\n /**\n * Legacy translation method (sends entire structure)\n */\n private async translateWithOpenAILegacy(\n data: any,\n fromLocale: string,\n toLocale: string,\n payload: Payload,\n ): Promise<any> {\n const client = this.getOpenAIClient()\n const timeout = this.config.provider?.timeout || 30000\n\n try {\n // Get translation settings from global\n const settings = await this.getTranslationSettings(payload)\n\n // Build system message from settings\n const systemPrompt = settings.systemPrompt\n .replace('{fromLocale}', fromLocale)\n .replace('{toLocale}', toLocale)\n\n const systemMessage = `${systemPrompt}\\n\\n${settings.translationRules}`\n\n const requestParams = {\n messages: [\n {\n content: systemMessage,\n role: 'system' as const,\n },\n {\n content: JSON.stringify(data, null, 2),\n role: 'user' as const,\n },\n ],\n model: settings.model,\n response_format: { type: 'json_object' as const },\n ...(supportsCustomTemperature(settings.model)\n ? { temperature: settings.temperature }\n : {}),\n ...(settings.maxTokens ? { max_tokens: settings.maxTokens } : {}),\n }\n\n const response = await client.chat.completions.create(requestParams, { timeout })\n\n const translatedText = response.choices[0]?.message?.content\n\n if (!translatedText) {\n throw new Error('No translation received from OpenAI')\n }\n\n return JSON.parse(translatedText)\n } catch (error) {\n console.error('[Auto-Translate] Translation error:', error)\n throw error\n }\n }\n\n /**\n * Gets global and collection-specific excluded fields\n */\n getConfigExcludedFields(collection: string): string[] {\n const globalExclusions = this.config.excludeFields || []\n const collectionConfig = this.config.collections?.[collection as CollectionSlug]\n\n if (typeof collectionConfig === 'object' && collectionConfig.excludeFields) {\n return [...globalExclusions, ...collectionConfig.excludeFields]\n }\n\n return globalExclusions\n }\n\n /**\n * Gets translation exclusions for a document\n */\n async getExclusions(\n payload: Payload,\n collection: string,\n documentId: string,\n locale: string,\n ): Promise<string[]> {\n const exclusionsSlug = (this.config.translationExclusionsSlug ||\n 'translation-exclusions') as CollectionSlug\n\n try {\n const result = await payload.find({\n collection: exclusionsSlug,\n limit: 1,\n where: {\n and: [\n { collectionSlug: { equals: collection } },\n { documentId: { equals: documentId } },\n { locale: { equals: locale } },\n ],\n },\n })\n\n if (result.docs.length > 0) {\n const exclusion = result.docs[0] as any\n return exclusion.excludedPaths?.map((item: any) => item.path) || []\n }\n\n return []\n } catch (error) {\n if (this.config.debugging) {\n payload.logger.error(`[Auto-Translate] Error fetching exclusions: ${error}`)\n }\n return []\n }\n }\n\n /**\n * Main translation method\n */\n async translate(options: TranslateOptions): Promise<any> {\n const { collection, data, excludedPaths = [], fromLocale, payload, toLocale } = options\n\n // Filter out excluded paths before translation\n const dataToTranslate = filterExcludedPaths(data, excludedPaths)\n\n if (this.config.debugging) {\n payload.logger.info(\n `[Auto-Translate] Translating from ${fromLocale} to ${toLocale} for collection ${collection}`,\n )\n payload.logger.info(`[Auto-Translate] Excluded paths: ${excludedPaths.join(', ')}`)\n }\n\n // Run the configured translation strategy\n let translated: any\n if (this.config.provider?.customTranslate) {\n // Use custom translator if provided\n translated = await this.config.provider.customTranslate(options)\n } else {\n // Use OpenAI by default\n translated = await this.translateWithOpenAI(dataToTranslate, fromLocale, toLocale, payload)\n }\n\n // Restore canonical values for enum-backed fields (select/radio). The Postgres\n // adapter stores these as native enum columns, so a translated option value\n // (e.g. \"narrow\" -> \"schmal\") is rejected with `invalid input value for enum`.\n //\n // When `translateLocalizedFieldsOnly` is enabled, also restore every field that\n // is not localized (directly or via a localized ancestor container) so only\n // localized fields are translated.\n const fields = this.getDocumentFields(payload, collection)\n if (fields) {\n overlayNonTranslatableValues(translated, data, fields, {\n localizedOnly: this.config.translateLocalizedFieldsOnly === true,\n })\n }\n\n return translated\n }\n\n /**\n * Resolves the field schema for a collection or global slug so translation can\n * be made schema-aware (e.g. to avoid translating enum-backed select/radio\n * field values).\n */\n private getDocumentFields(payload: Payload, slug: string): Field[] | undefined {\n const collectionConfig = (payload as any).collections?.[slug]?.config\n if (collectionConfig && Array.isArray(collectionConfig.fields)) {\n return collectionConfig.fields\n }\n\n const globalConfig = (payload.config as any)?.globals?.find((g: any) => g.slug === slug)\n if (globalConfig && Array.isArray(globalConfig.fields)) {\n return globalConfig.fields\n }\n\n return undefined\n }\n\n /**\n * Translates using OpenAI API (optimized version)\n * This method is now public and can be used directly in your application\n */\n async translateWithOpenAI(\n data: any,\n fromLocale: string,\n toLocale: string,\n payload: Payload,\n ): Promise<any> {\n const client = this.getOpenAIClient()\n\n // Use optimization by default (can be disabled via config)\n const useOptimization = this.config.optimizeTranslation !== false\n\n if (!useOptimization) {\n // Use legacy approach: send entire structure\n return this.translateWithOpenAILegacy(data, fromLocale, toLocale, payload)\n }\n\n // Extract only translatable strings with deduplication\n const { deduplicationMap, metadata, strings } = this.extractTranslatableStrings(data)\n\n if (strings.size === 0) {\n // Nothing to translate\n return data\n }\n\n // Create a simple object with just the strings to translate\n const stringsToTranslate: Record<string, string> = {}\n strings.forEach((value, key) => {\n stringsToTranslate[key] = value\n })\n\n if (this.config.debugging) {\n const originalSize = JSON.stringify(data).length\n const optimizedSize = JSON.stringify(stringsToTranslate).length\n const reduction = ((1 - optimizedSize / originalSize) * 100).toFixed(1)\n\n // Calculate deduplication stats\n let totalPaths = 0\n deduplicationMap.forEach((paths) => {\n totalPaths += paths.length\n })\n const deduplicationSavings = totalPaths - strings.size\n const deduplicationPercent =\n totalPaths > 0 ? ((deduplicationSavings / totalPaths) * 100).toFixed(1) : '0'\n\n console.log('[Auto-Translate] ✨ Optimization Stats:')\n console.log(` 📊 Unique strings to translate: ${strings.size}`)\n console.log(` 🔄 Total string instances: ${totalPaths}`)\n console.log(\n ` 💾 Deduplication savings: ${deduplicationSavings} strings (${deduplicationPercent}%)`,\n )\n console.log(` 📦 Original JSON size: ${originalSize.toLocaleString()} bytes`)\n console.log(` 📦 Optimized JSON size: ${optimizedSize.toLocaleString()} bytes`)\n console.log(` 🎯 Total size reduction: ${reduction}%`)\n }\n\n try {\n // Get translation settings from global\n const settings = await this.getTranslationSettings(payload)\n\n // Add timeout configuration (default 30 seconds, configurable via plugin options)\n const timeout = this.config.provider?.timeout || 30000\n\n if (this.config.debugging) {\n console.log(\n `[Auto-Translate] Calling OpenAI API (timeout: ${timeout}ms, model: ${settings.model})`,\n )\n console.log(\n `[Auto-Translate] Payload size: ${JSON.stringify(stringsToTranslate).length} bytes`,\n )\n }\n\n // Build system message from settings\n const systemPrompt = settings.systemPrompt\n .replace('{fromLocale}', fromLocale)\n .replace('{toLocale}', toLocale)\n\n const systemMessage = `${systemPrompt}\\n\\n${settings.translationRules}`\n\n const requestParams = {\n messages: [\n {\n content: systemMessage,\n role: 'system' as const,\n },\n {\n content: JSON.stringify(stringsToTranslate, null, 2),\n role: 'user' as const,\n },\n ],\n model: settings.model,\n response_format: { type: 'json_object' as const },\n ...(supportsCustomTemperature(settings.model)\n ? { temperature: settings.temperature }\n : {}),\n ...(settings.maxTokens ? { max_tokens: settings.maxTokens } : {}),\n }\n\n const response = await client.chat.completions.create(requestParams, { timeout })\n\n const translatedText = response.choices[0]?.message?.content\n\n if (!translatedText) {\n throw new Error('No translation received from OpenAI')\n }\n\n if (this.config.debugging) {\n console.log(\n `[Auto-Translate] Received response from OpenAI (${translatedText.length} chars)`,\n )\n }\n\n let translatedStrings: any\n try {\n translatedStrings = JSON.parse(translatedText)\n } catch (parseError) {\n console.error('[Auto-Translate] Failed to parse OpenAI response as JSON')\n console.error('[Auto-Translate] Response text:', translatedText.substring(0, 500))\n throw new Error(\n `Invalid JSON response from OpenAI: ${parseError instanceof Error ? parseError.message : String(parseError)}`,\n )\n }\n\n // Convert back to Map\n const translationsMap = new Map<string, string>()\n for (const [key, value] of Object.entries(translatedStrings)) {\n if (typeof value === 'string') {\n translationsMap.set(key, value)\n }\n }\n\n // Reconstruct the full data structure with translations, applying deduplication\n return this.reconstructWithTranslations(metadata, translationsMap, deduplicationMap)\n } catch (error) {\n console.error('[Auto-Translate] Translation error:', error)\n\n // Provide more context about the error\n if (error && typeof error === 'object') {\n const err = error as any\n if (err.status) {\n console.error(`[Auto-Translate] OpenAI API status: ${err.status}`)\n }\n if (err.code) {\n console.error(`[Auto-Translate] Error code: ${err.code}`)\n }\n if (err.message) {\n console.error(`[Auto-Translate] Error message: ${err.message}`)\n }\n }\n\n // Add context to the error before re-throwing\n const contextualError = new Error(\n `Translation failed from ${fromLocale} to ${toLocale}: ${error instanceof Error ? error.message : String(error)}`,\n )\n contextualError.cause = error\n throw contextualError\n }\n }\n\n /**\n * Updates translation exclusions for a document\n */\n async updateExclusions(\n payload: Payload,\n collection: string,\n documentId: string,\n locale: string,\n excludedPaths: string[],\n ): Promise<void> {\n const exclusionsSlug = (this.config.translationExclusionsSlug ||\n 'translation-exclusions') as CollectionSlug\n\n try {\n const existing = await payload.find({\n collection: exclusionsSlug,\n limit: 1,\n where: {\n and: [\n { collectionSlug: { equals: collection } },\n { documentId: { equals: documentId } },\n { locale: { equals: locale } },\n ],\n },\n })\n\n const exclusionsData = {\n collectionSlug: collection,\n documentId,\n excludedPaths: excludedPaths.map((path) => ({ path })),\n locale,\n }\n\n if (existing.docs.length > 0) {\n await payload.update({\n id: existing.docs[0].id,\n collection: exclusionsSlug,\n data: exclusionsData,\n })\n } else {\n await payload.create({\n collection: exclusionsSlug,\n data: exclusionsData,\n })\n }\n\n if (this.config.debugging) {\n payload.logger.info(\n `[Auto-Translate] Updated exclusions for ${collection}:${documentId}:${locale}`,\n )\n }\n } catch (error) {\n if (this.config.debugging) {\n payload.logger.error(`[Auto-Translate] Error updating exclusions: ${error}`)\n }\n }\n }\n}\n"],"names":["OpenAI","supportsCustomTemperature","filterExcludedPaths","overlayNonTranslatableValues","TranslationService","client","config","extractFromLexicalNode","node","path","strings","deduplicationMap","enableDeduplication","type","text","trimmed","trim","length","shouldSkipString","textPath","has","existingPaths","get","push","set","children","Array","isArray","map","child","index","extractTranslatableStrings","data","Map","extract","obj","currentPath","undefined","isLexicalEditorNode","item","result","key","value","Object","entries","newPath","trimmedValue","metadata","getOpenAIClient","apiKey","provider","process","env","OPENAI_API_KEY","Error","baseURL","OPENAI_BASE_URL","getOriginalValue","parts","split","filter","Boolean","current","part","getTranslationSettings","payload","settingsSlug","translationSettingsSlug","defaults","maxTokens","model","systemPrompt","temperature","translationRules","settings","findGlobal","slug","error","debugging","console","warn","reconstructWithTranslations","translations","fullTranslations","forEach","translatedValue","originalPath","originalValue","replace","paths","includes","reconstruct","startsWith","slice","str","test","minLength","minStringLength","toLowerCase","pathLower","endsWith","translateWithOpenAILegacy","fromLocale","toLocale","timeout","systemMessage","requestParams","messages","content","role","JSON","stringify","response_format","max_tokens","response","chat","completions","create","translatedText","choices","message","parse","getConfigExcludedFields","collection","globalExclusions","excludeFields","collectionConfig","collections","getExclusions","documentId","locale","exclusionsSlug","translationExclusionsSlug","find","limit","where","and","collectionSlug","equals","docs","exclusion","excludedPaths","logger","translate","options","dataToTranslate","info","join","translated","customTranslate","translateWithOpenAI","fields","getDocumentFields","localizedOnly","translateLocalizedFieldsOnly","globalConfig","globals","g","useOptimization","optimizeTranslation","size","stringsToTranslate","originalSize","optimizedSize","reduction","toFixed","totalPaths","deduplicationSavings","deduplicationPercent","log","toLocaleString","translatedStrings","parseError","substring","String","translationsMap","err","status","code","contextualError","cause","updateExclusions","existing","exclusionsData","update","id"],"mappings":"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"}
1
+ {"version":3,"sources":["../../src/services/translationService.ts"],"sourcesContent":["import type { CollectionSlug, Field, GlobalSlug, Payload } from 'payload'\n\nimport OpenAI from 'openai'\n\nimport type { AutoTranslateConfig, TranslateOptions } from '../types/index.js'\n\nimport { supportsCustomTemperature } from '../endpoints/listOpenAiModels.js'\nimport { filterExcludedPaths, overlayNonTranslatableValues } from '../utilities/fieldHelpers.js'\n\nexport class TranslationService {\n private client?: OpenAI\n private config: AutoTranslateConfig\n\n constructor(config: AutoTranslateConfig) {\n this.config = config\n }\n\n /**\n * Extracts translatable text from lexical editor nodes\n */\n private extractFromLexicalNode(\n node: any,\n path: string,\n strings: Map<string, string>,\n deduplicationMap: Map<string, string[]>,\n ): any {\n const enableDeduplication = this.config.enableDeduplication !== false // Default to true\n\n // Handle text nodes - skip whitespace-only or very short text\n if (node.type === 'text' && node.text && typeof node.text === 'string') {\n const trimmed = node.text.trim()\n\n // Skip if empty, whitespace-only, or too short\n if (trimmed.length === 0 || this.shouldSkipString(node.text, `${path}.text`)) {\n return node\n }\n\n const textPath = `${path}.text`\n\n if (enableDeduplication) {\n // Check for deduplication\n if (deduplicationMap.has(trimmed)) {\n // This string already exists, just store the path mapping\n const existingPaths = deduplicationMap.get(trimmed)!\n existingPaths.push(textPath)\n return { ...node, text: `__TRANSLATE_${textPath}__` }\n } else {\n // New unique string\n strings.set(textPath, node.text)\n deduplicationMap.set(trimmed, [textPath])\n return { ...node, text: `__TRANSLATE_${textPath}__` }\n }\n } else {\n // No deduplication - add every string\n strings.set(textPath, node.text)\n deduplicationMap.set(trimmed, [textPath])\n return { ...node, text: `__TRANSLATE_${textPath}__` }\n }\n }\n\n // Handle nodes with children\n if (node.children && Array.isArray(node.children)) {\n return {\n ...node,\n children: node.children.map((child: any, index: number) =>\n this.extractFromLexicalNode(\n child,\n `${path}.children[${index}]`,\n strings,\n deduplicationMap,\n ),\n ),\n }\n }\n\n return node\n }\n\n /**\n * Extracts translatable strings from data structure\n * Returns a map of paths to translatable values and metadata for reconstruction\n */\n private extractTranslatableStrings(\n data: any,\n path: string = '',\n ): { deduplicationMap: Map<string, string[]>; metadata: any; strings: Map<string, string> } {\n const strings = new Map<string, string>()\n const deduplicationMap = new Map<string, string[]>() // value -> [paths]\n const enableDeduplication = this.config.enableDeduplication !== false // Default to true\n\n const extract = (obj: any, currentPath: string): any => {\n if (obj === null || obj === undefined) {\n return obj\n }\n\n // Handle lexical editor format\n if (this.isLexicalEditorNode(obj)) {\n return this.extractFromLexicalNode(obj, currentPath, strings, deduplicationMap)\n }\n\n // Handle arrays\n if (Array.isArray(obj)) {\n return obj.map((item, index) => extract(item, `${currentPath}[${index}]`))\n }\n\n // Handle objects\n if (typeof obj === 'object') {\n const result: any = {}\n for (const [key, value] of Object.entries(obj)) {\n const newPath = currentPath ? `${currentPath}.${key}` : key\n result[key] = extract(value, newPath)\n }\n return result\n }\n\n // Handle strings\n if (typeof obj === 'string' && obj.trim().length > 0) {\n // Skip IDs and other non-translatable strings\n if (!this.shouldSkipString(obj, currentPath)) {\n if (enableDeduplication) {\n // Check for deduplication\n const trimmedValue = obj.trim()\n if (deduplicationMap.has(trimmedValue)) {\n // This string already exists, just store the path mapping\n const existingPaths = deduplicationMap.get(trimmedValue)!\n existingPaths.push(currentPath)\n return `__TRANSLATE_${currentPath}__`\n } else {\n // New unique string\n strings.set(currentPath, obj)\n deduplicationMap.set(trimmedValue, [currentPath])\n return `__TRANSLATE_${currentPath}__`\n }\n } else {\n // No deduplication - add every string\n strings.set(currentPath, obj)\n deduplicationMap.set(obj.trim(), [currentPath])\n return `__TRANSLATE_${currentPath}__`\n }\n }\n }\n\n return obj\n }\n\n const metadata = extract(data, path)\n return { deduplicationMap, metadata, strings }\n }\n\n /**\n * Lazily initialize OpenAI client only when needed\n */\n private getOpenAIClient(): OpenAI {\n if (!this.client) {\n const apiKey = this.config.provider?.apiKey || process.env.OPENAI_API_KEY\n if (!apiKey) {\n throw new Error(\n 'OpenAI API key is required. Set OPENAI_API_KEY environment variable or provide it in plugin config.',\n )\n }\n\n this.client = new OpenAI({\n apiKey,\n baseURL: this.config.provider?.baseURL || process.env.OPENAI_BASE_URL,\n })\n }\n return this.client\n }\n\n /**\n * Gets the original value at a path in metadata (helper for deduplication)\n */\n private getOriginalValue(metadata: any, path: string): null | string {\n try {\n const parts = path.split(/[.[\\]]/).filter(Boolean)\n let current = metadata\n for (const part of parts) {\n if (current === null || current === undefined) {\n return null\n }\n current = current[part]\n }\n return typeof current === 'string' ? current : null\n } catch {\n return null\n }\n }\n\n /**\n * Gets translation settings from the global or returns defaults\n */\n private async getTranslationSettings(payload: Payload): Promise<{\n maxTokens?: number\n model: string\n systemPrompt: string\n temperature: number\n translationRules: string\n }> {\n const settingsSlug = this.config.translationSettingsSlug || 'translation-settings'\n\n // Default values\n const defaults = {\n maxTokens: undefined,\n model: this.config.provider?.model || 'gpt-4o',\n systemPrompt:\n 'You are a professional translator. Translate the JSON object values from {fromLocale} to {toLocale}.',\n temperature: 0.3,\n translationRules: `Rules:\n - Only translate the values, never the keys\n - Preserve the exact JSON structure\n - Maintain formatting, HTML tags, and special characters\n - Return only valid JSON without any markdown formatting or code blocks\n - If a value is already in the target language or is a proper noun, keep it as is`,\n }\n\n try {\n const settings = await payload.findGlobal({\n slug: settingsSlug as GlobalSlug,\n })\n\n if (settings) {\n return {\n maxTokens: settings.maxTokens || defaults.maxTokens,\n model: settings.model || defaults.model,\n systemPrompt: settings.systemPrompt || defaults.systemPrompt,\n temperature:\n typeof settings.temperature === 'number' ? settings.temperature : defaults.temperature,\n translationRules: settings.translationRules || defaults.translationRules,\n }\n }\n } catch (error) {\n if (this.config.debugging) {\n console.warn(\n '[Auto-Translate] Could not fetch translation settings, using defaults:',\n error,\n )\n }\n }\n\n return defaults\n }\n\n /**\n * Checks if an object is a lexical editor node\n */\n private isLexicalEditorNode(obj: any): boolean {\n return (\n obj &&\n typeof obj === 'object' &&\n 'type' in obj &&\n 'version' in obj &&\n ('children' in obj || 'text' in obj)\n )\n }\n\n /**\n * Reconstructs data with translated strings, applying deduplicated translations\n */\n private reconstructWithTranslations(\n metadata: any,\n translations: Map<string, string>,\n deduplicationMap: Map<string, string[]>,\n ): any {\n // Build a comprehensive translation map including deduplicated paths\n const fullTranslations = new Map<string, string>()\n\n // For each unique string that was translated\n translations.forEach((translatedValue, originalPath) => {\n fullTranslations.set(originalPath, translatedValue)\n\n // Find all paths that had the same original value\n const originalValue = this.getOriginalValue(metadata, originalPath)\n if (originalValue) {\n const trimmed = originalValue.replace(/^__TRANSLATE_(.+)__$/, '$1')\n // Look through deduplication map to find all paths with same value\n for (const [value, paths] of deduplicationMap.entries()) {\n if (paths.includes(originalPath)) {\n // Apply the same translation to all paths with this value\n paths.forEach((path) => {\n fullTranslations.set(path, translatedValue)\n })\n break\n }\n }\n }\n })\n\n const reconstruct = (obj: any): any => {\n if (obj === null || obj === undefined) {\n return obj\n }\n\n // Handle arrays\n if (Array.isArray(obj)) {\n return obj.map((item) => reconstruct(item))\n }\n\n // Handle objects\n if (typeof obj === 'object') {\n const result: any = {}\n for (const [key, value] of Object.entries(obj)) {\n result[key] = reconstruct(value)\n }\n return result\n }\n\n // Replace translation placeholders\n if (typeof obj === 'string' && obj.startsWith('__TRANSLATE_')) {\n const path = obj.slice(12, -2) // Remove __TRANSLATE_ prefix and __ suffix\n return fullTranslations.get(path) || obj\n }\n\n return obj\n }\n\n return reconstruct(metadata)\n }\n\n /**\n * Determines if a string should be skipped from translation\n */\n private shouldSkipString(str: string, path: string): boolean {\n // Skip IDs (MongoDB ObjectIds and similar)\n if (/^[a-f0-9]{24}$/i.test(str)) {\n return true\n }\n\n // Skip URLs\n if (/^https?:\\/\\//.test(str)) {\n return true\n }\n\n // Skip file paths\n if (/^\\/\\S*\\.(jpg|jpeg|png|gif|webp|svg|pdf|mp4|webm|ogg|mp3|wav)$/i.test(str)) {\n return true\n }\n\n // Skip email addresses\n if (/^[^\\s@]+@[^\\s@][^\\s.@]*\\.[^\\s@]+$/.test(str)) {\n return true\n }\n\n // Skip ISO date strings\n if (/^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}/.test(str)) {\n return true\n }\n\n // Skip date-time strings like \"2019-01-31 12:05:04\"\n if (/^\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}$/.test(str)) {\n return true\n }\n\n // Skip percentages like \"100%\"\n if (/^\\d+%$/.test(str)) {\n return true\n }\n\n // Skip pure numbers\n if (/^\\d+$/.test(str)) {\n return true\n }\n\n // Skip whitespace-only strings (including single spaces)\n if (str.trim().length === 0) {\n return true\n }\n\n // Skip very short strings based on config (default: 3 characters)\n const minLength = this.config.minStringLength !== undefined ? this.config.minStringLength : 3\n if (str.trim().length < minLength) {\n return true\n }\n\n // Skip status values\n if (['archived', 'draft', 'pending', 'published'].includes(str.toLowerCase())) {\n return true\n }\n\n // Skip paths ending with id, createdAt, updatedAt, etc.\n const pathLower = path.toLowerCase()\n if (\n pathLower.endsWith('id') ||\n pathLower.endsWith('_id') ||\n pathLower.includes('createdat') ||\n pathLower.includes('updatedat')\n ) {\n return true\n }\n\n return false\n }\n\n /**\n * Legacy translation method (sends entire structure)\n */\n private async translateWithOpenAILegacy(\n data: any,\n fromLocale: string,\n toLocale: string,\n payload: Payload,\n ): Promise<any> {\n const client = this.getOpenAIClient()\n const timeout = this.config.provider?.timeout || 30000\n\n try {\n // Get translation settings from global\n const settings = await this.getTranslationSettings(payload)\n\n // Build system message from settings\n const systemPrompt = settings.systemPrompt\n .replace('{fromLocale}', fromLocale)\n .replace('{toLocale}', toLocale)\n\n const systemMessage = `${systemPrompt}\\n\\n${settings.translationRules}`\n\n const requestParams = {\n messages: [\n {\n content: systemMessage,\n role: 'system' as const,\n },\n {\n content: JSON.stringify(data, null, 2),\n role: 'user' as const,\n },\n ],\n model: settings.model,\n response_format: { type: 'json_object' as const },\n ...(supportsCustomTemperature(settings.model)\n ? { temperature: settings.temperature }\n : {}),\n ...(settings.maxTokens ? { max_tokens: settings.maxTokens } : {}),\n }\n\n const response = await client.chat.completions.create(requestParams, { timeout })\n\n const translatedText = response.choices[0]?.message?.content\n\n if (!translatedText) {\n throw new Error('No translation received from OpenAI')\n }\n\n return JSON.parse(translatedText)\n } catch (error) {\n console.error('[Auto-Translate] Translation error:', error)\n throw error\n }\n }\n\n /**\n * Gets global and collection-specific excluded fields\n */\n getConfigExcludedFields(collection: string): string[] {\n const globalExclusions = this.config.excludeFields || []\n const collectionConfig = this.config.collections?.[collection as CollectionSlug]\n\n if (typeof collectionConfig === 'object' && collectionConfig.excludeFields) {\n return [...globalExclusions, ...collectionConfig.excludeFields]\n }\n\n return globalExclusions\n }\n\n /**\n * Gets translation exclusions for a document\n */\n async getExclusions(\n payload: Payload,\n collection: string,\n documentId: string,\n locale: string,\n ): Promise<string[]> {\n const exclusionsSlug = (this.config.translationExclusionsSlug ||\n 'translation-exclusions') as CollectionSlug\n\n try {\n const result = await payload.find({\n collection: exclusionsSlug,\n limit: 1,\n where: {\n and: [\n { collectionSlug: { equals: collection } },\n { documentId: { equals: documentId } },\n { locale: { equals: locale } },\n ],\n },\n })\n\n if (result.docs.length > 0) {\n const exclusion = result.docs[0] as any\n return exclusion.excludedPaths?.map((item: any) => item.path) || []\n }\n\n return []\n } catch (error) {\n payload.logger.error(`[Auto-Translate] Error fetching exclusions: ${error}`)\n throw error\n }\n }\n\n /**\n * Main translation method\n */\n async translate(options: TranslateOptions): Promise<any> {\n const { collection, data, excludedPaths = [], fromLocale, payload, toLocale } = options\n\n // Filter out excluded paths before translation\n const dataToTranslate = filterExcludedPaths(data, excludedPaths)\n\n if (this.config.debugging) {\n payload.logger.info(\n `[Auto-Translate] Translating from ${fromLocale} to ${toLocale} for collection ${collection}`,\n )\n payload.logger.info(`[Auto-Translate] Excluded paths: ${excludedPaths.join(', ')}`)\n }\n\n // Run the configured translation strategy\n let translated: any\n if (this.config.provider?.customTranslate) {\n // Use custom translator if provided\n translated = await this.config.provider.customTranslate(options)\n } else {\n // Use OpenAI by default\n translated = await this.translateWithOpenAI(dataToTranslate, fromLocale, toLocale, payload)\n }\n\n // Restore canonical values for enum-backed fields (select/radio). The Postgres\n // adapter stores these as native enum columns, so a translated option value\n // (e.g. \"narrow\" -> \"schmal\") is rejected with `invalid input value for enum`.\n //\n // When `translateLocalizedFieldsOnly` is enabled, also restore every field that\n // is not localized (directly or via a localized ancestor container) so only\n // localized fields are translated.\n const fields = this.getDocumentFields(payload, collection)\n if (fields) {\n overlayNonTranslatableValues(translated, data, fields, {\n localizedOnly: this.config.translateLocalizedFieldsOnly === true,\n })\n }\n\n return translated\n }\n\n /**\n * Resolves the field schema for a collection or global slug so translation can\n * be made schema-aware (e.g. to avoid translating enum-backed select/radio\n * field values).\n */\n private getDocumentFields(payload: Payload, slug: string): Field[] | undefined {\n const collectionConfig = (payload as any).collections?.[slug]?.config\n if (collectionConfig && Array.isArray(collectionConfig.fields)) {\n return collectionConfig.fields\n }\n\n const globalConfig = (payload.config as any)?.globals?.find((g: any) => g.slug === slug)\n if (globalConfig && Array.isArray(globalConfig.fields)) {\n return globalConfig.fields\n }\n\n return undefined\n }\n\n /**\n * Translates using OpenAI API (optimized version)\n * This method is now public and can be used directly in your application\n */\n async translateWithOpenAI(\n data: any,\n fromLocale: string,\n toLocale: string,\n payload: Payload,\n ): Promise<any> {\n const client = this.getOpenAIClient()\n\n // Use optimization by default (can be disabled via config)\n const useOptimization = this.config.optimizeTranslation !== false\n\n if (!useOptimization) {\n // Use legacy approach: send entire structure\n return this.translateWithOpenAILegacy(data, fromLocale, toLocale, payload)\n }\n\n // Extract only translatable strings with deduplication\n const { deduplicationMap, metadata, strings } = this.extractTranslatableStrings(data)\n\n if (strings.size === 0) {\n // Nothing to translate\n return data\n }\n\n // Create a simple object with just the strings to translate\n const stringsToTranslate: Record<string, string> = {}\n strings.forEach((value, key) => {\n stringsToTranslate[key] = value\n })\n\n if (this.config.debugging) {\n const originalSize = JSON.stringify(data).length\n const optimizedSize = JSON.stringify(stringsToTranslate).length\n const reduction = ((1 - optimizedSize / originalSize) * 100).toFixed(1)\n\n // Calculate deduplication stats\n let totalPaths = 0\n deduplicationMap.forEach((paths) => {\n totalPaths += paths.length\n })\n const deduplicationSavings = totalPaths - strings.size\n const deduplicationPercent =\n totalPaths > 0 ? ((deduplicationSavings / totalPaths) * 100).toFixed(1) : '0'\n\n console.log('[Auto-Translate] ✨ Optimization Stats:')\n console.log(` 📊 Unique strings to translate: ${strings.size}`)\n console.log(` 🔄 Total string instances: ${totalPaths}`)\n console.log(\n ` 💾 Deduplication savings: ${deduplicationSavings} strings (${deduplicationPercent}%)`,\n )\n console.log(` 📦 Original JSON size: ${originalSize.toLocaleString()} bytes`)\n console.log(` 📦 Optimized JSON size: ${optimizedSize.toLocaleString()} bytes`)\n console.log(` 🎯 Total size reduction: ${reduction}%`)\n }\n\n try {\n // Get translation settings from global\n const settings = await this.getTranslationSettings(payload)\n\n // Add timeout configuration (default 30 seconds, configurable via plugin options)\n const timeout = this.config.provider?.timeout || 30000\n\n if (this.config.debugging) {\n console.log(\n `[Auto-Translate] Calling OpenAI API (timeout: ${timeout}ms, model: ${settings.model})`,\n )\n console.log(\n `[Auto-Translate] Payload size: ${JSON.stringify(stringsToTranslate).length} bytes`,\n )\n }\n\n // Build system message from settings\n const systemPrompt = settings.systemPrompt\n .replace('{fromLocale}', fromLocale)\n .replace('{toLocale}', toLocale)\n\n const systemMessage = `${systemPrompt}\\n\\n${settings.translationRules}`\n\n const requestParams = {\n messages: [\n {\n content: systemMessage,\n role: 'system' as const,\n },\n {\n content: JSON.stringify(stringsToTranslate, null, 2),\n role: 'user' as const,\n },\n ],\n model: settings.model,\n response_format: { type: 'json_object' as const },\n ...(supportsCustomTemperature(settings.model)\n ? { temperature: settings.temperature }\n : {}),\n ...(settings.maxTokens ? { max_tokens: settings.maxTokens } : {}),\n }\n\n const response = await client.chat.completions.create(requestParams, { timeout })\n\n const translatedText = response.choices[0]?.message?.content\n\n if (!translatedText) {\n throw new Error('No translation received from OpenAI')\n }\n\n if (this.config.debugging) {\n console.log(\n `[Auto-Translate] Received response from OpenAI (${translatedText.length} chars)`,\n )\n }\n\n let translatedStrings: any\n try {\n translatedStrings = JSON.parse(translatedText)\n } catch (parseError) {\n console.error('[Auto-Translate] Failed to parse OpenAI response as JSON')\n console.error('[Auto-Translate] Response text:', translatedText.substring(0, 500))\n throw new Error(\n `Invalid JSON response from OpenAI: ${parseError instanceof Error ? parseError.message : String(parseError)}`,\n )\n }\n\n // Convert back to Map\n const translationsMap = new Map<string, string>()\n for (const [key, value] of Object.entries(translatedStrings)) {\n if (typeof value === 'string') {\n translationsMap.set(key, value)\n }\n }\n\n // Reconstruct the full data structure with translations, applying deduplication\n return this.reconstructWithTranslations(metadata, translationsMap, deduplicationMap)\n } catch (error) {\n console.error('[Auto-Translate] Translation error:', error)\n\n // Provide more context about the error\n if (error && typeof error === 'object') {\n const err = error as any\n if (err.status) {\n console.error(`[Auto-Translate] OpenAI API status: ${err.status}`)\n }\n if (err.code) {\n console.error(`[Auto-Translate] Error code: ${err.code}`)\n }\n if (err.message) {\n console.error(`[Auto-Translate] Error message: ${err.message}`)\n }\n }\n\n // Add context to the error before re-throwing\n const contextualError = new Error(\n `Translation failed from ${fromLocale} to ${toLocale}: ${error instanceof Error ? error.message : String(error)}`,\n )\n contextualError.cause = error\n throw contextualError\n }\n }\n\n /**\n * Updates translation exclusions for a document\n */\n async updateExclusions(\n payload: Payload,\n collection: string,\n documentId: string,\n locale: string,\n excludedPaths: string[],\n ): Promise<void> {\n const exclusionsSlug = (this.config.translationExclusionsSlug ||\n 'translation-exclusions') as CollectionSlug\n\n try {\n const existing = await payload.find({\n collection: exclusionsSlug,\n limit: 1,\n where: {\n and: [\n { collectionSlug: { equals: collection } },\n { documentId: { equals: documentId } },\n { locale: { equals: locale } },\n ],\n },\n })\n\n const exclusionsData = {\n collectionSlug: collection,\n documentId,\n excludedPaths: excludedPaths.map((path) => ({ path })),\n locale,\n }\n\n if (existing.docs.length > 0) {\n await payload.update({\n id: existing.docs[0].id,\n collection: exclusionsSlug,\n data: exclusionsData,\n })\n } else {\n await payload.create({\n collection: exclusionsSlug,\n data: exclusionsData,\n })\n }\n\n if (this.config.debugging) {\n payload.logger.info(\n `[Auto-Translate] Updated exclusions for ${collection}:${documentId}:${locale}`,\n )\n }\n } catch (error) {\n payload.logger.error(`[Auto-Translate] Error updating exclusions: ${error}`)\n throw error\n }\n }\n}\n"],"names":["OpenAI","supportsCustomTemperature","filterExcludedPaths","overlayNonTranslatableValues","TranslationService","client","config","extractFromLexicalNode","node","path","strings","deduplicationMap","enableDeduplication","type","text","trimmed","trim","length","shouldSkipString","textPath","has","existingPaths","get","push","set","children","Array","isArray","map","child","index","extractTranslatableStrings","data","Map","extract","obj","currentPath","undefined","isLexicalEditorNode","item","result","key","value","Object","entries","newPath","trimmedValue","metadata","getOpenAIClient","apiKey","provider","process","env","OPENAI_API_KEY","Error","baseURL","OPENAI_BASE_URL","getOriginalValue","parts","split","filter","Boolean","current","part","getTranslationSettings","payload","settingsSlug","translationSettingsSlug","defaults","maxTokens","model","systemPrompt","temperature","translationRules","settings","findGlobal","slug","error","debugging","console","warn","reconstructWithTranslations","translations","fullTranslations","forEach","translatedValue","originalPath","originalValue","replace","paths","includes","reconstruct","startsWith","slice","str","test","minLength","minStringLength","toLowerCase","pathLower","endsWith","translateWithOpenAILegacy","fromLocale","toLocale","timeout","systemMessage","requestParams","messages","content","role","JSON","stringify","response_format","max_tokens","response","chat","completions","create","translatedText","choices","message","parse","getConfigExcludedFields","collection","globalExclusions","excludeFields","collectionConfig","collections","getExclusions","documentId","locale","exclusionsSlug","translationExclusionsSlug","find","limit","where","and","collectionSlug","equals","docs","exclusion","excludedPaths","logger","translate","options","dataToTranslate","info","join","translated","customTranslate","translateWithOpenAI","fields","getDocumentFields","localizedOnly","translateLocalizedFieldsOnly","globalConfig","globals","g","useOptimization","optimizeTranslation","size","stringsToTranslate","originalSize","optimizedSize","reduction","toFixed","totalPaths","deduplicationSavings","deduplicationPercent","log","toLocaleString","translatedStrings","parseError","substring","String","translationsMap","err","status","code","contextualError","cause","updateExclusions","existing","exclusionsData","update","id"],"mappings":"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"}
@@ -1,5 +1,4 @@
1
1
  import type { Field } from 'payload';
2
- import type { FieldPath } from '../types/index.js';
3
2
  export type OverlayOptions = {
4
3
  /**
5
4
  * Localization inherited from an ancestor container (`group`/`array`/`blocks`/
@@ -26,35 +25,7 @@ export type OverlayOptions = {
26
25
  * (optimized, legacy, or a custom translator).
27
26
  */
28
27
  export declare function overlayNonTranslatableValues(translated: any, original: any, fields: Field[] | undefined, options?: OverlayOptions): void;
29
- /**
30
- * Recursively extracts all field paths and their values from a document
31
- */
32
- export declare function extractFieldPaths(data: any, parentPath?: string, fields?: Field[]): FieldPath[];
33
28
  /**
34
29
  * Filters out excluded paths from data before translation
35
30
  */
36
31
  export declare function filterExcludedPaths(data: any, excludedPaths: string[]): any;
37
- /**
38
- * Merges translated data back, respecting excluded paths
39
- */
40
- export declare function mergeTranslatedData(originalData: any, translatedData: any, excludedPaths: string[]): any;
41
- /**
42
- * Checks if a path is excluded or if any parent path is excluded
43
- */
44
- export declare function isPathExcluded(path: string, excludedPaths: string[]): boolean;
45
- /**
46
- * Gets value at path using dot notation
47
- */
48
- export declare function getValueAtPath(obj: any, path: string): any;
49
- /**
50
- * Sets value at path using dot notation
51
- */
52
- export declare function setValueAtPath(obj: any, path: string, value: any): void;
53
- /**
54
- * Checks if a field is a localized field
55
- */
56
- export declare function isLocalizedField(field: Field): boolean;
57
- /**
58
- * Gets all localized field paths from a collection config
59
- */
60
- export declare function getLocalizedFieldPaths(fields: Field[], parentPath?: string): string[];