Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions docs/configuration/localization.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -144,15 +144,17 @@ export default buildConfig({
// ...
experimental: {
localizeStatus: true,
localizeUpdatedAt: true,
},
})
```

The following experimental options are available related to localization:

| Option | Description |
| -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **`localizeStatus`** | **Boolean.** When `true`, shows document status per locale in the admin panel instead of always showing the latest overall status. Opt-in for backwards compatibility. Defaults to `false`. |
| Option | Description |
| ----------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **`localizeStatus`** | **Boolean.** When `true`, shows document status per locale in the admin panel instead of always showing the latest overall status. Opt-in for backwards compatibility. Defaults to `false`. |
| **`localizeUpdatedAt`** | **Boolean.** When `true`, shows `updatedAt` timestamp per locale in the admin panel instead of showing the latest overall timestamp. Opt-in for backwards compatibility. Defaults to `false`. |

## Field Localization

Expand Down
8 changes: 5 additions & 3 deletions docs/experimental/overview.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ const config = buildConfig({
// ...
experimental: {
localizeStatus: true, // highlight-line
localizeUpdatedAt: true, // highlight-line
},
})
```
Expand All @@ -27,9 +28,10 @@ const config = buildConfig({

The following options are available:

| Option | Description |
| -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **`localizeStatus`** | **Boolean.** When `true`, shows document status per locale in the admin panel instead of always showing the latest overall status. Opt-in for backwards compatibility. Defaults to `false`. |
| Option | Description |
| ----------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **`localizeStatus`** | **Boolean.** When `true`, shows document status per locale in the admin panel instead of always showing the latest overall status. Opt-in for backwards compatibility. Defaults to `false`. |
| **`localizeUpdatedAt`** | **Boolean.** When `true`, shows `updatedAt` timestamp per locale in the admin panel instead of showing the latest overall timestamp. Opt-in for backwards compatibility. Defaults to `false`. |

This list may change without notice.

Expand Down
2 changes: 2 additions & 0 deletions packages/db-mongodb/src/createGlobalVersion.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export const createGlobalVersion: CreateGlobalVersion = async function createGlo
createdAt,
globalSlug,
localeStatus,
localeUpdatedAt,
parent,
publishedLocale,
req,
Expand All @@ -35,6 +36,7 @@ export const createGlobalVersion: CreateGlobalVersion = async function createGlo
createdAt,
latest: true,
localeStatus,
localeUpdatedAt,
parent,
publishedLocale,
snapshot,
Expand Down
2 changes: 2 additions & 0 deletions packages/db-mongodb/src/createVersion.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export const createVersion: CreateVersion = async function createVersion(
collectionSlug,
createdAt,
localeStatus,
localeUpdatedAt,
parent,
publishedLocale,
req,
Expand All @@ -39,6 +40,7 @@ export const createVersion: CreateVersion = async function createVersion(
createdAt,
latest: true,
localeStatus,
localeUpdatedAt,
parent,
publishedLocale,
snapshot,
Expand Down
13 changes: 10 additions & 3 deletions packages/db-mongodb/src/queryDrafts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -181,9 +181,16 @@ export const queryDrafts: QueryDrafts = async function queryDrafts(
const id = result.docs[i].parent

const localeStatus = result.docs[i].localeStatus || {}
if (locale && localeStatus[locale]) {
result.docs[i].status = localeStatus[locale]
result.docs[i].version._status = localeStatus[locale]
const localeUpdatedAt = result.docs[i].localeUpdatedAt || {}

if (locale) {
if (localeStatus[locale]) {
result.docs[i].status = localeStatus[locale]
result.docs[i].version._status = localeStatus[locale]
}
if (localeUpdatedAt[locale]) {
result.docs[i].version.updatedAt = localeUpdatedAt[locale]
}
}

result.docs[i] = result.docs[i].version ?? {}
Expand Down
2 changes: 2 additions & 0 deletions packages/drizzle/src/createGlobalVersion.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export async function createGlobalVersion<T extends TypeWithID>(
createdAt,
globalSlug,
localeStatus,
localeUpdatedAt,
publishedLocale,
req,
returning,
Expand All @@ -37,6 +38,7 @@ export async function createGlobalVersion<T extends TypeWithID>(
createdAt,
latest: true,
localeStatus,
localeUpdatedAt,
publishedLocale,
snapshot,
updatedAt,
Expand Down
2 changes: 2 additions & 0 deletions packages/drizzle/src/createVersion.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export async function createVersion<T extends TypeWithID>(
collectionSlug,
createdAt,
localeStatus,
localeUpdatedAt,
parent,
publishedLocale,
req,
Expand All @@ -42,6 +43,7 @@ export async function createVersion<T extends TypeWithID>(
createdAt,
latest: true,
localeStatus,
localeUpdatedAt,
parent,
publishedLocale,
snapshot,
Expand Down
13 changes: 10 additions & 3 deletions packages/drizzle/src/queryDrafts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,16 @@ export const queryDrafts: QueryDrafts = async function queryDrafts(
for (let i = 0; i < result.docs.length; i++) {
const id = result.docs[i].parent
const localeStatus = result.docs[i].localeStatus || {}
if (locale && localeStatus[locale]) {
result.docs[i].status = localeStatus[locale]
result.docs[i].version._status = localeStatus[locale]
const localeUpdatedAt = result.docs[i].localeUpdatedAt || {}

if (locale) {
if (localeStatus[locale]) {
result.docs[i].status = localeStatus[locale]
result.docs[i].version._status = localeStatus[locale]
}
if (localeUpdatedAt[locale]) {
result.docs[i].version.updatedAt = localeUpdatedAt[locale]
}
}

result.docs[i] = result.docs[i].version ?? {}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ type AutosaveCellProps = {
autosave?: boolean
id: number | string
localeStatus?: Record<string, 'draft' | 'published'>
localeUpdatedAt?: Record<string, string>
publishedLocale?: string
version: {
_status: string
Expand Down
6 changes: 5 additions & 1 deletion packages/payload/src/config/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -162,9 +162,13 @@ export const createClientConfig = ({
case 'experimental':
if (config.experimental) {
clientConfig.experimental = {}
if (config.experimental?.localizeStatus) {
if (config.experimental.localizeStatus) {
clientConfig.experimental.localizeStatus = config.experimental.localizeStatus
}

if (config.experimental.localizeUpdatedAt) {
clientConfig.experimental.localizeUpdatedAt = config.experimental.localizeUpdatedAt
}
}

break
Expand Down
4 changes: 4 additions & 0 deletions packages/payload/src/config/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -727,6 +727,10 @@ export type ImportMapGenerators = Array<
*/
export type ExperimentalConfig = {
localizeStatus?: boolean
/**
* Boolean. Returns the `updatedAt` timestamp of the localized document.
**/
localizeUpdatedAt?: boolean
}

export type AfterErrorHook = (
Expand Down
2 changes: 2 additions & 0 deletions packages/payload/src/database/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -391,6 +391,7 @@ export type CreateVersionArgs<T = TypeWithID> = {
collectionSlug: CollectionSlug
createdAt: string
localeStatus?: Record<string, 'draft' | 'published'>
localeUpdatedAt?: Record<string, string>
/** ID of the parent document for which the version should be created for */
parent: number | string
publishedLocale?: string
Expand All @@ -416,6 +417,7 @@ export type CreateGlobalVersionArgs<T = TypeWithID> = {
createdAt: string
globalSlug: GlobalSlug
localeStatus?: Record<string, 'draft' | 'published'>
localeUpdatedAt?: Record<string, string>
/** ID of the parent document for which the version should be created for */
parent: number | string
publishedLocale?: string
Expand Down
16 changes: 16 additions & 0 deletions packages/payload/src/versions/baseFields.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,3 +64,19 @@ export function buildLocaleStatusField(config: SanitizedConfig): Field[] {
}
})
}

export function buildLocaleUpdatedAtFields(config: SanitizedConfig): Field[] {
if (!config.localization || !config.localization.locales) {
return []
}

return config.localization.locales.map((locale) => {
const code = typeof locale === 'string' ? locale : locale.code

return {
name: code,
type: 'date',
index: true,
}
})
}
23 changes: 22 additions & 1 deletion packages/payload/src/versions/buildCollectionFields.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@ import type { SanitizedCollectionConfig } from '../collections/config/types.js'
import type { SanitizedConfig } from '../config/types.js'
import type { Field, FlattenedField } from '../fields/config/types.js'

import { buildLocaleStatusField, versionSnapshotField } from './baseFields.js'
import {
buildLocaleStatusField,
buildLocaleUpdatedAtFields,
versionSnapshotField,
} from './baseFields.js'

export const buildVersionCollectionFields = <T extends boolean = false>(
config: SanitizedConfig,
Expand Down Expand Up @@ -79,6 +83,23 @@ export const buildVersionCollectionFields = <T extends boolean = false>(
})!,
})
}

if (config.experimental?.localizeUpdatedAt) {
const localeUpdatedAtFields = buildLocaleUpdatedAtFields(config)

fields.push({
name: 'localeUpdatedAt',
type: 'group',
admin: {
disableBulkEdit: true,
disabled: true,
},
fields: localeUpdatedAtFields,
...(flatten && {
flattenedFields: localeUpdatedAtFields as FlattenedField[],
})!,
})
}
}

fields.push({
Expand Down
23 changes: 22 additions & 1 deletion packages/payload/src/versions/buildGlobalFields.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@ import type { SanitizedConfig } from '../config/types.js'
import type { Field, FlattenedField } from '../fields/config/types.js'
import type { SanitizedGlobalConfig } from '../globals/config/types.js'

import { buildLocaleStatusField, versionSnapshotField } from './baseFields.js'
import {
buildLocaleStatusField,
buildLocaleUpdatedAtFields,
versionSnapshotField,
} from './baseFields.js'

export const buildVersionGlobalFields = <T extends boolean = false>(
config: SanitizedConfig,
Expand Down Expand Up @@ -73,6 +77,23 @@ export const buildVersionGlobalFields = <T extends boolean = false>(
})!,
})
}

if (config.experimental.localizeUpdatedAt) {
const localeUpdatedAtFields = buildLocaleUpdatedAtFields(config)

fields.push({
name: 'localeUpdatedAt',
type: 'group',
admin: {
disableBulkEdit: true,
disabled: true,
},
fields: localeUpdatedAtFields,
...(flatten && {
flattenedFields: localeUpdatedAtFields as FlattenedField[],
})!,
})
}
}

fields.push({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,12 @@ export const replaceWithDraftIfAvailable = async <T extends TypeWithID>({
;(draft.version as { _status?: string })['_status'] = localeStatus[locale]
}

// Lift locale updatedAt from version data if available
const localeUpdatedAt = draft.localeUpdatedAt || {}
if (locale && localeUpdatedAt[locale]) {
;(draft.version as { updatedAt?: string })['updatedAt'] = localeUpdatedAt[locale]
}

// Disregard all other draft content at this point,
// Only interested in the version itself.
// Operations will handle firing hooks, etc.
Expand Down
65 changes: 44 additions & 21 deletions packages/payload/src/versions/saveVersion.ts
Original file line number Diff line number Diff line change
Expand Up @@ -131,41 +131,63 @@ export const saveVersion = async ({

if (createNewVersion) {
let localeStatus = {}
let localeUpdatedAt = {}
const localizationEnabled =
payload.config.localization && payload.config.localization.locales.length > 0

if (
localizationEnabled &&
payload.config.localization !== false &&
payload.config.experimental?.localizeStatus
) {
if (localizationEnabled && payload.config.localization !== false) {
const allLocales = (
(payload.config.localization && payload.config.localization?.locales) ||
[]
).map((locale) => (typeof locale === 'string' ? locale : locale.code))

// If `publish all`, set all locales to published
if (versionData._status === 'published' && !publishSpecificLocale) {
localeStatus = Object.fromEntries(allLocales.map((code) => [code, 'published']))
} else if (publishSpecificLocale || (locale && versionData._status === 'draft')) {
const status: 'draft' | 'published' = publishSpecificLocale ? 'published' : 'draft'
const incomingLocale = String(publishSpecificLocale || locale)
const existing = latestVersion?.localeStatus
if (payload.config.experimental?.localizeStatus) {
// If `publish all`, set all locales to published
if (versionData._status === 'published' && !publishSpecificLocale) {
localeStatus = Object.fromEntries(allLocales.map((code) => [code, 'published']))
} else if (publishSpecificLocale || (locale && versionData._status === 'draft')) {
const status: 'draft' | 'published' = publishSpecificLocale ? 'published' : 'draft'
const incomingLocale = String(publishSpecificLocale || locale)
const existing = latestVersion?.localeStatus

// If no locale statuses are set, set it and set all others to draft
if (!existing) {
localeStatus = {
...Object.fromEntries(
allLocales
.filter((code) => code !== incomingLocale)
.map((code) => [code, 'draft']),
),
[incomingLocale]: status,
}
} else {
// If locales already exist, update the status for the incoming locale
const { [incomingLocale]: _, ...rest } = existing
localeStatus = {
...rest,
[incomingLocale]: status,
}
}
}
}

if (payload.config.experimental?.localizeUpdatedAt) {
const incomingLocale = String(locale)
const existing = latestVersion?.localeUpdatedAt

// If no locale statuses are set, set it and set all others to draft
if (!existing) {
localeStatus = {
localeUpdatedAt = {
...Object.fromEntries(
allLocales.filter((code) => code !== incomingLocale).map((code) => [code, 'draft']),
allLocales
.filter((code) => code !== incomingLocale)
.map((code) => [code, latestVersion?.createdAt || now]),
),
[incomingLocale]: status,
[incomingLocale]: now,
}
} else {
// If locales already exist, update the status for the incoming locale
const { [incomingLocale]: _, ...rest } = existing
localeStatus = {
...rest,
[incomingLocale]: status,
localeUpdatedAt = {
...existing,
[incomingLocale]: now,
}
}
}
Expand All @@ -177,6 +199,7 @@ export const saveVersion = async ({
createdAt: operation === 'restoreVersion' ? versionData.createdAt : now,
globalSlug: undefined as string | undefined,
localeStatus,
localeUpdatedAt,
parent: collection ? id : undefined,
publishedLocale: publishSpecificLocale || undefined,
req,
Expand Down
Loading
Loading