@roxxel/payload-multilang 0.0.7 → 0.0.8

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.
@@ -150,7 +150,10 @@ const getBlockFieldsForRow = (field, sourceRow)=>{
150
150
  return field.blocks?.find((block)=>block.slug === blockType)?.fields || [];
151
151
  };
152
152
  const createSynchronizedRow = (sourceRow, previousRow, targetRow, field)=>{
153
- const row = targetRow ? {
153
+ const sourceBlockType = field.kind === 'blocks' ? getStringValue(sourceRow.blockType) : undefined;
154
+ const previousBlockType = field.kind === 'blocks' && previousRow ? getStringValue(previousRow.blockType) : undefined;
155
+ const blockTypeChanged = field.kind === 'blocks' && field.synchronizePosition && previousRow !== undefined && sourceBlockType !== previousBlockType;
156
+ const row = targetRow && !blockTypeChanged ? {
154
157
  ...targetRow
155
158
  } : {};
156
159
  if (field.kind === 'blocks') {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/hooks/translatedCollection.ts"],"sourcesContent":["import type {\n CollectionAfterChangeHook,\n CollectionBeforeChangeHook,\n CollectionConfig,\n Field,\n Where,\n} from 'payload'\n\nimport { randomUUID } from 'crypto'\n\nimport type { ResolvedMultilangCollection } from '../types.js'\n\nimport { MULTILANG_SKIP_HOOK } from '../constants.js'\nimport { asDocument, getID, getStringValue } from '../lib/data.js'\n\nconst LANGUAGE_LABEL = {\n en: 'Language',\n uk: 'Мова',\n}\n\nconst TRANSLATIONS_LABEL = {\n en: 'Translations',\n uk: 'Переклади',\n}\n\ntype FieldAffectingData = { name: string } & Field\ntype SynchronizedBlock = {\n fields: SynchronizedField[]\n slug: string\n}\ntype SynchronizedField =\n | {\n blocks: SynchronizedBlock[]\n kind: 'blocks'\n name: string\n synchronizePosition: boolean\n }\n | {\n fields: SynchronizedField[]\n kind: 'array'\n name: string\n synchronizePosition: boolean\n }\n | {\n fields: SynchronizedField[]\n kind: 'group'\n name: string\n }\n | {\n kind: 'value'\n name: string\n }\ntype SynchronizedContainerField = Extract<SynchronizedField, { kind: 'array' | 'blocks' }>\n\nconst hasSkipContext = (context?: Record<string, unknown>): boolean =>\n context?.[MULTILANG_SKIP_HOOK] === true\n\nconst isObject = (value: unknown): value is Record<string, unknown> =>\n typeof value === 'object' && value !== null && !Array.isArray(value)\n\nconst toArray = (value: unknown): Record<string, unknown>[] =>\n Array.isArray(value) ? value.filter(isObject) : []\n\nconst valuesAreEqual = (left: unknown, right: unknown): boolean => {\n if (left === right) {\n return true\n }\n\n return JSON.stringify(left) === JSON.stringify(right)\n}\n\nconst fieldAffectsData = (field: Field): field is FieldAffectingData =>\n 'name' in field && typeof field.name === 'string' && field.name !== 'id' && field.type !== 'ui'\n\nconst fieldSynchronizes = (field: Field): boolean => {\n const custom = isObject(field.custom) ? field.custom : {}\n const multilang = isObject(custom.multilang) ? custom.multilang : {}\n\n return multilang.synchronize === true\n}\n\nconst fieldSynchronizesPosition = (field: Field): boolean => {\n const custom = isObject(field.custom) ? field.custom : {}\n const multilang = isObject(custom.multilang) ? custom.multilang : {}\n\n return multilang.synchronizePosition === true\n}\n\nconst hasName = (value: unknown): value is { name: string } =>\n isObject(value) && typeof value.name === 'string'\n\nconst getSynchronizedBlocks = (\n field: Field,\n inheritedSynchronize: boolean,\n): SynchronizedBlock[] => {\n if (field.type !== 'blocks') {\n return []\n }\n\n return field.blocks.flatMap((block) => {\n const fields = getSynchronizedFields(block.fields, inheritedSynchronize)\n\n if (fields.length === 0) {\n return []\n }\n\n return [\n {\n slug: block.slug,\n fields,\n },\n ]\n })\n}\n\nconst getSynchronizedTabFields = (\n field: Extract<Field, { type: 'tabs' }>,\n inheritedSynchronize: boolean,\n): SynchronizedField[] =>\n field.tabs.flatMap<SynchronizedField>((tab) => {\n const fields = getSynchronizedFields(tab.fields, inheritedSynchronize)\n\n if (fields.length === 0) {\n return []\n }\n\n if (hasName(tab)) {\n return [\n {\n name: tab.name,\n fields,\n kind: 'group',\n },\n ]\n }\n\n return fields\n })\n\nconst getSynchronizedFields = (\n fields: Field[] = [],\n inheritedSynchronize = false,\n): SynchronizedField[] =>\n fields.flatMap<SynchronizedField>((field) => {\n if (field.type === 'row' || field.type === 'collapsible') {\n return getSynchronizedFields(\n field.fields,\n inheritedSynchronize || fieldSynchronizes(field),\n )\n }\n\n if (field.type === 'tabs') {\n return getSynchronizedTabFields(field, inheritedSynchronize)\n }\n\n if (!fieldAffectsData(field)) {\n return []\n }\n\n const synchronize = inheritedSynchronize || fieldSynchronizes(field)\n\n if (field.type === 'array') {\n const fields = getSynchronizedFields(field.fields, synchronize)\n const synchronizePosition = synchronize || fieldSynchronizesPosition(field)\n\n if (!synchronizePosition && fields.length === 0) {\n return []\n }\n\n return [\n {\n name: field.name,\n fields,\n kind: 'array',\n synchronizePosition,\n },\n ]\n }\n\n if (field.type === 'blocks') {\n const blocks = getSynchronizedBlocks(field, synchronize)\n const synchronizePosition = synchronize || fieldSynchronizesPosition(field)\n\n if (!synchronizePosition && blocks.length === 0) {\n return []\n }\n\n return [\n {\n name: field.name,\n blocks,\n kind: 'blocks',\n synchronizePosition,\n },\n ]\n }\n\n if (field.type === 'group') {\n const fields = getSynchronizedFields(field.fields, synchronize)\n\n if (fields.length === 0) {\n return []\n }\n\n return [\n {\n name: field.name,\n fields,\n kind: 'group',\n },\n ]\n }\n\n if (!synchronize) {\n return []\n }\n\n return [\n {\n name: field.name,\n kind: 'value',\n },\n ]\n })\n\nconst getRowKey = (row: Record<string, unknown>, index: number): string => {\n const id = getID(row.id)\n\n return id === undefined ? `index:${index}` : `id:${String(id)}`\n}\n\nconst getShellSignature = (value: unknown, field: SynchronizedField): string =>\n JSON.stringify(\n toArray(value).map((row, index) => ({\n blockName: field.kind === 'blocks' ? getStringValue(row.blockName) : undefined,\n blockType: field.kind === 'blocks' ? getStringValue(row.blockType) : undefined,\n key: getRowKey(row, index),\n })),\n )\n\nconst positionChanged = (\n field: SynchronizedField,\n source: Record<string, unknown>,\n previous: Record<string, unknown>,\n): boolean => {\n if (\n (field.kind !== 'array' && field.kind !== 'blocks') ||\n !field.synchronizePosition ||\n !(field.name in source)\n ) {\n return false\n }\n\n return (\n getShellSignature(source[field.name], field) !==\n getShellSignature(previous[field.name], field)\n )\n}\n\nconst getBlockFieldsForRow = (\n field: SynchronizedField,\n sourceRow: Record<string, unknown>,\n): SynchronizedField[] => {\n if (field.kind !== 'blocks') {\n return []\n }\n\n const blockType = getStringValue(sourceRow.blockType)\n\n return field.blocks?.find((block) => block.slug === blockType)?.fields || []\n}\n\nconst createSynchronizedRow = (\n sourceRow: Record<string, unknown>,\n previousRow: Record<string, unknown> | undefined,\n targetRow: Record<string, unknown> | undefined,\n field: SynchronizedContainerField,\n): Record<string, unknown> => {\n const row = targetRow ? { ...targetRow } : {}\n\n if (field.kind === 'blocks') {\n row.id = randomUUID()\n }\n\n if (field.synchronizePosition && field.kind === 'blocks' && 'blockType' in sourceRow) {\n row.blockType = sourceRow.blockType\n }\n\n if (field.synchronizePosition && field.kind === 'blocks') {\n if ('blockName' in sourceRow) {\n row.blockName = sourceRow.blockName\n } else {\n delete row.blockName\n }\n }\n\n const fields =\n field.kind === 'array' ? field.fields : getBlockFieldsForRow(field, sourceRow)\n\n return synchronizeData({\n fields,\n previous: previousRow || {},\n source: sourceRow,\n target: row,\n })\n}\n\nconst synchronizeContainerValue = ({\n field,\n previousSourceValue,\n sourceValue,\n targetValue,\n}: {\n field: SynchronizedContainerField\n previousSourceValue: unknown\n sourceValue: unknown\n targetValue: unknown\n}): unknown[] => {\n const targetRows = toArray(targetValue)\n const previousSourceRows = toArray(previousSourceValue)\n const sourceRows = toArray(sourceValue)\n\n if (!field.synchronizePosition) {\n const sourceRowsByPreviousKey = new Map(\n sourceRows.map((row, index) => {\n const previousRow = previousSourceRows[index]\n const key = previousRow ? getRowKey(previousRow, index) : getRowKey(row, index)\n\n return [key, row] as const\n }),\n )\n\n return targetRows.map((targetRow, index) => {\n const previousRow = previousSourceRows[index]\n const sourceRow =\n (previousRow && sourceRowsByPreviousKey.get(getRowKey(previousRow, index))) ||\n sourceRows[index]\n\n return sourceRow\n ? createSynchronizedRow(sourceRow, previousRow, targetRow, field)\n : { ...targetRow }\n })\n }\n\n const previousSourceIndexesByKey = new Map(\n previousSourceRows.map((row, index) => [getRowKey(row, index), index] as const),\n )\n\n return sourceRows.map((sourceRow, index) => {\n const previousIndex = previousSourceIndexesByKey.get(getRowKey(sourceRow, index))\n\n return createSynchronizedRow(\n sourceRow,\n previousIndex === undefined ? undefined : previousSourceRows[previousIndex],\n previousIndex === undefined ? undefined : targetRows[previousIndex],\n field,\n )\n })\n}\n\nconst descriptorChanged = ({\n field,\n previous,\n source,\n}: {\n field: SynchronizedField\n previous: Record<string, unknown>\n source: Record<string, unknown>\n}): boolean => {\n if (field.kind === 'value') {\n return !valuesAreEqual(source[field.name], previous[field.name])\n }\n\n if (field.kind === 'group') {\n return descriptorsChanged({\n fields: field.fields,\n previous: asDocument(previous[field.name]),\n source: asDocument(source[field.name]),\n })\n }\n\n if (!(field.name in source)) {\n return false\n }\n\n if (positionChanged(field, source, previous)) {\n return true\n }\n\n const previousRows = toArray(previous[field.name])\n const previousRowsByKey = new Map(\n previousRows.map((row, index) => [getRowKey(row, index), row] as const),\n )\n\n return toArray(source[field.name]).some((sourceRow, index) => {\n const previousRow = previousRowsByKey.get(getRowKey(sourceRow, index)) || previousRows[index]\n const fields =\n field.kind === 'array' ? field.fields : getBlockFieldsForRow(field, sourceRow)\n\n return descriptorsChanged({\n fields,\n previous: previousRow || {},\n source: sourceRow,\n })\n })\n}\n\nconst descriptorsChanged = ({\n fields,\n previous,\n source,\n}: {\n fields: SynchronizedField[]\n previous: Record<string, unknown>\n source: Record<string, unknown>\n}): boolean =>\n fields.some((field) =>\n descriptorChanged({\n field,\n previous,\n source,\n }),\n )\n\nconst synchronizeData = ({\n fields,\n previous,\n source,\n target,\n}: {\n fields: SynchronizedField[]\n previous: Record<string, unknown>\n source: Record<string, unknown>\n target: Record<string, unknown>\n}): Record<string, unknown> =>\n fields.reduce<Record<string, unknown>>((acc, field) => {\n if (field.kind === 'value') {\n if (field.name in source) {\n acc[field.name] = source[field.name]\n } else {\n delete acc[field.name]\n }\n\n return acc\n }\n\n if (field.kind === 'group') {\n if (field.name in source) {\n const value = synchronizeData({\n fields: field.fields,\n previous: asDocument(previous[field.name]),\n source: asDocument(source[field.name]),\n target: asDocument(acc[field.name]),\n })\n\n if (!valuesAreEqual(value, acc[field.name])) {\n acc[field.name] = value\n }\n } else {\n delete acc[field.name]\n }\n\n return acc\n }\n\n const value = synchronizeContainerValue({\n field,\n previousSourceValue: previous[field.name],\n sourceValue: source[field.name],\n targetValue: target[field.name],\n })\n\n if (!valuesAreEqual(value, target[field.name])) {\n acc[field.name] = value\n }\n\n return acc\n }, { ...target })\n\nconst getSynchronizedDataForTranslation = ({\n fields,\n nextDoc,\n previous,\n translation,\n}: {\n fields: SynchronizedField[]\n nextDoc: Record<string, unknown>\n previous: Record<string, unknown>\n translation: Record<string, unknown>\n}): Record<string, unknown> => {\n const synchronized = synchronizeData({\n fields,\n previous,\n source: nextDoc,\n target: translation,\n })\n\n return fields.reduce<Record<string, unknown>>((acc, field) => {\n if (!valuesAreEqual(synchronized[field.name], translation[field.name])) {\n acc[field.name] = synchronized[field.name]\n }\n\n return acc\n }, {})\n}\n\nconst isConfiguredLanguage = (\n collection: ResolvedMultilangCollection,\n language: string | undefined,\n): boolean =>\n Boolean(\n language &&\n collection.languages.some((configuredLanguage) => configuredLanguage.code === language),\n )\n\ntype CollectionEditViews = NonNullable<\n NonNullable<NonNullable<CollectionConfig['admin']>['components']>['views']\n>['edit']\n\nconst getDuplicateLanguageIDs = async ({\n collection,\n excludeID,\n group,\n language,\n req,\n}: {\n collection: ResolvedMultilangCollection\n excludeID?: number | string\n group: string\n language: string\n req: Parameters<CollectionBeforeChangeHook>[0]['req']\n}): Promise<Array<number | string>> => {\n const and: Where[] = [\n {\n [collection.fieldNames.group]: {\n equals: group,\n },\n },\n {\n [collection.fieldNames.language]: {\n equals: language,\n },\n },\n ]\n\n if (excludeID) {\n and.push({\n id: {\n not_equals: excludeID,\n },\n })\n }\n\n const result = await req.payload.find({\n collection: collection.slug,\n depth: 0,\n limit: 200,\n overrideAccess: true,\n req,\n where: {\n and,\n },\n })\n\n return result.docs\n .map((doc) => getID(asDocument(doc).id))\n .filter((id): id is number | string => id !== undefined)\n}\n\nexport const createTranslatedCollectionBeforeChangeHook =\n ({ collection }: { collection: ResolvedMultilangCollection }): CollectionBeforeChangeHook =>\n async ({ context, data, operation, originalDoc, req }) => {\n if (hasSkipContext(context)) {\n return data\n }\n\n const nextData = asDocument(data)\n const original = asDocument(originalDoc)\n const { group: groupField, language: languageField } = collection.fieldNames\n const originalLanguage = getStringValue(original[languageField])\n const originalLanguageIsConfigured = isConfiguredLanguage(collection, originalLanguage)\n const incomingLanguage = getStringValue(nextData[languageField])\n\n if (operation === 'update' && originalLanguage && !originalLanguageIsConfigured) {\n if (\n !incomingLanguage ||\n incomingLanguage === originalLanguage ||\n !isConfiguredLanguage(collection, incomingLanguage)\n ) {\n nextData[languageField] = ''\n }\n } else if (!incomingLanguage) {\n nextData[languageField] =\n operation === 'create'\n ? collection.defaultLanguage.code\n : originalLanguageIsConfigured\n ? originalLanguage\n : ''\n }\n\n const language = getStringValue(nextData[languageField])\n\n if (\n operation === 'update' &&\n originalLanguage &&\n originalLanguageIsConfigured &&\n language !== originalLanguage\n ) {\n throw new Error('Document language cannot be changed after creation.')\n }\n\n if (language && !isConfiguredLanguage(collection, language)) {\n throw new Error(`Language \"${language}\" is not configured for ${collection.slug}.`)\n }\n\n if (!getStringValue(nextData[groupField])) {\n const fallbackGroup = getStringValue(original[groupField])\n nextData[groupField] = fallbackGroup || randomUUID()\n }\n\n const group = getStringValue(nextData[groupField])\n\n if (language && group) {\n const currentID = operation === 'update' ? getID(original.id) : undefined\n const duplicateIDs = await getDuplicateLanguageIDs({\n collection,\n excludeID: currentID,\n group,\n language,\n req,\n })\n\n if (duplicateIDs.length > 0) {\n throw new Error(\n `A ${collection.slug} translation already exists for language \"${language}\" in this translation group.`,\n )\n }\n }\n\n return nextData\n }\n\nexport const createSynchronizedFieldsAfterChangeHook =\n ({\n collection,\n fields,\n }: {\n collection: ResolvedMultilangCollection\n fields?: Field[]\n }): CollectionAfterChangeHook =>\n async ({ context, doc, operation, previousDoc, req }) => {\n const synchronizedFields = getSynchronizedFields(fields)\n\n if (hasSkipContext(context) || operation !== 'update' || synchronizedFields.length === 0) {\n return doc\n }\n\n const nextDoc = asDocument(doc)\n const previous = asDocument(previousDoc)\n const group = getStringValue(nextDoc[collection.fieldNames.group])\n const currentID = getID(nextDoc.id)\n\n if (!group || !currentID) {\n return doc\n }\n\n const changedFields = synchronizedFields.filter((field) =>\n descriptorChanged({\n field,\n previous,\n source: nextDoc,\n }),\n )\n\n if (changedFields.length === 0) {\n return doc\n }\n\n const translations = await req.payload.find({\n collection: collection.slug,\n depth: 0,\n limit: 200,\n overrideAccess: true,\n req,\n where: {\n and: [\n {\n [collection.fieldNames.group]: {\n equals: group,\n },\n },\n {\n id: {\n not_equals: currentID,\n },\n },\n ],\n },\n })\n\n await Promise.all(\n translations.docs\n .map((translation) => {\n const translationDoc = asDocument(translation)\n const id = getID(translationDoc.id)\n\n if (id === undefined) {\n return undefined\n }\n\n const synchronizedData = getSynchronizedDataForTranslation({\n fields: changedFields,\n nextDoc,\n previous,\n translation: translationDoc,\n })\n\n if (Object.keys(synchronizedData).length === 0) {\n return undefined\n }\n\n return {\n id,\n data: synchronizedData,\n }\n })\n .filter(\n (update): update is { data: Record<string, unknown>; id: number | string } =>\n update !== undefined,\n )\n .map(({ id, data }) =>\n req.payload.update({\n id,\n collection: collection.slug,\n context: {\n [MULTILANG_SKIP_HOOK]: true,\n },\n data,\n overrideAccess: true,\n req,\n }),\n ),\n )\n\n return doc\n }\n\nexport const createHiddenFields = ({\n collection,\n}: {\n collection: ResolvedMultilangCollection\n}): Field[] => [\n {\n name: collection.fieldNames.language,\n type: 'text',\n admin: {\n disableListColumn: true,\n hidden: true,\n },\n index: true,\n label: LANGUAGE_LABEL,\n },\n {\n name: collection.fieldNames.group,\n type: 'text',\n admin: {\n disableListColumn: true,\n hidden: true,\n },\n index: true,\n label: TRANSLATIONS_LABEL,\n },\n {\n name: collection.fieldNames.meta,\n type: 'json',\n admin: {\n disableListColumn: true,\n hidden: true,\n },\n },\n {\n name: 'multilangLanguageMetabox',\n type: 'ui',\n admin: {\n components: {\n Field: '@roxxel/payload-multilang/client#LanguageMetabox',\n },\n position: 'sidebar',\n },\n },\n]\n\nexport const getLanguageColumnName = (): string => 'payloadMultilangTranslations'\n\nexport const createLanguageColumnFields = ({\n collection,\n}: {\n collection: ResolvedMultilangCollection\n}): Field[] => {\n const label = collection.languages\n .map((language) => language.flagLabel || language.code.toUpperCase())\n .join(' ')\n\n return [\n {\n name: getLanguageColumnName(),\n type: 'ui',\n admin: {\n components: {\n Cell: '@roxxel/payload-multilang/rsc#TranslationColumnCell',\n },\n disableListColumn: false,\n width: '132px',\n },\n label: label || TRANSLATIONS_LABEL,\n },\n ]\n}\n\nexport const translatedCollectionMeta = ({\n collection,\n}: {\n collection: ResolvedMultilangCollection\n}) => ({\n defaultLanguage: collection.defaultLanguage,\n fieldNames: collection.fieldNames,\n languages: collection.languages,\n})\n\nconst getDefaultColumns = ({\n collection,\n existingDefaultColumns,\n languageColumnName,\n}: {\n collection: ResolvedMultilangCollection\n existingDefaultColumns: string[]\n languageColumnName: string\n}): string[] => {\n const hiddenMultilangColumns = new Set([\n collection.fieldNames.group,\n collection.fieldNames.language,\n collection.fieldNames.meta,\n languageColumnName,\n ])\n const visibleExistingColumns = existingDefaultColumns.filter(\n (column) => !hiddenMultilangColumns.has(column),\n )\n\n return [...visibleExistingColumns, languageColumnName]\n}\n\nexport const withTranslatedCollection = ({\n collection,\n config,\n}: {\n collection: ResolvedMultilangCollection\n config: CollectionConfig\n}): CollectionConfig => {\n const existingDefaultColumns = config.admin?.defaultColumns || []\n const languageColumnName = getLanguageColumnName()\n const existingEditViews =\n (config.admin?.components?.views?.edit as Record<string, unknown> | undefined) || {}\n const defaultColumns = getDefaultColumns({\n collection,\n existingDefaultColumns,\n languageColumnName,\n })\n\n return {\n ...config,\n admin: {\n ...config.admin,\n components: {\n ...config.admin?.components,\n beforeList: [\n ...(config.admin?.components?.beforeList || []),\n '@roxxel/payload-multilang/client#LanguageListToolbar',\n ],\n beforeListTable: config.admin?.components?.beforeListTable,\n views: {\n ...config.admin?.components?.views,\n edit: {\n ...existingEditViews,\n translations: {\n Component: '@roxxel/payload-multilang/rsc#TranslationsTab',\n path: '/translations',\n tab: {\n label: ({ t }) => t('payloadMultilang:translations'),\n order: 80,\n },\n },\n } as CollectionEditViews,\n },\n },\n custom: {\n ...config.admin?.custom,\n payloadMultilang: translatedCollectionMeta({\n collection,\n }),\n },\n defaultColumns,\n },\n endpoints: [...(config.endpoints || [])],\n fields: [\n ...(config.fields || []),\n ...createHiddenFields({ collection }),\n ...createLanguageColumnFields({ collection }),\n ],\n hooks: {\n ...config.hooks,\n afterChange: [\n createSynchronizedFieldsAfterChangeHook({\n collection,\n fields: config.fields,\n }),\n ...(config.hooks?.afterChange || []),\n ],\n beforeChange: [\n createTranslatedCollectionBeforeChangeHook({\n collection,\n }),\n ...(config.hooks?.beforeChange || []),\n ],\n },\n }\n}\n"],"names":["randomUUID","MULTILANG_SKIP_HOOK","asDocument","getID","getStringValue","LANGUAGE_LABEL","en","uk","TRANSLATIONS_LABEL","hasSkipContext","context","isObject","value","Array","isArray","toArray","filter","valuesAreEqual","left","right","JSON","stringify","fieldAffectsData","field","name","type","fieldSynchronizes","custom","multilang","synchronize","fieldSynchronizesPosition","synchronizePosition","hasName","getSynchronizedBlocks","inheritedSynchronize","blocks","flatMap","block","fields","getSynchronizedFields","length","slug","getSynchronizedTabFields","tabs","tab","kind","getRowKey","row","index","id","undefined","String","getShellSignature","map","blockName","blockType","key","positionChanged","source","previous","getBlockFieldsForRow","sourceRow","find","createSynchronizedRow","previousRow","targetRow","synchronizeData","target","synchronizeContainerValue","previousSourceValue","sourceValue","targetValue","targetRows","previousSourceRows","sourceRows","sourceRowsByPreviousKey","Map","get","previousSourceIndexesByKey","previousIndex","descriptorChanged","descriptorsChanged","previousRows","previousRowsByKey","some","reduce","acc","getSynchronizedDataForTranslation","nextDoc","translation","synchronized","isConfiguredLanguage","collection","language","Boolean","languages","configuredLanguage","code","getDuplicateLanguageIDs","excludeID","group","req","and","fieldNames","equals","push","not_equals","result","payload","depth","limit","overrideAccess","where","docs","doc","createTranslatedCollectionBeforeChangeHook","data","operation","originalDoc","nextData","original","groupField","languageField","originalLanguage","originalLanguageIsConfigured","incomingLanguage","defaultLanguage","Error","fallbackGroup","currentID","duplicateIDs","createSynchronizedFieldsAfterChangeHook","previousDoc","synchronizedFields","changedFields","translations","Promise","all","translationDoc","synchronizedData","Object","keys","update","createHiddenFields","admin","disableListColumn","hidden","label","meta","components","Field","position","getLanguageColumnName","createLanguageColumnFields","flagLabel","toUpperCase","join","Cell","width","translatedCollectionMeta","getDefaultColumns","existingDefaultColumns","languageColumnName","hiddenMultilangColumns","Set","visibleExistingColumns","column","has","withTranslatedCollection","config","defaultColumns","existingEditViews","views","edit","beforeList","beforeListTable","Component","path","t","order","payloadMultilang","endpoints","hooks","afterChange","beforeChange"],"mappings":"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"}
1
+ {"version":3,"sources":["../../src/hooks/translatedCollection.ts"],"sourcesContent":["import type {\n CollectionAfterChangeHook,\n CollectionBeforeChangeHook,\n CollectionConfig,\n Field,\n Where,\n} from 'payload'\n\nimport { randomUUID } from 'crypto'\n\nimport type { ResolvedMultilangCollection } from '../types.js'\n\nimport { MULTILANG_SKIP_HOOK } from '../constants.js'\nimport { asDocument, getID, getStringValue } from '../lib/data.js'\n\nconst LANGUAGE_LABEL = {\n en: 'Language',\n uk: 'Мова',\n}\n\nconst TRANSLATIONS_LABEL = {\n en: 'Translations',\n uk: 'Переклади',\n}\n\ntype FieldAffectingData = { name: string } & Field\ntype SynchronizedBlock = {\n fields: SynchronizedField[]\n slug: string\n}\ntype SynchronizedField =\n | {\n blocks: SynchronizedBlock[]\n kind: 'blocks'\n name: string\n synchronizePosition: boolean\n }\n | {\n fields: SynchronizedField[]\n kind: 'array'\n name: string\n synchronizePosition: boolean\n }\n | {\n fields: SynchronizedField[]\n kind: 'group'\n name: string\n }\n | {\n kind: 'value'\n name: string\n }\ntype SynchronizedContainerField = Extract<SynchronizedField, { kind: 'array' | 'blocks' }>\n\nconst hasSkipContext = (context?: Record<string, unknown>): boolean =>\n context?.[MULTILANG_SKIP_HOOK] === true\n\nconst isObject = (value: unknown): value is Record<string, unknown> =>\n typeof value === 'object' && value !== null && !Array.isArray(value)\n\nconst toArray = (value: unknown): Record<string, unknown>[] =>\n Array.isArray(value) ? value.filter(isObject) : []\n\nconst valuesAreEqual = (left: unknown, right: unknown): boolean => {\n if (left === right) {\n return true\n }\n\n return JSON.stringify(left) === JSON.stringify(right)\n}\n\nconst fieldAffectsData = (field: Field): field is FieldAffectingData =>\n 'name' in field && typeof field.name === 'string' && field.name !== 'id' && field.type !== 'ui'\n\nconst fieldSynchronizes = (field: Field): boolean => {\n const custom = isObject(field.custom) ? field.custom : {}\n const multilang = isObject(custom.multilang) ? custom.multilang : {}\n\n return multilang.synchronize === true\n}\n\nconst fieldSynchronizesPosition = (field: Field): boolean => {\n const custom = isObject(field.custom) ? field.custom : {}\n const multilang = isObject(custom.multilang) ? custom.multilang : {}\n\n return multilang.synchronizePosition === true\n}\n\nconst hasName = (value: unknown): value is { name: string } =>\n isObject(value) && typeof value.name === 'string'\n\nconst getSynchronizedBlocks = (\n field: Field,\n inheritedSynchronize: boolean,\n): SynchronizedBlock[] => {\n if (field.type !== 'blocks') {\n return []\n }\n\n return field.blocks.flatMap((block) => {\n const fields = getSynchronizedFields(block.fields, inheritedSynchronize)\n\n if (fields.length === 0) {\n return []\n }\n\n return [\n {\n slug: block.slug,\n fields,\n },\n ]\n })\n}\n\nconst getSynchronizedTabFields = (\n field: Extract<Field, { type: 'tabs' }>,\n inheritedSynchronize: boolean,\n): SynchronizedField[] =>\n field.tabs.flatMap<SynchronizedField>((tab) => {\n const fields = getSynchronizedFields(tab.fields, inheritedSynchronize)\n\n if (fields.length === 0) {\n return []\n }\n\n if (hasName(tab)) {\n return [\n {\n name: tab.name,\n fields,\n kind: 'group',\n },\n ]\n }\n\n return fields\n })\n\nconst getSynchronizedFields = (\n fields: Field[] = [],\n inheritedSynchronize = false,\n): SynchronizedField[] =>\n fields.flatMap<SynchronizedField>((field) => {\n if (field.type === 'row' || field.type === 'collapsible') {\n return getSynchronizedFields(\n field.fields,\n inheritedSynchronize || fieldSynchronizes(field),\n )\n }\n\n if (field.type === 'tabs') {\n return getSynchronizedTabFields(field, inheritedSynchronize)\n }\n\n if (!fieldAffectsData(field)) {\n return []\n }\n\n const synchronize = inheritedSynchronize || fieldSynchronizes(field)\n\n if (field.type === 'array') {\n const fields = getSynchronizedFields(field.fields, synchronize)\n const synchronizePosition = synchronize || fieldSynchronizesPosition(field)\n\n if (!synchronizePosition && fields.length === 0) {\n return []\n }\n\n return [\n {\n name: field.name,\n fields,\n kind: 'array',\n synchronizePosition,\n },\n ]\n }\n\n if (field.type === 'blocks') {\n const blocks = getSynchronizedBlocks(field, synchronize)\n const synchronizePosition = synchronize || fieldSynchronizesPosition(field)\n\n if (!synchronizePosition && blocks.length === 0) {\n return []\n }\n\n return [\n {\n name: field.name,\n blocks,\n kind: 'blocks',\n synchronizePosition,\n },\n ]\n }\n\n if (field.type === 'group') {\n const fields = getSynchronizedFields(field.fields, synchronize)\n\n if (fields.length === 0) {\n return []\n }\n\n return [\n {\n name: field.name,\n fields,\n kind: 'group',\n },\n ]\n }\n\n if (!synchronize) {\n return []\n }\n\n return [\n {\n name: field.name,\n kind: 'value',\n },\n ]\n })\n\nconst getRowKey = (row: Record<string, unknown>, index: number): string => {\n const id = getID(row.id)\n\n return id === undefined ? `index:${index}` : `id:${String(id)}`\n}\n\nconst getShellSignature = (value: unknown, field: SynchronizedField): string =>\n JSON.stringify(\n toArray(value).map((row, index) => ({\n blockName: field.kind === 'blocks' ? getStringValue(row.blockName) : undefined,\n blockType: field.kind === 'blocks' ? getStringValue(row.blockType) : undefined,\n key: getRowKey(row, index),\n })),\n )\n\nconst positionChanged = (\n field: SynchronizedField,\n source: Record<string, unknown>,\n previous: Record<string, unknown>,\n): boolean => {\n if (\n (field.kind !== 'array' && field.kind !== 'blocks') ||\n !field.synchronizePosition ||\n !(field.name in source)\n ) {\n return false\n }\n\n return (\n getShellSignature(source[field.name], field) !==\n getShellSignature(previous[field.name], field)\n )\n}\n\nconst getBlockFieldsForRow = (\n field: SynchronizedField,\n sourceRow: Record<string, unknown>,\n): SynchronizedField[] => {\n if (field.kind !== 'blocks') {\n return []\n }\n\n const blockType = getStringValue(sourceRow.blockType)\n\n return field.blocks?.find((block) => block.slug === blockType)?.fields || []\n}\n\nconst createSynchronizedRow = (\n sourceRow: Record<string, unknown>,\n previousRow: Record<string, unknown> | undefined,\n targetRow: Record<string, unknown> | undefined,\n field: SynchronizedContainerField,\n): Record<string, unknown> => {\n const sourceBlockType = field.kind === 'blocks' ? getStringValue(sourceRow.blockType) : undefined\n const previousBlockType =\n field.kind === 'blocks' && previousRow\n ? getStringValue(previousRow.blockType)\n : undefined\n const blockTypeChanged =\n field.kind === 'blocks' &&\n field.synchronizePosition &&\n previousRow !== undefined &&\n sourceBlockType !== previousBlockType\n const row = targetRow && !blockTypeChanged ? { ...targetRow } : {}\n\n if (field.kind === 'blocks') {\n row.id = randomUUID()\n }\n\n if (field.synchronizePosition && field.kind === 'blocks' && 'blockType' in sourceRow) {\n row.blockType = sourceRow.blockType\n }\n\n if (field.synchronizePosition && field.kind === 'blocks') {\n if ('blockName' in sourceRow) {\n row.blockName = sourceRow.blockName\n } else {\n delete row.blockName\n }\n }\n\n const fields =\n field.kind === 'array' ? field.fields : getBlockFieldsForRow(field, sourceRow)\n\n return synchronizeData({\n fields,\n previous: previousRow || {},\n source: sourceRow,\n target: row,\n })\n}\n\nconst synchronizeContainerValue = ({\n field,\n previousSourceValue,\n sourceValue,\n targetValue,\n}: {\n field: SynchronizedContainerField\n previousSourceValue: unknown\n sourceValue: unknown\n targetValue: unknown\n}): unknown[] => {\n const targetRows = toArray(targetValue)\n const previousSourceRows = toArray(previousSourceValue)\n const sourceRows = toArray(sourceValue)\n\n if (!field.synchronizePosition) {\n const sourceRowsByPreviousKey = new Map(\n sourceRows.map((row, index) => {\n const previousRow = previousSourceRows[index]\n const key = previousRow ? getRowKey(previousRow, index) : getRowKey(row, index)\n\n return [key, row] as const\n }),\n )\n\n return targetRows.map((targetRow, index) => {\n const previousRow = previousSourceRows[index]\n const sourceRow =\n (previousRow && sourceRowsByPreviousKey.get(getRowKey(previousRow, index))) ||\n sourceRows[index]\n\n return sourceRow\n ? createSynchronizedRow(sourceRow, previousRow, targetRow, field)\n : { ...targetRow }\n })\n }\n\n const previousSourceIndexesByKey = new Map(\n previousSourceRows.map((row, index) => [getRowKey(row, index), index] as const),\n )\n\n return sourceRows.map((sourceRow, index) => {\n const previousIndex = previousSourceIndexesByKey.get(getRowKey(sourceRow, index))\n\n return createSynchronizedRow(\n sourceRow,\n previousIndex === undefined ? undefined : previousSourceRows[previousIndex],\n previousIndex === undefined ? undefined : targetRows[previousIndex],\n field,\n )\n })\n}\n\nconst descriptorChanged = ({\n field,\n previous,\n source,\n}: {\n field: SynchronizedField\n previous: Record<string, unknown>\n source: Record<string, unknown>\n}): boolean => {\n if (field.kind === 'value') {\n return !valuesAreEqual(source[field.name], previous[field.name])\n }\n\n if (field.kind === 'group') {\n return descriptorsChanged({\n fields: field.fields,\n previous: asDocument(previous[field.name]),\n source: asDocument(source[field.name]),\n })\n }\n\n if (!(field.name in source)) {\n return false\n }\n\n if (positionChanged(field, source, previous)) {\n return true\n }\n\n const previousRows = toArray(previous[field.name])\n const previousRowsByKey = new Map(\n previousRows.map((row, index) => [getRowKey(row, index), row] as const),\n )\n\n return toArray(source[field.name]).some((sourceRow, index) => {\n const previousRow = previousRowsByKey.get(getRowKey(sourceRow, index)) || previousRows[index]\n const fields =\n field.kind === 'array' ? field.fields : getBlockFieldsForRow(field, sourceRow)\n\n return descriptorsChanged({\n fields,\n previous: previousRow || {},\n source: sourceRow,\n })\n })\n}\n\nconst descriptorsChanged = ({\n fields,\n previous,\n source,\n}: {\n fields: SynchronizedField[]\n previous: Record<string, unknown>\n source: Record<string, unknown>\n}): boolean =>\n fields.some((field) =>\n descriptorChanged({\n field,\n previous,\n source,\n }),\n )\n\nconst synchronizeData = ({\n fields,\n previous,\n source,\n target,\n}: {\n fields: SynchronizedField[]\n previous: Record<string, unknown>\n source: Record<string, unknown>\n target: Record<string, unknown>\n}): Record<string, unknown> =>\n fields.reduce<Record<string, unknown>>((acc, field) => {\n if (field.kind === 'value') {\n if (field.name in source) {\n acc[field.name] = source[field.name]\n } else {\n delete acc[field.name]\n }\n\n return acc\n }\n\n if (field.kind === 'group') {\n if (field.name in source) {\n const value = synchronizeData({\n fields: field.fields,\n previous: asDocument(previous[field.name]),\n source: asDocument(source[field.name]),\n target: asDocument(acc[field.name]),\n })\n\n if (!valuesAreEqual(value, acc[field.name])) {\n acc[field.name] = value\n }\n } else {\n delete acc[field.name]\n }\n\n return acc\n }\n\n const value = synchronizeContainerValue({\n field,\n previousSourceValue: previous[field.name],\n sourceValue: source[field.name],\n targetValue: target[field.name],\n })\n\n if (!valuesAreEqual(value, target[field.name])) {\n acc[field.name] = value\n }\n\n return acc\n }, { ...target })\n\nconst getSynchronizedDataForTranslation = ({\n fields,\n nextDoc,\n previous,\n translation,\n}: {\n fields: SynchronizedField[]\n nextDoc: Record<string, unknown>\n previous: Record<string, unknown>\n translation: Record<string, unknown>\n}): Record<string, unknown> => {\n const synchronized = synchronizeData({\n fields,\n previous,\n source: nextDoc,\n target: translation,\n })\n\n return fields.reduce<Record<string, unknown>>((acc, field) => {\n if (!valuesAreEqual(synchronized[field.name], translation[field.name])) {\n acc[field.name] = synchronized[field.name]\n }\n\n return acc\n }, {})\n}\n\nconst isConfiguredLanguage = (\n collection: ResolvedMultilangCollection,\n language: string | undefined,\n): boolean =>\n Boolean(\n language &&\n collection.languages.some((configuredLanguage) => configuredLanguage.code === language),\n )\n\ntype CollectionEditViews = NonNullable<\n NonNullable<NonNullable<CollectionConfig['admin']>['components']>['views']\n>['edit']\n\nconst getDuplicateLanguageIDs = async ({\n collection,\n excludeID,\n group,\n language,\n req,\n}: {\n collection: ResolvedMultilangCollection\n excludeID?: number | string\n group: string\n language: string\n req: Parameters<CollectionBeforeChangeHook>[0]['req']\n}): Promise<Array<number | string>> => {\n const and: Where[] = [\n {\n [collection.fieldNames.group]: {\n equals: group,\n },\n },\n {\n [collection.fieldNames.language]: {\n equals: language,\n },\n },\n ]\n\n if (excludeID) {\n and.push({\n id: {\n not_equals: excludeID,\n },\n })\n }\n\n const result = await req.payload.find({\n collection: collection.slug,\n depth: 0,\n limit: 200,\n overrideAccess: true,\n req,\n where: {\n and,\n },\n })\n\n return result.docs\n .map((doc) => getID(asDocument(doc).id))\n .filter((id): id is number | string => id !== undefined)\n}\n\nexport const createTranslatedCollectionBeforeChangeHook =\n ({ collection }: { collection: ResolvedMultilangCollection }): CollectionBeforeChangeHook =>\n async ({ context, data, operation, originalDoc, req }) => {\n if (hasSkipContext(context)) {\n return data\n }\n\n const nextData = asDocument(data)\n const original = asDocument(originalDoc)\n const { group: groupField, language: languageField } = collection.fieldNames\n const originalLanguage = getStringValue(original[languageField])\n const originalLanguageIsConfigured = isConfiguredLanguage(collection, originalLanguage)\n const incomingLanguage = getStringValue(nextData[languageField])\n\n if (operation === 'update' && originalLanguage && !originalLanguageIsConfigured) {\n if (\n !incomingLanguage ||\n incomingLanguage === originalLanguage ||\n !isConfiguredLanguage(collection, incomingLanguage)\n ) {\n nextData[languageField] = ''\n }\n } else if (!incomingLanguage) {\n nextData[languageField] =\n operation === 'create'\n ? collection.defaultLanguage.code\n : originalLanguageIsConfigured\n ? originalLanguage\n : ''\n }\n\n const language = getStringValue(nextData[languageField])\n\n if (\n operation === 'update' &&\n originalLanguage &&\n originalLanguageIsConfigured &&\n language !== originalLanguage\n ) {\n throw new Error('Document language cannot be changed after creation.')\n }\n\n if (language && !isConfiguredLanguage(collection, language)) {\n throw new Error(`Language \"${language}\" is not configured for ${collection.slug}.`)\n }\n\n if (!getStringValue(nextData[groupField])) {\n const fallbackGroup = getStringValue(original[groupField])\n nextData[groupField] = fallbackGroup || randomUUID()\n }\n\n const group = getStringValue(nextData[groupField])\n\n if (language && group) {\n const currentID = operation === 'update' ? getID(original.id) : undefined\n const duplicateIDs = await getDuplicateLanguageIDs({\n collection,\n excludeID: currentID,\n group,\n language,\n req,\n })\n\n if (duplicateIDs.length > 0) {\n throw new Error(\n `A ${collection.slug} translation already exists for language \"${language}\" in this translation group.`,\n )\n }\n }\n\n return nextData\n }\n\nexport const createSynchronizedFieldsAfterChangeHook =\n ({\n collection,\n fields,\n }: {\n collection: ResolvedMultilangCollection\n fields?: Field[]\n }): CollectionAfterChangeHook =>\n async ({ context, doc, operation, previousDoc, req }) => {\n const synchronizedFields = getSynchronizedFields(fields)\n\n if (hasSkipContext(context) || operation !== 'update' || synchronizedFields.length === 0) {\n return doc\n }\n\n const nextDoc = asDocument(doc)\n const previous = asDocument(previousDoc)\n const group = getStringValue(nextDoc[collection.fieldNames.group])\n const currentID = getID(nextDoc.id)\n\n if (!group || !currentID) {\n return doc\n }\n\n const changedFields = synchronizedFields.filter((field) =>\n descriptorChanged({\n field,\n previous,\n source: nextDoc,\n }),\n )\n\n if (changedFields.length === 0) {\n return doc\n }\n\n const translations = await req.payload.find({\n collection: collection.slug,\n depth: 0,\n limit: 200,\n overrideAccess: true,\n req,\n where: {\n and: [\n {\n [collection.fieldNames.group]: {\n equals: group,\n },\n },\n {\n id: {\n not_equals: currentID,\n },\n },\n ],\n },\n })\n\n await Promise.all(\n translations.docs\n .map((translation) => {\n const translationDoc = asDocument(translation)\n const id = getID(translationDoc.id)\n\n if (id === undefined) {\n return undefined\n }\n\n const synchronizedData = getSynchronizedDataForTranslation({\n fields: changedFields,\n nextDoc,\n previous,\n translation: translationDoc,\n })\n\n if (Object.keys(synchronizedData).length === 0) {\n return undefined\n }\n\n return {\n id,\n data: synchronizedData,\n }\n })\n .filter(\n (update): update is { data: Record<string, unknown>; id: number | string } =>\n update !== undefined,\n )\n .map(({ id, data }) =>\n req.payload.update({\n id,\n collection: collection.slug,\n context: {\n [MULTILANG_SKIP_HOOK]: true,\n },\n data,\n overrideAccess: true,\n req,\n }),\n ),\n )\n\n return doc\n }\n\nexport const createHiddenFields = ({\n collection,\n}: {\n collection: ResolvedMultilangCollection\n}): Field[] => [\n {\n name: collection.fieldNames.language,\n type: 'text',\n admin: {\n disableListColumn: true,\n hidden: true,\n },\n index: true,\n label: LANGUAGE_LABEL,\n },\n {\n name: collection.fieldNames.group,\n type: 'text',\n admin: {\n disableListColumn: true,\n hidden: true,\n },\n index: true,\n label: TRANSLATIONS_LABEL,\n },\n {\n name: collection.fieldNames.meta,\n type: 'json',\n admin: {\n disableListColumn: true,\n hidden: true,\n },\n },\n {\n name: 'multilangLanguageMetabox',\n type: 'ui',\n admin: {\n components: {\n Field: '@roxxel/payload-multilang/client#LanguageMetabox',\n },\n position: 'sidebar',\n },\n },\n]\n\nexport const getLanguageColumnName = (): string => 'payloadMultilangTranslations'\n\nexport const createLanguageColumnFields = ({\n collection,\n}: {\n collection: ResolvedMultilangCollection\n}): Field[] => {\n const label = collection.languages\n .map((language) => language.flagLabel || language.code.toUpperCase())\n .join(' ')\n\n return [\n {\n name: getLanguageColumnName(),\n type: 'ui',\n admin: {\n components: {\n Cell: '@roxxel/payload-multilang/rsc#TranslationColumnCell',\n },\n disableListColumn: false,\n width: '132px',\n },\n label: label || TRANSLATIONS_LABEL,\n },\n ]\n}\n\nexport const translatedCollectionMeta = ({\n collection,\n}: {\n collection: ResolvedMultilangCollection\n}) => ({\n defaultLanguage: collection.defaultLanguage,\n fieldNames: collection.fieldNames,\n languages: collection.languages,\n})\n\nconst getDefaultColumns = ({\n collection,\n existingDefaultColumns,\n languageColumnName,\n}: {\n collection: ResolvedMultilangCollection\n existingDefaultColumns: string[]\n languageColumnName: string\n}): string[] => {\n const hiddenMultilangColumns = new Set([\n collection.fieldNames.group,\n collection.fieldNames.language,\n collection.fieldNames.meta,\n languageColumnName,\n ])\n const visibleExistingColumns = existingDefaultColumns.filter(\n (column) => !hiddenMultilangColumns.has(column),\n )\n\n return [...visibleExistingColumns, languageColumnName]\n}\n\nexport const withTranslatedCollection = ({\n collection,\n config,\n}: {\n collection: ResolvedMultilangCollection\n config: CollectionConfig\n}): CollectionConfig => {\n const existingDefaultColumns = config.admin?.defaultColumns || []\n const languageColumnName = getLanguageColumnName()\n const existingEditViews =\n (config.admin?.components?.views?.edit as Record<string, unknown> | undefined) || {}\n const defaultColumns = getDefaultColumns({\n collection,\n existingDefaultColumns,\n languageColumnName,\n })\n\n return {\n ...config,\n admin: {\n ...config.admin,\n components: {\n ...config.admin?.components,\n beforeList: [\n ...(config.admin?.components?.beforeList || []),\n '@roxxel/payload-multilang/client#LanguageListToolbar',\n ],\n beforeListTable: config.admin?.components?.beforeListTable,\n views: {\n ...config.admin?.components?.views,\n edit: {\n ...existingEditViews,\n translations: {\n Component: '@roxxel/payload-multilang/rsc#TranslationsTab',\n path: '/translations',\n tab: {\n label: ({ t }) => t('payloadMultilang:translations'),\n order: 80,\n },\n },\n } as CollectionEditViews,\n },\n },\n custom: {\n ...config.admin?.custom,\n payloadMultilang: translatedCollectionMeta({\n collection,\n }),\n },\n defaultColumns,\n },\n endpoints: [...(config.endpoints || [])],\n fields: [\n ...(config.fields || []),\n ...createHiddenFields({ collection }),\n ...createLanguageColumnFields({ collection }),\n ],\n hooks: {\n ...config.hooks,\n afterChange: [\n createSynchronizedFieldsAfterChangeHook({\n collection,\n fields: config.fields,\n }),\n ...(config.hooks?.afterChange || []),\n ],\n beforeChange: [\n createTranslatedCollectionBeforeChangeHook({\n collection,\n }),\n ...(config.hooks?.beforeChange || []),\n ],\n },\n }\n}\n"],"names":["randomUUID","MULTILANG_SKIP_HOOK","asDocument","getID","getStringValue","LANGUAGE_LABEL","en","uk","TRANSLATIONS_LABEL","hasSkipContext","context","isObject","value","Array","isArray","toArray","filter","valuesAreEqual","left","right","JSON","stringify","fieldAffectsData","field","name","type","fieldSynchronizes","custom","multilang","synchronize","fieldSynchronizesPosition","synchronizePosition","hasName","getSynchronizedBlocks","inheritedSynchronize","blocks","flatMap","block","fields","getSynchronizedFields","length","slug","getSynchronizedTabFields","tabs","tab","kind","getRowKey","row","index","id","undefined","String","getShellSignature","map","blockName","blockType","key","positionChanged","source","previous","getBlockFieldsForRow","sourceRow","find","createSynchronizedRow","previousRow","targetRow","sourceBlockType","previousBlockType","blockTypeChanged","synchronizeData","target","synchronizeContainerValue","previousSourceValue","sourceValue","targetValue","targetRows","previousSourceRows","sourceRows","sourceRowsByPreviousKey","Map","get","previousSourceIndexesByKey","previousIndex","descriptorChanged","descriptorsChanged","previousRows","previousRowsByKey","some","reduce","acc","getSynchronizedDataForTranslation","nextDoc","translation","synchronized","isConfiguredLanguage","collection","language","Boolean","languages","configuredLanguage","code","getDuplicateLanguageIDs","excludeID","group","req","and","fieldNames","equals","push","not_equals","result","payload","depth","limit","overrideAccess","where","docs","doc","createTranslatedCollectionBeforeChangeHook","data","operation","originalDoc","nextData","original","groupField","languageField","originalLanguage","originalLanguageIsConfigured","incomingLanguage","defaultLanguage","Error","fallbackGroup","currentID","duplicateIDs","createSynchronizedFieldsAfterChangeHook","previousDoc","synchronizedFields","changedFields","translations","Promise","all","translationDoc","synchronizedData","Object","keys","update","createHiddenFields","admin","disableListColumn","hidden","label","meta","components","Field","position","getLanguageColumnName","createLanguageColumnFields","flagLabel","toUpperCase","join","Cell","width","translatedCollectionMeta","getDefaultColumns","existingDefaultColumns","languageColumnName","hiddenMultilangColumns","Set","visibleExistingColumns","column","has","withTranslatedCollection","config","defaultColumns","existingEditViews","views","edit","beforeList","beforeListTable","Component","path","t","order","payloadMultilang","endpoints","hooks","afterChange","beforeChange"],"mappings":"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"}
@@ -172,7 +172,7 @@ Mark fields that should stay shared across translations directly in the field co
172
172
  - `array` and `blocks` synchronize their row or block shell and every child field recursively.
173
173
  - `tabs` are not synchronized as values, but fields inside tabs are traversed and can synchronize normally.
174
174
 
175
- Use `custom.multilang.synchronizePosition: true` on `array` or `blocks` when only the outer shell should follow the source document. This synchronizes row or block order, plus block type and block name for blocks, while preserving each translation's nested field values.
175
+ Use `custom.multilang.synchronizePosition: true` on `array` or `blocks` when the repeatable structure should follow the source document. This synchronizes row or block order, plus block type and block name for blocks. Descendant fields marked with `custom.multilang.synchronize: true` are still copied, while unmarked nested fields remain localized.
176
176
 
177
177
  If a container is not marked but a descendant field is marked with `synchronize: true`, existing rows or blocks are matched without changing translation-local row order or membership.
178
178
 
package/docs/usage.md CHANGED
@@ -31,7 +31,7 @@ Editors can then choose the document language in the sidebar and create or conne
31
31
 
32
32
  Mark shared fields with `custom.multilang.synchronize: true`. For `group`, `array`, and `blocks`, this synchronizes nested values recursively. `tabs` are only traversed; fields inside tabs can still opt in.
33
33
 
34
- Use `custom.multilang.synchronizePosition: true` on `array` or `blocks` to synchronize only the repeatable shell, preserving localized values inside each row or block.
34
+ Use `custom.multilang.synchronizePosition: true` on `array` or `blocks` to synchronize the repeatable shell. Descendant fields marked with `custom.multilang.synchronize: true` are copied across translations, while unmarked nested fields stay localized.
35
35
 
36
36
  ## App-Level Convenience Helpers
37
37
 
@@ -259,7 +259,7 @@ Set `custom.multilang.synchronize` on fields that should be identical across tra
259
259
 
260
260
  When an editor changes one of those fields on a saved translation, the plugin updates the same field on the other linked translations. For `group`, `array`, and `blocks`, `synchronize: true` applies recursively to nested fields.
261
261
 
262
- Use `custom.multilang.synchronizePosition: true` on `array` or `blocks` to keep only the repeatable shell aligned while preserving localized values inside each row or block.
262
+ Use `custom.multilang.synchronizePosition: true` on `array` or `blocks` to keep the repeatable shell aligned. Descendant fields marked with `custom.multilang.synchronize: true` are copied across translations, while unmarked nested fields stay localized.
263
263
 
264
264
  ## Generate Types
265
265
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@roxxel/payload-multilang",
3
- "version": "0.0.7",
3
+ "version": "0.0.8",
4
4
  "description": "Polylang-style document localization for Payload CMS",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -41,6 +41,7 @@
41
41
  "dev:generate-importmap": "pnpm dev:payload generate:importmap",
42
42
  "dev:generate-types": "pnpm dev:payload generate:types",
43
43
  "dev:payload": "cross-env PAYLOAD_CONFIG_PATH=./dev/payload.config.ts payload",
44
+ "dev:seed": "cross-env PAYLOAD_CONFIG_PATH=./dev/payload.config.ts payload seed",
44
45
  "generate:importmap": "pnpm dev:generate-importmap",
45
46
  "generate:types": "pnpm dev:generate-types",
46
47
  "lint": "eslint",