feat: pass i18n through field label and description functions (#11802)
Passes the `i18n` arg through field label and description functions.
This is to avoid using custom components when simply needing to
translate a `StaticLabel` object, such as collection labels.
Here's an example:
```ts
{
labels: {
singular: {
en: 'My Collection'
}
},
fields: [
// ...
{
type: 'collapsible',
label: ({ i18n }) => `Translate this: ${getTranslation(collectionConfig.labels.singular, i18n)}`
// ...
}
]
}
```
This commit is contained in:
@@ -172,7 +172,7 @@ export async function VersionsView(props: DocumentViewServerProps) {
|
|||||||
|
|
||||||
const pluralLabel = collectionConfig?.labels?.plural
|
const pluralLabel = collectionConfig?.labels?.plural
|
||||||
? typeof collectionConfig.labels.plural === 'function'
|
? typeof collectionConfig.labels.plural === 'function'
|
||||||
? collectionConfig.labels.plural({ t })
|
? collectionConfig.labels.plural({ i18n, t })
|
||||||
: collectionConfig.labels.plural
|
: collectionConfig.labels.plural
|
||||||
: globalConfig?.label
|
: globalConfig?.label
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import type { TFunction } from '@payloadcms/translations'
|
import type { I18nClient, TFunction } from '@payloadcms/translations'
|
||||||
|
|
||||||
import type { Field } from '../../fields/config/types.js'
|
import type { Field } from '../../fields/config/types.js'
|
||||||
import type { ClientFieldWithOptionalType, ServerComponentProps } from './Field.js'
|
import type { ClientFieldWithOptionalType, ServerComponentProps } from './Field.js'
|
||||||
|
|
||||||
export type DescriptionFunction = ({ t }: { t: TFunction }) => string
|
export type DescriptionFunction = (args: { i18n: I18nClient; t: TFunction }) => string
|
||||||
|
|
||||||
export type FieldDescriptionClientComponent<
|
export type FieldDescriptionClientComponent<
|
||||||
TFieldClient extends ClientFieldWithOptionalType = ClientFieldWithOptionalType,
|
TFieldClient extends ClientFieldWithOptionalType = ClientFieldWithOptionalType,
|
||||||
|
|||||||
@@ -215,11 +215,11 @@ export const createClientCollectionConfig = ({
|
|||||||
clientCollection.labels = {
|
clientCollection.labels = {
|
||||||
plural:
|
plural:
|
||||||
typeof collection.labels.plural === 'function'
|
typeof collection.labels.plural === 'function'
|
||||||
? collection.labels.plural({ t: i18n.t })
|
? collection.labels.plural({ i18n, t: i18n.t })
|
||||||
: collection.labels.plural,
|
: collection.labels.plural,
|
||||||
singular:
|
singular:
|
||||||
typeof collection.labels.singular === 'function'
|
typeof collection.labels.singular === 'function'
|
||||||
? collection.labels.singular({ t: i18n.t })
|
? collection.labels.singular({ i18n, t: i18n.t })
|
||||||
: collection.labels.singular,
|
: collection.labels.singular,
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
|
|||||||
@@ -508,9 +508,8 @@ export type LocalizationConfig = Prettify<
|
|||||||
LocalizationConfigWithLabels | LocalizationConfigWithNoLabels
|
LocalizationConfigWithLabels | LocalizationConfigWithNoLabels
|
||||||
>
|
>
|
||||||
|
|
||||||
export type LabelFunction<TTranslationKeys = DefaultTranslationKeys> = ({
|
export type LabelFunction<TTranslationKeys = DefaultTranslationKeys> = (args: {
|
||||||
t,
|
i18n: I18nClient
|
||||||
}: {
|
|
||||||
t: TFunction<TTranslationKeys>
|
t: TFunction<TTranslationKeys>
|
||||||
}) => string
|
}) => string
|
||||||
|
|
||||||
|
|||||||
@@ -140,12 +140,12 @@ export const createClientBlocks = ({
|
|||||||
|
|
||||||
if (block.labels.singular) {
|
if (block.labels.singular) {
|
||||||
if (typeof block.labels.singular === 'function') {
|
if (typeof block.labels.singular === 'function') {
|
||||||
clientBlock.labels.singular = block.labels.singular({ t: i18n.t })
|
clientBlock.labels.singular = block.labels.singular({ i18n, t: i18n.t })
|
||||||
} else {
|
} else {
|
||||||
clientBlock.labels.singular = block.labels.singular
|
clientBlock.labels.singular = block.labels.singular
|
||||||
}
|
}
|
||||||
if (typeof block.labels.plural === 'function') {
|
if (typeof block.labels.plural === 'function') {
|
||||||
clientBlock.labels.plural = block.labels.plural({ t: i18n.t })
|
clientBlock.labels.plural = block.labels.plural({ i18n, t: i18n.t })
|
||||||
} else {
|
} else {
|
||||||
clientBlock.labels.plural = block.labels.plural
|
clientBlock.labels.plural = block.labels.plural
|
||||||
}
|
}
|
||||||
@@ -224,7 +224,7 @@ export const createClientField = ({
|
|||||||
//@ts-expect-error - would need to type narrow
|
//@ts-expect-error - would need to type narrow
|
||||||
if (typeof incomingField.label === 'function') {
|
if (typeof incomingField.label === 'function') {
|
||||||
//@ts-expect-error - would need to type narrow
|
//@ts-expect-error - would need to type narrow
|
||||||
clientField.label = incomingField.label({ t: i18n.t })
|
clientField.label = incomingField.label({ i18n, t: i18n.t })
|
||||||
} else {
|
} else {
|
||||||
//@ts-expect-error - would need to type narrow
|
//@ts-expect-error - would need to type narrow
|
||||||
clientField.label = incomingField.label
|
clientField.label = incomingField.label
|
||||||
@@ -246,12 +246,12 @@ export const createClientField = ({
|
|||||||
|
|
||||||
if (incomingField.labels.singular) {
|
if (incomingField.labels.singular) {
|
||||||
if (typeof incomingField.labels.singular === 'function') {
|
if (typeof incomingField.labels.singular === 'function') {
|
||||||
field.labels.singular = incomingField.labels.singular({ t: i18n.t })
|
field.labels.singular = incomingField.labels.singular({ i18n, t: i18n.t })
|
||||||
} else {
|
} else {
|
||||||
field.labels.singular = incomingField.labels.singular
|
field.labels.singular = incomingField.labels.singular
|
||||||
}
|
}
|
||||||
if (typeof incomingField.labels.plural === 'function') {
|
if (typeof incomingField.labels.plural === 'function') {
|
||||||
field.labels.plural = incomingField.labels.plural({ t: i18n.t })
|
field.labels.plural = incomingField.labels.plural({ i18n, t: i18n.t })
|
||||||
} else {
|
} else {
|
||||||
field.labels.plural = incomingField.labels.plural
|
field.labels.plural = incomingField.labels.plural
|
||||||
}
|
}
|
||||||
@@ -287,12 +287,12 @@ export const createClientField = ({
|
|||||||
|
|
||||||
if (incomingField.labels.singular) {
|
if (incomingField.labels.singular) {
|
||||||
if (typeof incomingField.labels.singular === 'function') {
|
if (typeof incomingField.labels.singular === 'function') {
|
||||||
field.labels.singular = incomingField.labels.singular({ t: i18n.t })
|
field.labels.singular = incomingField.labels.singular({ i18n, t: i18n.t })
|
||||||
} else {
|
} else {
|
||||||
field.labels.singular = incomingField.labels.singular
|
field.labels.singular = incomingField.labels.singular
|
||||||
}
|
}
|
||||||
if (typeof incomingField.labels.plural === 'function') {
|
if (typeof incomingField.labels.plural === 'function') {
|
||||||
field.labels.plural = incomingField.labels.plural({ t: i18n.t })
|
field.labels.plural = incomingField.labels.plural({ i18n, t: i18n.t })
|
||||||
} else {
|
} else {
|
||||||
field.labels.plural = incomingField.labels.plural
|
field.labels.plural = incomingField.labels.plural
|
||||||
}
|
}
|
||||||
@@ -345,7 +345,7 @@ export const createClientField = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
field.options[i] = {
|
field.options[i] = {
|
||||||
label: option.label({ t: i18n.t }),
|
label: option.label({ i18n, t: i18n.t }),
|
||||||
value: option.value,
|
value: option.value,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -409,7 +409,7 @@ export const createClientField = ({
|
|||||||
case 'description':
|
case 'description':
|
||||||
if ('description' in tab.admin) {
|
if ('description' in tab.admin) {
|
||||||
if (typeof tab.admin?.description === 'function') {
|
if (typeof tab.admin?.description === 'function') {
|
||||||
clientTab.admin.description = tab.admin.description({ t: i18n.t })
|
clientTab.admin.description = tab.admin.description({ i18n, t: i18n.t })
|
||||||
} else {
|
} else {
|
||||||
clientTab.admin.description = tab.admin.description
|
clientTab.admin.description = tab.admin.description
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -447,6 +447,7 @@ export type OptionObject = {
|
|||||||
label: OptionLabel
|
label: OptionLabel
|
||||||
value: string
|
value: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export type Option = OptionObject | string
|
export type Option = OptionObject | string
|
||||||
|
|
||||||
export type FieldGraphQLType = {
|
export type FieldGraphQLType = {
|
||||||
|
|||||||
@@ -105,7 +105,7 @@ export const createClientGlobalConfig = ({
|
|||||||
break
|
break
|
||||||
case 'label':
|
case 'label':
|
||||||
clientGlobal.label =
|
clientGlobal.label =
|
||||||
typeof global.label === 'function' ? global.label({ t: i18n.t }) : global.label
|
typeof global.label === 'function' ? global.label({ i18n, t: i18n.t }) : global.label
|
||||||
break
|
break
|
||||||
default: {
|
default: {
|
||||||
clientGlobal[key] = global[key]
|
clientGlobal[key] = global[key]
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import type { LabelFunction, StaticLabel } from '../config/types.js'
|
|||||||
|
|
||||||
export const getTranslatedLabel = (label: LabelFunction | StaticLabel, i18n?: I18n): string => {
|
export const getTranslatedLabel = (label: LabelFunction | StaticLabel, i18n?: I18n): string => {
|
||||||
if (typeof label === 'function') {
|
if (typeof label === 'function') {
|
||||||
return label({ t: i18n.t })
|
return label({ i18n, t: i18n.t })
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof label === 'object') {
|
if (typeof label === 'object') {
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
import type { JSX } from 'react'
|
import type { JSX } from 'react'
|
||||||
|
|
||||||
import type { I18n, TFunction } from '../types.js'
|
import type { I18n, I18nClient, TFunction } from '../types.js'
|
||||||
|
|
||||||
type LabelType =
|
type LabelType =
|
||||||
| (() => JSX.Element)
|
| (() => JSX.Element)
|
||||||
| (({ t }: { t: TFunction }) => string)
|
| ((args: { i18n: I18nClient; t: TFunction }) => string)
|
||||||
| JSX.Element
|
| JSX.Element
|
||||||
| Record<string, string>
|
| Record<string, string>
|
||||||
| string
|
| string
|
||||||
@@ -35,7 +35,9 @@ export const getTranslation = <T extends LabelType>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (typeof label === 'function') {
|
if (typeof label === 'function') {
|
||||||
return label({ t: i18n.t }) as unknown as T extends JSX.Element ? JSX.Element : string
|
return label({ i18n: undefined as any, t: i18n.t }) as unknown as T extends JSX.Element
|
||||||
|
? JSX.Element
|
||||||
|
: string
|
||||||
}
|
}
|
||||||
|
|
||||||
// If it's a React Element or string, then we should just pass it through
|
// If it's a React Element or string, then we should just pass it through
|
||||||
|
|||||||
@@ -98,7 +98,7 @@ const TabsFieldComponent: TabsFieldClientComponent = (props) => {
|
|||||||
|
|
||||||
const activeTabStaticDescription =
|
const activeTabStaticDescription =
|
||||||
typeof activeTabDescription === 'function'
|
typeof activeTabDescription === 'function'
|
||||||
? activeTabDescription({ t: i18n.t })
|
? activeTabDescription({ i18n, t: i18n.t })
|
||||||
: activeTabDescription
|
: activeTabDescription
|
||||||
|
|
||||||
const hasVisibleTabs = tabStates.some(({ passesCondition }) => passesCondition)
|
const hasVisibleTabs = tabStates.some(({ passesCondition }) => passesCondition)
|
||||||
|
|||||||
@@ -244,6 +244,7 @@ export const renderField: RenderFieldMethod = ({
|
|||||||
fieldState.customComponents.Description = (
|
fieldState.customComponents.Description = (
|
||||||
<FieldDescription
|
<FieldDescription
|
||||||
description={fieldConfig.admin?.description({
|
description={fieldConfig.admin?.description({
|
||||||
|
i18n: req.i18n,
|
||||||
t: req.i18n.t,
|
t: req.i18n.t,
|
||||||
})}
|
})}
|
||||||
path={path}
|
path={path}
|
||||||
|
|||||||
@@ -53,7 +53,9 @@ export function groupNavItems(
|
|||||||
: entityToGroup.entity.label
|
: entityToGroup.entity.label
|
||||||
|
|
||||||
const label =
|
const label =
|
||||||
typeof labelOrFunction === 'function' ? labelOrFunction({ t: i18n.t }) : labelOrFunction
|
typeof labelOrFunction === 'function'
|
||||||
|
? labelOrFunction({ i18n, t: i18n.t })
|
||||||
|
: labelOrFunction
|
||||||
|
|
||||||
if (entityToGroup.entity.admin.group) {
|
if (entityToGroup.entity.admin.group) {
|
||||||
const existingGroup = groups.find(
|
const existingGroup = groups.find(
|
||||||
|
|||||||
Reference in New Issue
Block a user