Skip to content
Open
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
19 changes: 10 additions & 9 deletions docs/configuration/localization.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -93,12 +93,12 @@ The locale codes do not need to be in any specific format. It's up to you to def

#### Locale Object

| Option | Description |
| -------------------- | ------------------------------------------------------------------------------------------------------------------------------ |
| **`code`** \* | Unique code to identify the language throughout the APIs for `locale` and `fallbackLocale` |
| **`label`** | A string to use for the selector when choosing a language, or an object keyed on the i18n keys for different languages in use. |
| **`rtl`** | A boolean that when true will make the admin UI display in Right-To-Left. |
| **`fallbackLocale`** | The code for this language to fallback to when properties of a document are not present. |
| Option | Description |
| -------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **`code`** \* | Unique code to identify the language throughout the APIs for `locale` and `fallbackLocale` |
| **`label`** | A string to use for the selector when choosing a language, or an object keyed on the i18n keys for different languages in use. |
| **`rtl`** | A boolean that when true will make the admin UI display in Right-To-Left. |
| **`fallbackLocale`** | The code for this language to fallback to when properties of a document are not present. You can enable `experimental.multipleFallbackLocales` to allow an array of locales. |

_\* An asterisk denotes that a property is required._

Expand Down Expand Up @@ -150,9 +150,10 @@ export default buildConfig({

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`. |
| **`multipleFallbackLocales`** | **Boolean.** When `true`, allows `fallbackLocale` to accept an array of locales in find queries and locale configuration. Defaults to `false`. |
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this needs to be behind an experimental flag. I'm guessing you might have done this because it would make for a new type union for plugins to deal with. The problem is that if a project uses this feature then the plugin will be broken either way as a result.


## Field Localization

Expand Down
2 changes: 1 addition & 1 deletion packages/payload/src/collections/operations/local/find.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ export type Options<TSlug extends CollectionSlug, TSelect extends SelectType> =
/**
* Specify a [fallback locale](https://payloadcms.com/docs/configuration/localization) to use for any returned documents.
*/
fallbackLocale?: false | TypedLocale
fallbackLocale?: false | TypedLocale | TypedLocale[]
/**
* Include info about the lock status to the result into all documents with fields: `_isLocked` and `_userEditing`
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ export type Options<
/**
* Specify a [fallback locale](https://payloadcms.com/docs/configuration/localization) to use for any returned documents.
*/
fallbackLocale?: false | TypedLocale
fallbackLocale?: false | TypedLocale | TypedLocale[]
/**
* The ID of the document to find.
*/
Expand Down
4 changes: 4 additions & 0 deletions packages/payload/src/config/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,10 @@ export const createClientConfig = ({
if (config.experimental?.localizeStatus) {
clientConfig.experimental.localizeStatus = config.experimental.localizeStatus
}
if (config.experimental?.multipleFallbackLocales) {
clientConfig.experimental.multipleFallbackLocales =
config.experimental.multipleFallbackLocales
}
}

break
Expand Down
6 changes: 5 additions & 1 deletion packages/payload/src/config/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -466,7 +466,7 @@ export type Locale = {
/**
* Code of another locale to use when reading documents with fallback, if not specified defaultLocale is used
*/
fallbackLocale?: string
fallbackLocale?: string | string[]
/**
* label of supported locale
* @example "English"
Expand Down Expand Up @@ -732,6 +732,10 @@ export type ImportMapGenerators = Array<
*/
export type ExperimentalConfig = {
localizeStatus?: boolean
/**
* When true, fallbackLocale accepts an array of locales in find queries and locale configuration.
*/
multipleFallbackLocales?: boolean
}

export type AfterErrorHook = (
Expand Down
1 change: 1 addition & 0 deletions packages/payload/src/fields/hooks/afterRead/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ export async function afterRead<T extends JsonObject>(args: AfterReadArgs<T>): P
depth,
doc: incomingDoc,
draft,
experimental: req.payload.config.experimental,
fallbackLocale,
fieldPromises,
fields: (collection?.fields || global?.fields)!,
Expand Down
19 changes: 17 additions & 2 deletions packages/payload/src/fields/hooks/afterRead/promise.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { RichTextAdapter } from '../../../admin/RichText.js'
import type { SanitizedCollectionConfig } from '../../../collections/config/types.js'
import type { SanitizedGlobalConfig } from '../../../globals/config/types.js'
import type { ExperimentalConfig, RequestContext } from '../../../index.js'
import type {
JsonObject,
PayloadRequest,
Expand All @@ -12,7 +13,6 @@ import type { Block, Field, TabAsField } from '../../config/types.js'
import type { AfterReadArgs } from './index.js'

import { MissingEditorProp } from '../../../errors/index.js'
import { type RequestContext } from '../../../index.js'
import { getBlockSelect } from '../../../utilities/getBlockSelect.js'
import { stripUnselectedFields } from '../../../utilities/stripUnselectedFields.js'
import { fieldAffectsData, fieldShouldBeLocalized, tabHasName } from '../../config/types.js'
Expand All @@ -33,6 +33,7 @@ type Args = {
depth: number
doc: JsonObject
draft: boolean
experimental?: ExperimentalConfig
fallbackLocale: null | string
field: Field | TabAsField
fieldIndex: number
Expand Down Expand Up @@ -79,6 +80,7 @@ export const promise = async ({
depth,
doc,
draft,
experimental,
fallbackLocale,
field,
fieldIndex,
Expand Down Expand Up @@ -158,8 +160,21 @@ export const promise = async ({
let hoistedValue = value

if (fallbackLocale && fallbackLocale !== locale) {
const fallbackValue = siblingDoc[field.name!][fallbackLocale]
let fallbackValue
const isNullOrUndefined = typeof value === 'undefined' || value === null
console.log(experimental?.multipleFallbackLocales)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(:

if (experimental?.multipleFallbackLocales && Array.isArray(fallbackLocale)) {
for (const locale of fallbackLocale) {
const val = siblingDoc[field.name!]?.[locale]

if (val !== undefined && val !== null && val !== '') {
fallbackValue = val
break
}
}
} else {
fallbackValue = siblingDoc[field.name!][fallbackLocale]
}

if (fallbackValue) {
switch (field.type) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { SanitizedCollectionConfig } from '../../../collections/config/types.js'
import type { SanitizedGlobalConfig } from '../../../globals/config/types.js'
import type { RequestContext } from '../../../index.js'
import type { ExperimentalConfig, RequestContext } from '../../../index.js'
import type {
JsonObject,
PayloadRequest,
Expand All @@ -23,6 +23,7 @@ type Args = {
depth: number
doc: JsonObject
draft: boolean
experimental?: ExperimentalConfig
fallbackLocale: null | string
/**
* fieldPromises are used for things like field hooks. They should be awaited before awaiting populationPromises
Expand Down Expand Up @@ -60,6 +61,7 @@ export const traverseFields = ({
depth,
doc,
draft,
experimental,
fallbackLocale,
fieldPromises,
fields,
Expand Down Expand Up @@ -92,6 +94,7 @@ export const traverseFields = ({
depth,
doc,
draft,
experimental,
fallbackLocale,
field,
fieldIndex,
Expand Down
2 changes: 1 addition & 1 deletion packages/payload/src/globals/operations/local/findOne.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ export type Options<TSlug extends GlobalSlug, TSelect extends SelectType> = {
/**
* Specify a [fallback locale](https://payloadcms.com/docs/configuration/localization) to use for any returned documents.
*/
fallbackLocale?: false | TypedLocale
fallbackLocale?: false | TypedLocale | TypedLocale[]
/**
* Include info about the lock status to the result with fields: `_isLocked` and `_userEditing`
*/
Expand Down
18 changes: 16 additions & 2 deletions packages/payload/src/utilities/sanitizeFallbackLocale.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import type { SanitizedLocalizationConfig } from '../config/types.js'
import type { TypedLocale } from '../index.js'

interface Args {
fallbackLocale: false | TypedLocale
fallbackLocale: false | TypedLocale | TypedLocale[]
locale: string
localization: SanitizedLocalizationConfig
}
Expand All @@ -26,7 +26,10 @@ export const sanitizeFallbackLocale = ({
hasFallbackLocale = Boolean(localization && localization.fallback)
}

if (fallbackLocale && !['false', 'none', 'null'].includes(fallbackLocale)) {
if (
fallbackLocale &&
!['false', 'none', 'null'].includes(!Array.isArray(fallbackLocale) ? fallbackLocale : '')
) {
hasFallbackLocale = true
}

Expand All @@ -52,5 +55,16 @@ export const sanitizeFallbackLocale = ({
fallbackLocale = null
}

if (
typeof fallbackLocale === 'string' &&
fallbackLocale.startsWith('[') &&
fallbackLocale.endsWith(']')
) {
fallbackLocale = fallbackLocale
.slice(1, -1)
.split(',')
.map((l) => l.trim())
}

return fallbackLocale as null | string
}
2 changes: 1 addition & 1 deletion test/helpers/NextRESTClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ type RequestOptions = {
auth?: boolean
query?: { [key: string]: unknown } & {
depth?: number
fallbackLocale?: string
fallbackLocale?: string | string[]
joins?: JoinQuery
limit?: number
locale?: string
Expand Down
1 change: 1 addition & 0 deletions test/localization/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -430,6 +430,7 @@ export default buildConfigWithDefaults({
],
experimental: {
localizeStatus: true,
multipleFallbackLocales: true,
},
localization: {
filterAvailableLocales: ({ locales }) => {
Expand Down
Loading
Loading