Compare commits
49 Commits
v3.0.0-alp
...
v3.0.0-alp
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e9c7f9da92 | ||
|
|
0ce26d2c08 | ||
|
|
abf285d713 | ||
|
|
c2ee8e3999 | ||
|
|
167ba0c68f | ||
|
|
9ad1cbe920 | ||
|
|
313ea52e3d | ||
|
|
3acfb7a83f | ||
|
|
783dae2bbb | ||
|
|
59681b211b | ||
|
|
98438175cf | ||
|
|
af40302e5f | ||
|
|
ec0e0ae449 | ||
|
|
607ff17033 | ||
|
|
e73e610669 | ||
|
|
30fddde066 | ||
|
|
a56d2842fb | ||
|
|
35f59a47cc | ||
|
|
817d57bd12 | ||
|
|
5826048e7b | ||
|
|
1a975b31cf | ||
|
|
73298a80f0 | ||
|
|
a5d14ef4c1 | ||
|
|
d0c79b65f8 | ||
|
|
2fc50b1a1f | ||
|
|
0ddeedb0b3 | ||
|
|
09c2fb10f3 | ||
|
|
5bfff5b7ba | ||
|
|
702088375c | ||
|
|
ea507fbcc4 | ||
|
|
0ff1e6632b | ||
|
|
996ee47f96 | ||
|
|
3e9bd5bb62 | ||
|
|
ee7221c986 | ||
|
|
318c126ae3 | ||
|
|
2154aea89f | ||
|
|
4d3ad1af35 | ||
|
|
75cab7688f | ||
|
|
5084d6dd97 | ||
|
|
518f80cbb6 | ||
|
|
c9399efa65 | ||
|
|
d3016b7eb5 | ||
|
|
69e884f5b7 | ||
|
|
3e7925e33f | ||
|
|
7a2ccba63c | ||
|
|
be2134eb69 | ||
|
|
95e422b0e1 | ||
|
|
53d9c4ca95 | ||
|
|
30948ab545 |
7
.github/workflows/main.yml
vendored
7
.github/workflows/main.yml
vendored
@@ -221,8 +221,11 @@ jobs:
|
||||
- email
|
||||
- field-error-states
|
||||
- fields-relationship
|
||||
# - fields
|
||||
- fields/lexical
|
||||
- fields
|
||||
- fields__collections__Blocks
|
||||
- fields__collections__Array
|
||||
- fields__collections__Relationship
|
||||
- fields__collections__Lexical
|
||||
- live-preview
|
||||
- localization
|
||||
- plugin-form-builder
|
||||
|
||||
@@ -3,7 +3,7 @@ import type { Metadata } from 'next'
|
||||
|
||||
import config from '@payload-config'
|
||||
/* DO NOT MODIFY IT BECAUSE IT COULD BE REWRITTEN AT ANY TIME. */
|
||||
import { NotFoundPage, generatePageMetadata } from '@payloadcms/next/views/NotFound/index.js'
|
||||
import { NotFoundPage, generatePageMetadata } from '@payloadcms/next/views'
|
||||
|
||||
type Args = {
|
||||
params: {
|
||||
@@ -14,8 +14,8 @@ type Args = {
|
||||
}
|
||||
}
|
||||
|
||||
export const generateMetadata = ({ params }: Args): Promise<Metadata> =>
|
||||
generatePageMetadata({ config, params })
|
||||
export const generateMetadata = ({ params, searchParams }: Args): Promise<Metadata> =>
|
||||
generatePageMetadata({ config, params, searchParams })
|
||||
|
||||
const NotFound = ({ params, searchParams }: Args) => NotFoundPage({ config, params, searchParams })
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ import type { Metadata } from 'next'
|
||||
|
||||
import config from '@payload-config'
|
||||
/* DO NOT MODIFY IT BECAUSE IT COULD BE REWRITTEN AT ANY TIME. */
|
||||
import { RootPage, generatePageMetadata } from '@payloadcms/next/views/Root/index.js'
|
||||
import { RootPage, generatePageMetadata } from '@payloadcms/next/views'
|
||||
|
||||
type Args = {
|
||||
params: {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* THIS FILE WAS GENERATED AUTOMATICALLY BY PAYLOAD. */
|
||||
/* DO NOT MODIFY it because it could be re-written at any time. */
|
||||
import config from '@payload-config'
|
||||
import { REST_DELETE, REST_GET, REST_PATCH, REST_POST } from '@payloadcms/next/routes/index.js'
|
||||
import { REST_DELETE, REST_GET, REST_PATCH, REST_POST } from '@payloadcms/next/routes'
|
||||
|
||||
export const GET = REST_GET(config)
|
||||
export const POST = REST_POST(config)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* THIS FILE WAS GENERATED AUTOMATICALLY BY PAYLOAD. */
|
||||
/* DO NOT MODIFY it because it could be re-written at any time. */
|
||||
import config from '@payload-config'
|
||||
import { GRAPHQL_PLAYGROUND_GET } from '@payloadcms/next/routes/index.js'
|
||||
import { GRAPHQL_PLAYGROUND_GET } from '@payloadcms/next/routes'
|
||||
|
||||
export const GET = GRAPHQL_PLAYGROUND_GET(config)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* THIS FILE WAS GENERATED AUTOMATICALLY BY PAYLOAD. */
|
||||
/* DO NOT MODIFY it because it could be re-written at any time. */
|
||||
import config from '@payload-config'
|
||||
import { GRAPHQL_POST } from '@payloadcms/next/routes/index.js'
|
||||
import { GRAPHQL_POST } from '@payloadcms/next/routes'
|
||||
|
||||
export const POST = GRAPHQL_POST(config)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* THIS FILE WAS GENERATED AUTOMATICALLY BY PAYLOAD. */
|
||||
import configPromise from '@payload-config'
|
||||
import { RootLayout } from '@payloadcms/next/layouts/Root/index.js'
|
||||
import { RootLayout } from '@payloadcms/next/layouts'
|
||||
/* DO NOT MODIFY IT BECAUSE IT COULD BE REWRITTEN AT ANY TIME. */
|
||||
import React from 'react'
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "payload-monorepo",
|
||||
"version": "3.0.0-alpha.60",
|
||||
"version": "3.0.0-alpha.61",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"workspaces:": [
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "create-payload-app",
|
||||
"version": "3.0.0-alpha.60",
|
||||
"version": "3.0.0-alpha.61",
|
||||
"license": "MIT",
|
||||
"type": "module",
|
||||
"homepage": "https://payloadcms.com",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/db-mongodb",
|
||||
"version": "3.0.0-alpha.60",
|
||||
"version": "3.0.0-alpha.61",
|
||||
"description": "The officially supported MongoDB database adapter for Payload",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/db-postgres",
|
||||
"version": "3.0.0-alpha.60",
|
||||
"version": "3.0.0-alpha.61",
|
||||
"description": "The officially supported Postgres database adapter for Payload",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/graphql",
|
||||
"version": "3.0.0-alpha.60",
|
||||
"version": "3.0.0-alpha.61",
|
||||
"main": "./src/index.ts",
|
||||
"types": "./src/index.d.ts",
|
||||
"type": "module",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/next",
|
||||
"version": "3.0.0-alpha.60",
|
||||
"version": "3.0.0-alpha.61",
|
||||
"main": "./src/index.js",
|
||||
"types": "./src/index.js",
|
||||
"type": "module",
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
import type { AcceptedLanguages } from '@payloadcms/translations'
|
||||
import type { SanitizedConfig } from 'payload/types'
|
||||
|
||||
import { translations } from '@payloadcms/translations/client'
|
||||
import { rtlLanguages } from '@payloadcms/translations'
|
||||
import { initI18n } from '@payloadcms/translations'
|
||||
import { RootProvider } from '@payloadcms/ui/providers/Root'
|
||||
import '@payloadcms/ui/scss/app.scss'
|
||||
import { buildComponentMap } from '@payloadcms/ui/utilities/buildComponentMap'
|
||||
import { headers as getHeaders, cookies as nextCookies } from 'next/headers.js'
|
||||
import { parseCookies } from 'payload/auth'
|
||||
import { createClientConfig } from 'payload/config'
|
||||
import { deepMerge } from 'payload/utilities'
|
||||
import React from 'react'
|
||||
import 'react-toastify/dist/ReactToastify.css'
|
||||
|
||||
@@ -20,8 +21,6 @@ export const metadata = {
|
||||
title: 'Next.js',
|
||||
}
|
||||
|
||||
const rtlLanguages = ['ar', 'fa', 'ha', 'ku', 'ur', 'ps', 'dv', 'ks', 'khw', 'he', 'yi']
|
||||
|
||||
export const RootLayout = async ({
|
||||
children,
|
||||
config: configPromise,
|
||||
@@ -30,26 +29,36 @@ export const RootLayout = async ({
|
||||
config: Promise<SanitizedConfig>
|
||||
}) => {
|
||||
const config = await configPromise
|
||||
const clientConfig = await createClientConfig(config)
|
||||
|
||||
const headers = getHeaders()
|
||||
const cookies = parseCookies(headers)
|
||||
|
||||
const lang =
|
||||
getRequestLanguage({
|
||||
config,
|
||||
cookies,
|
||||
headers,
|
||||
}) ?? clientConfig.i18n.fallbackLanguage
|
||||
const languageCode = getRequestLanguage({
|
||||
config,
|
||||
cookies,
|
||||
headers,
|
||||
})
|
||||
|
||||
const dir = rtlLanguages.includes(lang) ? 'RTL' : 'LTR'
|
||||
const i18n = await initI18n({ config: config.i18n, context: 'client', language: languageCode })
|
||||
const clientConfig = await createClientConfig({ config, t: i18n.t })
|
||||
|
||||
const mergedTranslations = deepMerge(translations, clientConfig.i18n.translations)
|
||||
const dir = (rtlLanguages as unknown as AcceptedLanguages[]).includes(languageCode)
|
||||
? 'RTL'
|
||||
: 'LTR'
|
||||
|
||||
const languageOptions = Object.entries(translations || {}).map(([language, translations]) => ({
|
||||
label: translations.general.thisLanguage,
|
||||
value: language,
|
||||
}))
|
||||
const languageOptions = Object.entries(config.i18n.supportedLanguages || {}).reduce(
|
||||
(acc, [language, languageConfig]) => {
|
||||
if (Object.keys(config.i18n.supportedLanguages).includes(language)) {
|
||||
acc.push({
|
||||
label: languageConfig.translations.general.thisLanguage,
|
||||
value: language,
|
||||
})
|
||||
}
|
||||
|
||||
return acc
|
||||
},
|
||||
[],
|
||||
)
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/require-await
|
||||
async function switchLanguageServerAction(lang: string): Promise<void> {
|
||||
@@ -66,20 +75,22 @@ export const RootLayout = async ({
|
||||
DefaultListView,
|
||||
children,
|
||||
config,
|
||||
i18n,
|
||||
})
|
||||
|
||||
return (
|
||||
<html dir={dir} lang={lang}>
|
||||
<html dir={dir} lang={languageCode}>
|
||||
<body>
|
||||
<RootProvider
|
||||
componentMap={componentMap}
|
||||
config={clientConfig}
|
||||
dateFNSKey={i18n.dateFNSKey}
|
||||
fallbackLang={clientConfig.i18n.fallbackLanguage}
|
||||
lang={lang}
|
||||
languageCode={languageCode}
|
||||
languageOptions={languageOptions}
|
||||
// eslint-disable-next-line react/jsx-no-bind
|
||||
switchLanguageServerAction={switchLanguageServerAction}
|
||||
translations={mergedTranslations[lang]}
|
||||
translations={i18n.translations}
|
||||
>
|
||||
{wrappedChildren}
|
||||
</RootProvider>
|
||||
|
||||
@@ -1,11 +1,5 @@
|
||||
import type { BuildFormStateArgs } from '@payloadcms/ui/forms/buildStateFromSchema'
|
||||
import type {
|
||||
DocumentPreferences,
|
||||
Field,
|
||||
PayloadRequest,
|
||||
SanitizedConfig,
|
||||
TypeWithID,
|
||||
} from 'payload/types'
|
||||
import type { DocumentPreferences, Field, PayloadRequest, TypeWithID } from 'payload/types'
|
||||
|
||||
import { buildStateFromSchema } from '@payloadcms/ui/forms/buildStateFromSchema'
|
||||
import { reduceFieldsToValues } from '@payloadcms/ui/utilities/reduceFieldsToValues'
|
||||
@@ -22,12 +16,12 @@ if (!cached) {
|
||||
cached = global._payload_fieldSchemaMap = null
|
||||
}
|
||||
|
||||
export const getFieldSchemaMap = (config: SanitizedConfig): FieldSchemaMap => {
|
||||
export const getFieldSchemaMap = (req: PayloadRequest): FieldSchemaMap => {
|
||||
if (cached && process.env.NODE_ENV !== 'development') {
|
||||
return cached
|
||||
}
|
||||
|
||||
cached = buildFieldSchemaMap(config)
|
||||
cached = buildFieldSchemaMap(req)
|
||||
|
||||
return cached
|
||||
}
|
||||
@@ -65,7 +59,7 @@ export const buildFormState = async ({ req }: { req: PayloadRequest }) => {
|
||||
})
|
||||
}
|
||||
|
||||
const fieldSchemaMap = getFieldSchemaMap(req.payload.config)
|
||||
const fieldSchemaMap = getFieldSchemaMap(req)
|
||||
|
||||
const id = collectionSlug ? reqData.id : undefined
|
||||
const schemaPathSegments = schemaPath.split('.')
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
import type { SanitizedConfig } from 'payload/types'
|
||||
import type { PayloadRequest } from 'payload/types'
|
||||
|
||||
import type { FieldSchemaMap } from './types.js'
|
||||
|
||||
import { traverseFields } from './traverseFields.js'
|
||||
|
||||
export const buildFieldSchemaMap = (config: SanitizedConfig): FieldSchemaMap => {
|
||||
export const buildFieldSchemaMap = ({
|
||||
i18n,
|
||||
payload: { config },
|
||||
}: PayloadRequest): FieldSchemaMap => {
|
||||
const result: FieldSchemaMap = new Map()
|
||||
|
||||
const validRelationships = config.collections.map((c) => c.slug) || []
|
||||
@@ -13,6 +16,7 @@ export const buildFieldSchemaMap = (config: SanitizedConfig): FieldSchemaMap =>
|
||||
traverseFields({
|
||||
config,
|
||||
fields: collection.fields,
|
||||
i18n,
|
||||
schemaMap: result,
|
||||
schemaPath: collection.slug,
|
||||
validRelationships,
|
||||
@@ -23,6 +27,7 @@ export const buildFieldSchemaMap = (config: SanitizedConfig): FieldSchemaMap =>
|
||||
traverseFields({
|
||||
config,
|
||||
fields: global.fields,
|
||||
i18n,
|
||||
schemaMap: result,
|
||||
schemaPath: global.slug,
|
||||
validRelationships,
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import type { I18n } from '@payloadcms/translations'
|
||||
import type { Field, SanitizedConfig } from 'payload/types'
|
||||
|
||||
import { tabHasName } from 'payload/types'
|
||||
@@ -7,6 +8,7 @@ import type { FieldSchemaMap } from './types.js'
|
||||
type Args = {
|
||||
config: SanitizedConfig
|
||||
fields: Field[]
|
||||
i18n: I18n
|
||||
schemaMap: FieldSchemaMap
|
||||
schemaPath: string
|
||||
validRelationships: string[]
|
||||
@@ -15,6 +17,7 @@ type Args = {
|
||||
export const traverseFields = ({
|
||||
config,
|
||||
fields,
|
||||
i18n,
|
||||
schemaMap,
|
||||
schemaPath,
|
||||
validRelationships,
|
||||
@@ -28,6 +31,7 @@ export const traverseFields = ({
|
||||
traverseFields({
|
||||
config,
|
||||
fields: field.fields,
|
||||
i18n,
|
||||
schemaMap,
|
||||
schemaPath: `${schemaPath}.${field.name}`,
|
||||
validRelationships,
|
||||
@@ -39,6 +43,7 @@ export const traverseFields = ({
|
||||
traverseFields({
|
||||
config,
|
||||
fields: field.fields,
|
||||
i18n,
|
||||
schemaMap,
|
||||
schemaPath,
|
||||
validRelationships,
|
||||
@@ -54,6 +59,7 @@ export const traverseFields = ({
|
||||
traverseFields({
|
||||
config,
|
||||
fields: block.fields,
|
||||
i18n,
|
||||
schemaMap,
|
||||
schemaPath: blockSchemaPath,
|
||||
validRelationships,
|
||||
@@ -65,6 +71,7 @@ export const traverseFields = ({
|
||||
if (typeof field.editor.generateSchemaMap === 'function') {
|
||||
field.editor.generateSchemaMap({
|
||||
config,
|
||||
i18n,
|
||||
schemaMap,
|
||||
schemaPath: `${schemaPath}.${field.name}`,
|
||||
})
|
||||
@@ -83,6 +90,7 @@ export const traverseFields = ({
|
||||
traverseFields({
|
||||
config,
|
||||
fields: tab.fields,
|
||||
i18n,
|
||||
schemaMap,
|
||||
schemaPath: tabSchemaPath,
|
||||
validRelationships,
|
||||
|
||||
@@ -6,7 +6,6 @@ import type {
|
||||
} from 'payload/types'
|
||||
|
||||
import { initI18n } from '@payloadcms/translations'
|
||||
import { translations } from '@payloadcms/translations/api'
|
||||
import { executeAuthStrategies } from 'payload/auth'
|
||||
import { parseCookies } from 'payload/auth'
|
||||
import { getDataLoader } from 'payload/utilities'
|
||||
@@ -72,11 +71,10 @@ export const createPayloadRequest = async ({
|
||||
headers: request.headers,
|
||||
})
|
||||
|
||||
const i18n = initI18n({
|
||||
const i18n = await initI18n({
|
||||
config: config.i18n,
|
||||
context: 'api',
|
||||
language,
|
||||
translations,
|
||||
})
|
||||
|
||||
const customRequest: CustomPayloadRequest = {
|
||||
|
||||
@@ -1,22 +1,20 @@
|
||||
import type { I18n } from '@payloadcms/translations'
|
||||
import type { AcceptedLanguages, I18n } from '@payloadcms/translations'
|
||||
import type { SanitizedConfig } from 'payload/types'
|
||||
|
||||
import { initI18n } from '@payloadcms/translations'
|
||||
import { translations } from '@payloadcms/translations/client'
|
||||
import { cookies, headers } from 'next/headers.js'
|
||||
|
||||
import { getRequestLanguage } from './getRequestLanguage.js'
|
||||
|
||||
export const getNextI18n = ({
|
||||
export const getNextI18n = async ({
|
||||
config,
|
||||
language,
|
||||
}: {
|
||||
config: SanitizedConfig
|
||||
language?: string
|
||||
}): I18n =>
|
||||
language?: AcceptedLanguages
|
||||
}): Promise<I18n> =>
|
||||
initI18n({
|
||||
config: config.i18n,
|
||||
context: 'client',
|
||||
language: language || getRequestLanguage({ config, cookies: cookies(), headers: headers() }),
|
||||
translations,
|
||||
})
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import type { AcceptedLanguages } from '@payloadcms/translations'
|
||||
import type { ReadonlyRequestCookies } from 'next/dist/server/web/spec-extension/adapters/request-cookies.js'
|
||||
import type { SanitizedConfig } from 'payload/config'
|
||||
|
||||
@@ -6,7 +7,7 @@ import { matchLanguage } from '@payloadcms/translations'
|
||||
type GetRequestLanguageArgs = {
|
||||
config: SanitizedConfig
|
||||
cookies: Map<string, string> | ReadonlyRequestCookies
|
||||
defaultLanguage?: string
|
||||
defaultLanguage?: AcceptedLanguages
|
||||
headers: Request['headers']
|
||||
}
|
||||
|
||||
@@ -15,14 +16,15 @@ export const getRequestLanguage = ({
|
||||
cookies,
|
||||
defaultLanguage = 'en',
|
||||
headers,
|
||||
}: GetRequestLanguageArgs): string => {
|
||||
}: GetRequestLanguageArgs): AcceptedLanguages => {
|
||||
const acceptLanguage = headers.get('Accept-Language')
|
||||
const cookieLanguage = cookies.get(`${config.cookiePrefix || 'payload'}-lng`)
|
||||
|
||||
const reqLanguage =
|
||||
(typeof cookieLanguage === 'string' ? cookieLanguage : cookieLanguage?.value) ||
|
||||
acceptLanguage ||
|
||||
config.i18n.fallbackLanguage ||
|
||||
defaultLanguage
|
||||
|
||||
return matchLanguage(reqLanguage)
|
||||
return matchLanguage(reqLanguage) || defaultLanguage
|
||||
}
|
||||
|
||||
@@ -8,7 +8,6 @@ import type {
|
||||
} from 'payload/types'
|
||||
|
||||
import { initI18n } from '@payloadcms/translations'
|
||||
import { translations } from '@payloadcms/translations/client'
|
||||
import { findLocaleFromCode } from '@payloadcms/ui/utilities/findLocaleFromCode'
|
||||
import { headers as getHeaders } from 'next/headers.js'
|
||||
import { notFound, redirect } from 'next/navigation.js'
|
||||
@@ -45,14 +44,13 @@ export const initPage = async ({
|
||||
const cookies = parseCookies(headers)
|
||||
const language = getRequestLanguage({ config: payload.config, cookies, headers })
|
||||
|
||||
const i18n = initI18n({
|
||||
const i18n = await initI18n({
|
||||
config: payload.config.i18n,
|
||||
context: 'client',
|
||||
language,
|
||||
translations,
|
||||
})
|
||||
|
||||
const req = createLocalReq(
|
||||
const req = await createLocalReq(
|
||||
{
|
||||
fallbackLocale: null,
|
||||
locale: locale.code,
|
||||
|
||||
@@ -16,6 +16,7 @@ export const CreateFirstUserView: React.FC<AdminViewProps> = async ({ initPageRe
|
||||
const {
|
||||
req,
|
||||
req: {
|
||||
i18n,
|
||||
payload: {
|
||||
config,
|
||||
config: {
|
||||
@@ -51,6 +52,7 @@ export const CreateFirstUserView: React.FC<AdminViewProps> = async ({ initPageRe
|
||||
const createFirstUserFieldMap = mapFields({
|
||||
config,
|
||||
fieldSchema: fields,
|
||||
i18n,
|
||||
parentPath: userSlug,
|
||||
})
|
||||
|
||||
|
||||
@@ -117,7 +117,10 @@ export const ListView: React.FC<AdminViewProps> = async ({ initPageResult, searc
|
||||
<Fragment>
|
||||
<HydrateClientUser permissions={permissions} user={user} />
|
||||
<ListInfoProvider
|
||||
collectionConfig={createClientCollectionConfig(collectionConfig)}
|
||||
collectionConfig={createClientCollectionConfig({
|
||||
collection: collectionConfig,
|
||||
t: initPageResult.req.i18n.t,
|
||||
})}
|
||||
collectionSlug={collectionSlug}
|
||||
hasCreatePermission={permissions?.collections?.[collectionSlug]?.create?.permission}
|
||||
newDocumentURL={`${admin}/collections/${collectionSlug}/create`}
|
||||
|
||||
@@ -2,12 +2,12 @@ import type { I18n } from '@payloadcms/translations'
|
||||
import type { Metadata } from 'next'
|
||||
import type { AdminViewComponent, SanitizedConfig } from 'payload/types'
|
||||
|
||||
import { getNextI18n } from '@payloadcms/next/utilities'
|
||||
import { HydrateClientUser } from '@payloadcms/ui/elements/HydrateClientUser'
|
||||
import { DefaultTemplate } from '@payloadcms/ui/templates/Default'
|
||||
import React, { Fragment } from 'react'
|
||||
|
||||
import { initPage } from '../../utilities/initPage.js'
|
||||
import { getNextI18n } from '.././../utilities/getNextI18n.js'
|
||||
import { NotFoundClient } from './index.client.js'
|
||||
|
||||
export const generatePageMetadata = async ({
|
||||
@@ -19,7 +19,7 @@ export const generatePageMetadata = async ({
|
||||
}): Promise<Metadata> => {
|
||||
const config = await configPromise
|
||||
|
||||
const i18n = getNextI18n({
|
||||
const i18n = await getNextI18n({
|
||||
config,
|
||||
})
|
||||
|
||||
|
||||
@@ -49,7 +49,7 @@ export const generatePageMetadata = async ({ config: configPromise, params }: Ar
|
||||
const isGlobal = segmentOne === 'globals'
|
||||
const isCollection = segmentOne === 'collections'
|
||||
|
||||
const i18n = getNextI18n({
|
||||
const i18n = await getNextI18n({
|
||||
config,
|
||||
})
|
||||
|
||||
|
||||
@@ -85,7 +85,9 @@ export const SetStepNav: React.FC<{
|
||||
url: `${adminRoute}/collections/${collectionSlug}/${id}/versions`,
|
||||
},
|
||||
{
|
||||
label: doc?.createdAt ? formatDate(doc.createdAt, dateFormat, i18n?.language) : '',
|
||||
label: doc?.createdAt
|
||||
? formatDate({ date: doc.createdAt, i18n, pattern: dateFormat })
|
||||
: '',
|
||||
},
|
||||
]
|
||||
}
|
||||
@@ -101,7 +103,9 @@ export const SetStepNav: React.FC<{
|
||||
url: `${adminRoute}/globals/${globalConfig.slug}/versions`,
|
||||
},
|
||||
{
|
||||
label: doc?.createdAt ? formatDate(doc.createdAt, dateFormat, i18n?.language) : '',
|
||||
label: doc?.createdAt
|
||||
? formatDate({ date: doc.createdAt, i18n, pattern: dateFormat })
|
||||
: '',
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
@@ -61,7 +61,7 @@ export const DefaultVersionView: React.FC<DefaultVersionsViewProps> = ({
|
||||
} = config
|
||||
|
||||
const formattedCreatedAt = doc?.createdAt
|
||||
? formatDate(doc.createdAt, dateFormat, i18n.language)
|
||||
? formatDate({ date: doc.createdAt, i18n, pattern: dateFormat })
|
||||
: ''
|
||||
|
||||
const originalDocFetchURL = `${serverURL}${apiRoute}/${globalSlug ? 'globals/' : ''}${
|
||||
|
||||
@@ -88,7 +88,7 @@ export const SelectComparison: React.FC<Props> = (props) => {
|
||||
setOptions((existingOptions) => [
|
||||
...existingOptions,
|
||||
...data.docs.map((doc) => ({
|
||||
label: formatDate(doc.updatedAt, dateFormat, i18n.language),
|
||||
label: formatDate({ date: doc.updatedAt, i18n, pattern: dateFormat }),
|
||||
value: doc.id,
|
||||
})),
|
||||
])
|
||||
|
||||
@@ -22,7 +22,7 @@ export const generateMetadata: GenerateEditViewMetadata = async ({
|
||||
const doc: any = {} // TODO: figure this out
|
||||
|
||||
const formattedCreatedAt = doc?.createdAt
|
||||
? formatDate(doc.createdAt, config?.admin?.dateFormat, i18n?.language)
|
||||
? formatDate({ date: doc.createdAt, i18n, pattern: config?.admin?.dateFormat })
|
||||
: ''
|
||||
|
||||
if (collectionConfig) {
|
||||
|
||||
@@ -38,7 +38,8 @@ export const CreatedAtCell: React.FC<CreatedAtCellProps> = ({
|
||||
|
||||
return (
|
||||
<Link href={to}>
|
||||
{cellData && formatDate(cellData as Date | number | string, dateFormat, i18n.language)}
|
||||
{cellData &&
|
||||
formatDate({ date: cellData as Date | number | string, i18n, pattern: dateFormat })}
|
||||
</Link>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "payload",
|
||||
"version": "3.0.0-alpha.60",
|
||||
"version": "3.0.0-alpha.61",
|
||||
"description": "Node, React and MongoDB Headless CMS and Application Framework",
|
||||
"license": "MIT",
|
||||
"main": "./src/index.ts",
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import type { I18n } from '@payloadcms/translations'
|
||||
import type { JSONSchema4 } from 'json-schema'
|
||||
|
||||
import type { SanitizedConfig } from '../config/types.js'
|
||||
@@ -28,10 +29,12 @@ type RichTextAdapterBase<
|
||||
}) => Promise<void> | null
|
||||
generateComponentMap: (args: {
|
||||
config: SanitizedConfig
|
||||
i18n: I18n
|
||||
schemaPath: string
|
||||
}) => Map<string, React.ReactNode>
|
||||
generateSchemaMap?: (args: {
|
||||
config: SanitizedConfig
|
||||
i18n: I18n
|
||||
schemaMap: Map<string, Field[]>
|
||||
schemaPath: string
|
||||
}) => Map<string, Field[]>
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import type React from 'react'
|
||||
|
||||
export type DescriptionFunction = () => string
|
||||
import type { LabelFunction } from '../../config/types.js'
|
||||
|
||||
export type DescriptionFunction = LabelFunction
|
||||
|
||||
export type DescriptionComponent = React.ComponentType<FieldDescriptionProps>
|
||||
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
import type { LabelFunction } from '../../config/types.js'
|
||||
|
||||
export type LabelProps = {
|
||||
CustomLabel?: React.ReactNode
|
||||
as?: 'label' | 'span'
|
||||
htmlFor?: string
|
||||
label?: Record<string, string> | false | string
|
||||
label?: LabelFunction | Record<string, string> | false | string
|
||||
required?: boolean
|
||||
unstyled?: boolean
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { Translations } from '@payloadcms/translations'
|
||||
import type { SupportedLanguages } from '@payloadcms/translations'
|
||||
|
||||
import type { Permissions } from '../../auth/index.js'
|
||||
import type { SanitizedCollectionConfig } from '../../collections/config/types.js'
|
||||
@@ -43,7 +43,7 @@ export type InitPageResult = {
|
||||
locale: Locale
|
||||
permissions: Permissions
|
||||
req: PayloadRequest
|
||||
translations: Translations
|
||||
translations: SupportedLanguages
|
||||
visibleEntities: VisibleEntities
|
||||
}
|
||||
|
||||
|
||||
@@ -2,15 +2,12 @@ import crypto from 'crypto'
|
||||
|
||||
import type { Field, FieldHook } from '../../fields/config/types.js'
|
||||
|
||||
import { extractTranslations } from '../../translations/extractTranslations.js'
|
||||
|
||||
const labels = extractTranslations(['authentication:enableAPIKey', 'authentication:apiKey'])
|
||||
|
||||
const encryptKey: FieldHook = ({ req, value }) =>
|
||||
value ? req.payload.encrypt(value as string) : null
|
||||
const decryptKey: FieldHook = ({ req, value }) =>
|
||||
value ? req.payload.decrypt(value as string) : undefined
|
||||
|
||||
// eslint-disable-next-line no-restricted-exports
|
||||
export default [
|
||||
{
|
||||
name: 'enableAPIKey',
|
||||
@@ -21,7 +18,7 @@ export default [
|
||||
},
|
||||
},
|
||||
defaultValue: false,
|
||||
label: labels['authentication:enableAPIKey'],
|
||||
label: ({ t }) => t('authentication:enableAPIKey'),
|
||||
},
|
||||
{
|
||||
name: 'apiKey',
|
||||
@@ -35,7 +32,7 @@ export default [
|
||||
afterRead: [decryptKey],
|
||||
beforeChange: [encryptKey],
|
||||
},
|
||||
label: labels['authentication:apiKey'],
|
||||
label: ({ t }) => t('authentication:apiKey'),
|
||||
},
|
||||
{
|
||||
name: 'apiKeyIndex',
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
import type { Field } from '../../fields/config/types.js'
|
||||
|
||||
import { email } from '../../fields/validations.js'
|
||||
import { extractTranslations } from '../../translations/extractTranslations.js'
|
||||
|
||||
const labels = extractTranslations(['general:email'])
|
||||
|
||||
const baseAuthFields: Field[] = [
|
||||
{
|
||||
@@ -14,7 +11,7 @@ const baseAuthFields: Field[] = [
|
||||
Field: () => null,
|
||||
},
|
||||
},
|
||||
label: labels['general:email'],
|
||||
label: ({ t }) => t('general:email'),
|
||||
required: true,
|
||||
unique: true,
|
||||
validate: email,
|
||||
|
||||
@@ -1,9 +1,5 @@
|
||||
import type { Field, FieldHook } from '../../fields/config/types.js'
|
||||
|
||||
import { extractTranslations } from '../../translations/extractTranslations.js'
|
||||
|
||||
const labels = extractTranslations(['authentication:verified'])
|
||||
|
||||
const autoRemoveVerificationToken: FieldHook = ({ data, operation, originalDoc, value }) => {
|
||||
// If a user manually sets `_verified` to true,
|
||||
// and it was `false`, set _verificationToken to `null`.
|
||||
@@ -33,7 +29,7 @@ export default [
|
||||
Field: () => null,
|
||||
},
|
||||
},
|
||||
label: labels['authentication:verified'],
|
||||
label: ({ t }) => t('authentication:verified'),
|
||||
},
|
||||
{
|
||||
name: '_verificationToken',
|
||||
|
||||
@@ -1,9 +1,5 @@
|
||||
import type { CollectionConfig } from '../collections/config/types.js'
|
||||
|
||||
import { extractTranslations } from '../translations/extractTranslations.js'
|
||||
|
||||
const labels = extractTranslations(['general:user', 'general:users'])
|
||||
|
||||
export const defaultUserCollection: CollectionConfig = {
|
||||
slug: 'users',
|
||||
admin: {
|
||||
@@ -14,7 +10,7 @@ export const defaultUserCollection: CollectionConfig = {
|
||||
},
|
||||
fields: [],
|
||||
labels: {
|
||||
plural: labels['general:users'],
|
||||
singular: labels['general:user'],
|
||||
plural: ({ t }) => t('general:users'),
|
||||
singular: ({ t }) => t('general:user'),
|
||||
},
|
||||
}
|
||||
|
||||
@@ -10,6 +10,6 @@ export const auth = async (payload: Payload, options: AuthArgs): Promise<AuthRes
|
||||
|
||||
return await authOperation({
|
||||
headers,
|
||||
req: createLocalReq({ req: options.req as PayloadRequest }, payload),
|
||||
req: await createLocalReq({ req: options.req as PayloadRequest }, payload),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -78,7 +78,6 @@ export const resolve: ResolveFn = async (specifier, context, nextResolve) => {
|
||||
// and keep going
|
||||
let nextResult: ResolveResult
|
||||
|
||||
// First, try to
|
||||
if (!isTS) {
|
||||
try {
|
||||
nextResult = await nextResolve(specifier, context, nextResolve)
|
||||
|
||||
@@ -23,14 +23,22 @@ export type ClientCollectionConfig = Omit<
|
||||
fields: ClientFieldConfig[]
|
||||
}
|
||||
|
||||
import type { TFunction } from '@payloadcms/translations'
|
||||
|
||||
import type { ClientFieldConfig } from '../../fields/config/client.js'
|
||||
import type { SanitizedCollectionConfig } from './types.js'
|
||||
|
||||
import { createClientFieldConfigs } from '../../fields/config/client.js'
|
||||
|
||||
export const createClientCollectionConfig = (collection: SanitizedCollectionConfig) => {
|
||||
export const createClientCollectionConfig = ({
|
||||
collection,
|
||||
t,
|
||||
}: {
|
||||
collection: SanitizedCollectionConfig
|
||||
t: TFunction
|
||||
}) => {
|
||||
const sanitized = { ...collection }
|
||||
sanitized.fields = createClientFieldConfigs(sanitized.fields)
|
||||
sanitized.fields = createClientFieldConfigs({ fields: sanitized.fields, t })
|
||||
|
||||
const serverOnlyCollectionProperties: Partial<ServerOnlyCollectionProperties>[] = [
|
||||
'hooks',
|
||||
@@ -60,6 +68,14 @@ export const createClientCollectionConfig = (collection: SanitizedCollectionConf
|
||||
delete sanitized.auth.verify
|
||||
}
|
||||
|
||||
if (sanitized.labels) {
|
||||
Object.entries(sanitized.labels).forEach(([labelType, collectionLabel]) => {
|
||||
if (typeof collectionLabel === 'function') {
|
||||
sanitized.labels[labelType] = collectionLabel({ t })
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
if ('admin' in sanitized) {
|
||||
sanitized.admin = { ...sanitized.admin }
|
||||
|
||||
@@ -85,7 +101,11 @@ export const createClientCollectionConfig = (collection: SanitizedCollectionConf
|
||||
return sanitized
|
||||
}
|
||||
|
||||
export const createClientCollectionConfigs = (
|
||||
collections: SanitizedCollectionConfig[],
|
||||
): ClientCollectionConfig[] =>
|
||||
collections.map((collection) => createClientCollectionConfig(collection))
|
||||
export const createClientCollectionConfigs = ({
|
||||
collections,
|
||||
t,
|
||||
}: {
|
||||
collections: SanitizedCollectionConfig[]
|
||||
t: TFunction
|
||||
}): ClientCollectionConfig[] =>
|
||||
collections.map((collection) => createClientCollectionConfig({ collection, t }))
|
||||
|
||||
@@ -11,15 +11,12 @@ import TimestampsRequired from '../../errors/TimestampsRequired.js'
|
||||
import { sanitizeFields } from '../../fields/config/sanitize.js'
|
||||
import { fieldAffectsData } from '../../fields/config/types.js'
|
||||
import mergeBaseFields from '../../fields/mergeBaseFields.js'
|
||||
import { extractTranslations } from '../../translations/extractTranslations.js'
|
||||
import { getBaseUploadFields } from '../../uploads/getBaseFields.js'
|
||||
import { formatLabels } from '../../utilities/formatLabels.js'
|
||||
import { isPlainObject } from '../../utilities/isPlainObject.js'
|
||||
import baseVersionFields from '../../versions/baseFields.js'
|
||||
import { authDefaults, defaults } from './defaults.js'
|
||||
|
||||
const translations = extractTranslations(['general:createdAt', 'general:updatedAt'])
|
||||
|
||||
const sanitizeCollection = (
|
||||
config: Config,
|
||||
collection: CollectionConfig,
|
||||
@@ -51,7 +48,7 @@ const sanitizeCollection = (
|
||||
disableBulkEdit: true,
|
||||
hidden: true,
|
||||
},
|
||||
label: translations['general:updatedAt'],
|
||||
label: ({ t }) => t('general:updatedAt'),
|
||||
})
|
||||
}
|
||||
if (!hasCreatedAt) {
|
||||
@@ -64,7 +61,7 @@ const sanitizeCollection = (
|
||||
// The default sort for list view is createdAt. Thus, enabling indexing by default, is a major performance improvement, especially for large or a large amount of collections.
|
||||
type: 'date',
|
||||
index: true,
|
||||
label: translations['general:createdAt'],
|
||||
label: ({ t }) => t('general:createdAt'),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -140,10 +140,10 @@ const collectionSchema = joi.object().keys({
|
||||
labels: joi.object({
|
||||
plural: joi
|
||||
.alternatives()
|
||||
.try(joi.string(), joi.object().pattern(joi.string(), [joi.string()])),
|
||||
.try(joi.func(), joi.string(), joi.object().pattern(joi.string(), [joi.string()])),
|
||||
singular: joi
|
||||
.alternatives()
|
||||
.try(joi.string(), joi.object().pattern(joi.string(), [joi.string()])),
|
||||
.try(joi.func(), joi.string(), joi.object().pattern(joi.string(), [joi.string()])),
|
||||
}),
|
||||
timestamps: joi.boolean(),
|
||||
typescript: joi.object().keys({
|
||||
|
||||
@@ -14,6 +14,7 @@ import type {
|
||||
Endpoint,
|
||||
EntityDescription,
|
||||
GeneratePreviewURL,
|
||||
LabelFunction,
|
||||
LivePreviewConfig,
|
||||
} from '../../config/types.js'
|
||||
import type { Field } from '../../fields/config/types.js'
|
||||
@@ -360,8 +361,8 @@ export type CollectionConfig = {
|
||||
* Label configuration
|
||||
*/
|
||||
labels?: {
|
||||
plural?: Record<string, string> | string
|
||||
singular?: Record<string, string> | string
|
||||
plural?: LabelFunction | Record<string, string> | string
|
||||
singular?: LabelFunction | Record<string, string> | string
|
||||
}
|
||||
slug: string
|
||||
/**
|
||||
|
||||
@@ -34,6 +34,7 @@ export type Options<TSlug extends keyof GeneratedTypes['collections']> = {
|
||||
user?: Document
|
||||
}
|
||||
|
||||
// eslint-disable-next-line no-restricted-exports
|
||||
export default async function createLocal<TSlug extends keyof GeneratedTypes['collections']>(
|
||||
payload: Payload,
|
||||
options: Options<TSlug>,
|
||||
@@ -58,7 +59,7 @@ export default async function createLocal<TSlug extends keyof GeneratedTypes['co
|
||||
)
|
||||
}
|
||||
|
||||
const req = createLocalReq(options, payload)
|
||||
const req = await createLocalReq(options, payload)
|
||||
req.file = file ?? (await getFileByPath(filePath))
|
||||
|
||||
return createOperation<TSlug>({
|
||||
|
||||
@@ -50,7 +50,7 @@ export async function duplicate<TSlug extends keyof GeneratedTypes['collections'
|
||||
)
|
||||
}
|
||||
|
||||
const req = createLocalReq(options, payload)
|
||||
const req = await createLocalReq(options, payload)
|
||||
|
||||
return duplicateOperation<TSlug>({
|
||||
id,
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import type { TFunction } from '@payloadcms/translations'
|
||||
|
||||
import type { ClientCollectionConfig } from '../collections/config/client.js'
|
||||
import type { SanitizedCollectionConfig } from '../collections/config/types.js'
|
||||
import type { ClientGlobalConfig } from '../globals/config/client.js'
|
||||
@@ -41,10 +43,13 @@ export type ClientConfig = Omit<
|
||||
globals: ClientGlobalConfig[]
|
||||
}
|
||||
|
||||
export const createClientConfig = async (
|
||||
configPromise: Promise<SanitizedConfig> | SanitizedConfig,
|
||||
): Promise<ClientConfig> => {
|
||||
const config = await configPromise
|
||||
export const createClientConfig = async ({
|
||||
config,
|
||||
t,
|
||||
}: {
|
||||
config: SanitizedConfig
|
||||
t: TFunction
|
||||
}): Promise<ClientConfig> => {
|
||||
const clientConfig: ClientConfig = { ...config }
|
||||
|
||||
const serverOnlyConfigProperties: Partial<ServerOnlyRootProperties>[] = [
|
||||
@@ -95,11 +100,15 @@ export const createClientConfig = async (
|
||||
}
|
||||
}
|
||||
|
||||
clientConfig.collections = createClientCollectionConfigs(
|
||||
clientConfig.collections as SanitizedCollectionConfig[],
|
||||
)
|
||||
clientConfig.collections = createClientCollectionConfigs({
|
||||
collections: clientConfig.collections as SanitizedCollectionConfig[],
|
||||
t,
|
||||
})
|
||||
|
||||
clientConfig.globals = createClientGlobalConfigs(clientConfig.globals as SanitizedGlobalConfig[])
|
||||
clientConfig.globals = createClientGlobalConfigs({
|
||||
globals: clientConfig.globals as SanitizedGlobalConfig[],
|
||||
t,
|
||||
})
|
||||
|
||||
return clientConfig
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { translations } from '@payloadcms/translations/api'
|
||||
import { en } from '@payloadcms/translations/languages/en'
|
||||
import merge from 'deepmerge'
|
||||
|
||||
import type {
|
||||
@@ -87,8 +87,10 @@ export const sanitizeConfig = (incomingConfig: Config): SanitizedConfig => {
|
||||
|
||||
config.i18n = {
|
||||
fallbackLanguage: 'en',
|
||||
supportedLanguages: Object.keys(translations),
|
||||
translations,
|
||||
supportedLanguages: {
|
||||
en,
|
||||
},
|
||||
translations: {},
|
||||
...(incomingConfig?.i18n ?? {}),
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { I18nOptions } from '@payloadcms/translations'
|
||||
import type { I18nOptions, TFunction } from '@payloadcms/translations'
|
||||
import type { Options as ExpressFileUploadOptions } from 'express-fileupload'
|
||||
import type GraphQL from 'graphql'
|
||||
import type { Transporter } from 'nodemailer'
|
||||
@@ -363,6 +363,8 @@ export type LocalizationConfig = Prettify<
|
||||
LocalizationConfigWithLabels | LocalizationConfigWithNoLabels
|
||||
>
|
||||
|
||||
export type LabelFunction = ({ t }: { t: TFunction }) => string
|
||||
|
||||
export type SharpDependency = (
|
||||
input?:
|
||||
| ArrayBuffer
|
||||
@@ -671,11 +673,12 @@ export type Config = {
|
||||
|
||||
export type SanitizedConfig = Omit<
|
||||
DeepRequired<Config>,
|
||||
'collections' | 'endpoint' | 'globals' | 'localization'
|
||||
'collections' | 'endpoint' | 'globals' | 'i18n' | 'localization'
|
||||
> & {
|
||||
collections: SanitizedCollectionConfig[]
|
||||
endpoints: Endpoint[]
|
||||
globals: SanitizedGlobalConfig[]
|
||||
i18n: Required<I18nOptions>
|
||||
localization: SanitizedLocalizationConfig | false
|
||||
paths: {
|
||||
config: string
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { TFunction } from '@payloadcms/translations'
|
||||
|
||||
import { translations } from '@payloadcms/translations/api'
|
||||
import { en } from '@payloadcms/translations/languages/en'
|
||||
import httpStatus from 'http-status'
|
||||
|
||||
import APIError from './APIError.js'
|
||||
@@ -8,7 +8,7 @@ import APIError from './APIError.js'
|
||||
class AuthenticationError extends APIError {
|
||||
constructor(t?: TFunction) {
|
||||
super(
|
||||
t ? t('error:emailOrPasswordIncorrect') : translations.en.error.emailOrPasswordIncorrect,
|
||||
t ? t('error:emailOrPasswordIncorrect') : en.translations.error.emailOrPasswordIncorrect,
|
||||
httpStatus.UNAUTHORIZED,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { TFunction } from '@payloadcms/translations'
|
||||
|
||||
import { translations } from '@payloadcms/translations/api'
|
||||
import { en } from '@payloadcms/translations/languages/en'
|
||||
import httpStatus from 'http-status'
|
||||
|
||||
import APIError from './APIError.js'
|
||||
@@ -8,7 +8,7 @@ import APIError from './APIError.js'
|
||||
class ErrorDeletingFile extends APIError {
|
||||
constructor(t?: TFunction) {
|
||||
super(
|
||||
t ? t('error:deletingFile') : translations.en.error.deletingFile,
|
||||
t ? t('error:deletingFile') : en.translations.error.deletingFile,
|
||||
httpStatus.INTERNAL_SERVER_ERROR,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { TFunction } from '@payloadcms/translations'
|
||||
|
||||
import { translations } from '@payloadcms/translations/api'
|
||||
import { en } from '@payloadcms/translations/languages/en'
|
||||
import httpStatus from 'http-status'
|
||||
|
||||
import APIError from './APIError.js'
|
||||
@@ -8,7 +8,7 @@ import APIError from './APIError.js'
|
||||
class FileUploadError extends APIError {
|
||||
constructor(t?: TFunction) {
|
||||
super(
|
||||
t ? t('error:problemUploadingFile') : translations.en.error.problemUploadingFile,
|
||||
t ? t('error:problemUploadingFile') : en.translations.error.problemUploadingFile,
|
||||
httpStatus.BAD_REQUEST,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { TFunction } from '@payloadcms/translations'
|
||||
|
||||
import { translations } from '@payloadcms/translations/api'
|
||||
import { en } from '@payloadcms/translations/languages/en'
|
||||
import httpStatus from 'http-status'
|
||||
|
||||
import APIError from './APIError.js'
|
||||
@@ -8,7 +8,7 @@ import APIError from './APIError.js'
|
||||
class Forbidden extends APIError {
|
||||
constructor(t?: TFunction) {
|
||||
super(
|
||||
t ? t('error:notAllowedToPerformAction') : translations.en.error.notAllowedToPerformAction,
|
||||
t ? t('error:notAllowedToPerformAction') : en.translations.error.notAllowedToPerformAction,
|
||||
httpStatus.FORBIDDEN,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import type { TFunction } from '@payloadcms/translations'
|
||||
|
||||
import { translations } from '@payloadcms/translations/api'
|
||||
import { en } from '@payloadcms/translations/languages/en'
|
||||
import httpStatus from 'http-status'
|
||||
|
||||
import APIError from './APIError.js'
|
||||
|
||||
class LockedAuth extends APIError {
|
||||
constructor(t?: TFunction) {
|
||||
super(t ? t('error:userLocked') : translations.en.error.userLocked, httpStatus.UNAUTHORIZED)
|
||||
super(t ? t('error:userLocked') : en.translations.error.userLocked, httpStatus.UNAUTHORIZED)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { TFunction } from '@payloadcms/translations'
|
||||
|
||||
import { translations } from '@payloadcms/translations/api'
|
||||
import { en } from '@payloadcms/translations/languages/en'
|
||||
import httpStatus from 'http-status'
|
||||
|
||||
import APIError from './APIError.js'
|
||||
@@ -8,7 +8,7 @@ import APIError from './APIError.js'
|
||||
class MissingFile extends APIError {
|
||||
constructor(t?: TFunction) {
|
||||
super(
|
||||
t ? t('error:noFilesUploaded') : translations.en.error.noFilesUploaded,
|
||||
t ? t('error:noFilesUploaded') : en.translations.error.noFilesUploaded,
|
||||
httpStatus.BAD_REQUEST,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import type { TFunction } from '@payloadcms/translations'
|
||||
|
||||
import { translations } from '@payloadcms/translations/api'
|
||||
import { en } from '@payloadcms/translations/languages/en'
|
||||
import httpStatus from 'http-status'
|
||||
|
||||
import APIError from './APIError.js'
|
||||
|
||||
class NotFound extends APIError {
|
||||
constructor(t?: TFunction) {
|
||||
super(t ? t('general:notFound') : translations.en.general.notFound, httpStatus.NOT_FOUND)
|
||||
super(t ? t('general:notFound') : en.translations.general.notFound, httpStatus.NOT_FOUND)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import type { TFunction } from '@payloadcms/translations'
|
||||
|
||||
import { translations } from '@payloadcms/translations/api'
|
||||
import { en } from '@payloadcms/translations/languages/en'
|
||||
import httpStatus from 'http-status'
|
||||
|
||||
import APIError from './APIError.js'
|
||||
|
||||
class UnauthorizedError extends APIError {
|
||||
constructor(t?: TFunction) {
|
||||
super(t ? t('error:unauthorized') : translations.en.error.unauthorized, httpStatus.UNAUTHORIZED)
|
||||
super(t ? t('error:unauthorized') : en.translations.error.unauthorized, httpStatus.UNAUTHORIZED)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { TFunction } from '@payloadcms/translations'
|
||||
|
||||
import { translations } from '@payloadcms/translations/api'
|
||||
import { en } from '@payloadcms/translations/languages/en'
|
||||
import httpStatus from 'http-status'
|
||||
|
||||
import APIError from './APIError.js'
|
||||
@@ -10,8 +10,8 @@ class ValidationError extends APIError<{ field: string; message: string }[]> {
|
||||
const message = t
|
||||
? t('error:followingFieldsInvalid', { count: results.length })
|
||||
: results.length === 1
|
||||
? translations.en.error.followingFieldsInvalid_one
|
||||
: translations.en.error.followingFieldsInvalid_other
|
||||
? en.translations.error.followingFieldsInvalid_one
|
||||
: en.translations.error.followingFieldsInvalid_other
|
||||
|
||||
super(`${message} ${results.map((f) => f.field).join(', ')}`, httpStatus.BAD_REQUEST, results)
|
||||
}
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
export { generateTypes } from '../bin/generateTypes.js'
|
||||
export { importConfig, importWithoutClientFiles } from '../utilities/importWithoutClientFiles.js'
|
||||
|
||||
@@ -2,7 +2,6 @@ export { getDataLoader } from '../collections/dataloader.js'
|
||||
export { default as getDefaultValue } from '../fields/getDefaultValue.js'
|
||||
export { promise as afterReadPromise } from '../fields/hooks/afterRead/promise.js'
|
||||
export { traverseFields as afterReadTraverseFields } from '../fields/hooks/afterRead/traverseFields.js'
|
||||
export { extractTranslations } from '../translations/extractTranslations.js'
|
||||
|
||||
export { formatFilesize } from '../uploads/formatFilesize.js'
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import type { TFunction } from '@payloadcms/translations'
|
||||
|
||||
import type { Field, FieldBase } from '../../fields/config/types.js'
|
||||
|
||||
export type ClientFieldConfig = Omit<Field, 'access' | 'defaultValue' | 'hooks' | 'validate'>
|
||||
@@ -13,8 +15,14 @@ export type ServerOnlyFieldAdminProperties = keyof Pick<
|
||||
'components' | 'condition' | 'description'
|
||||
>
|
||||
|
||||
export const createClientFieldConfig = (f: Field) => {
|
||||
const field = { ...f }
|
||||
export const createClientFieldConfig = ({
|
||||
field: incomingField,
|
||||
t,
|
||||
}: {
|
||||
field: Field
|
||||
t: TFunction
|
||||
}) => {
|
||||
const field = { ...incomingField }
|
||||
|
||||
const serverOnlyFieldProperties: Partial<ServerOnlyFieldProperties>[] = [
|
||||
'hooks',
|
||||
@@ -37,21 +45,34 @@ export const createClientFieldConfig = (f: Field) => {
|
||||
}
|
||||
})
|
||||
|
||||
if ('options' in field && Array.isArray(field.options)) {
|
||||
field.options = field.options.map((option) => {
|
||||
if (typeof option === 'object' && typeof option.label === 'function') {
|
||||
return {
|
||||
label: option.label({ t }),
|
||||
value: option.value,
|
||||
}
|
||||
}
|
||||
|
||||
return option
|
||||
})
|
||||
}
|
||||
|
||||
if ('fields' in field) {
|
||||
field.fields = createClientFieldConfigs(field.fields)
|
||||
field.fields = createClientFieldConfigs({ fields: field.fields, t })
|
||||
}
|
||||
|
||||
if ('blocks' in field) {
|
||||
field.blocks = field.blocks.map((block) => {
|
||||
const sanitized = { ...block }
|
||||
sanitized.fields = createClientFieldConfigs(sanitized.fields)
|
||||
sanitized.fields = createClientFieldConfigs({ fields: sanitized.fields, t })
|
||||
return sanitized
|
||||
})
|
||||
}
|
||||
|
||||
if ('tabs' in field) {
|
||||
// @ts-expect-error
|
||||
field.tabs = field.tabs.map((tab) => createClientFieldConfig(tab))
|
||||
field.tabs = field.tabs.map((tab) => createClientFieldConfig({ field: tab, t }))
|
||||
}
|
||||
|
||||
if ('admin' in field) {
|
||||
@@ -73,5 +94,10 @@ export const createClientFieldConfig = (f: Field) => {
|
||||
return field
|
||||
}
|
||||
|
||||
export const createClientFieldConfigs = (fields: Field[]): Field[] =>
|
||||
fields.map(createClientFieldConfig)
|
||||
export const createClientFieldConfigs = ({
|
||||
fields,
|
||||
t,
|
||||
}: {
|
||||
fields: Field[]
|
||||
t: TFunction
|
||||
}): Field[] => fields.map((field) => createClientFieldConfig({ field, t }))
|
||||
|
||||
@@ -52,7 +52,12 @@ export const baseField = joi
|
||||
index: joi.boolean().default(false),
|
||||
label: joi
|
||||
.alternatives()
|
||||
.try(joi.object().pattern(joi.string(), [joi.string()]), joi.string(), joi.valid(false)),
|
||||
.try(
|
||||
joi.func(),
|
||||
joi.object().pattern(joi.string(), [joi.string()]),
|
||||
joi.string(),
|
||||
joi.valid(false),
|
||||
),
|
||||
localized: joi.boolean().default(false),
|
||||
required: joi.boolean().default(false),
|
||||
saveToJWT: joi.alternatives().try(joi.boolean(), joi.string()).default(false),
|
||||
@@ -216,7 +221,7 @@ export const select = baseField.keys({
|
||||
joi.object({
|
||||
label: joi
|
||||
.alternatives()
|
||||
.try(joi.string(), joi.object().pattern(joi.string(), [joi.string()])),
|
||||
.try(joi.func(), joi.string(), joi.object().pattern(joi.string(), [joi.string()])),
|
||||
value: joi.string().required().allow(''),
|
||||
}),
|
||||
),
|
||||
@@ -245,7 +250,7 @@ export const radio = baseField.keys({
|
||||
joi.object({
|
||||
label: joi
|
||||
.alternatives()
|
||||
.try(joi.string(), joi.object().pattern(joi.string(), [joi.string()]))
|
||||
.try(joi.func(), joi.string(), joi.object().pattern(joi.string(), [joi.string()]))
|
||||
.required(),
|
||||
value: joi.string().required().allow(''),
|
||||
}),
|
||||
|
||||
@@ -17,6 +17,7 @@ import type {
|
||||
} from '../../admin/types.js'
|
||||
import type { User } from '../../auth/index.js'
|
||||
import type { SanitizedCollectionConfig, TypeWithID } from '../../collections/config/types.js'
|
||||
import type { LabelFunction } from '../../config/types.js'
|
||||
import type { DBIdentifierName } from '../../database/types.js'
|
||||
import type { SanitizedGlobalConfig } from '../../globals/config/types.js'
|
||||
import type { Operation, PayloadRequest, RequestContext, Where } from '../../types/index.js'
|
||||
@@ -134,8 +135,8 @@ type Admin = {
|
||||
}
|
||||
|
||||
export type Labels = {
|
||||
plural: Record<string, string> | string
|
||||
singular: Record<string, string> | string
|
||||
plural: LabelFunction | Record<string, string> | string
|
||||
singular: LabelFunction | Record<string, string> | string
|
||||
}
|
||||
|
||||
export type BaseValidateOptions<TData, TSiblingData> = {
|
||||
@@ -165,7 +166,7 @@ export type Validate<
|
||||
export type ClientValidate = Omit<Validate, 'req'>
|
||||
|
||||
export type OptionObject = {
|
||||
label: Record<string, string> | string
|
||||
label: LabelFunction | Record<string, string> | string
|
||||
value: string
|
||||
}
|
||||
|
||||
@@ -193,7 +194,7 @@ export interface FieldBase {
|
||||
beforeValidate?: FieldHook[]
|
||||
}
|
||||
index?: boolean
|
||||
label?: Record<string, string> | false | string
|
||||
label?: LabelFunction | Record<string, string> | false | string
|
||||
localized?: boolean
|
||||
name: string
|
||||
required?: boolean
|
||||
@@ -394,6 +395,7 @@ export type UnnamedTab = Omit<TabBase, 'name'> & {
|
||||
| {
|
||||
[selectedLanguage: string]: string
|
||||
}
|
||||
| LabelFunction
|
||||
| string
|
||||
localized?: never
|
||||
}
|
||||
|
||||
@@ -1,16 +1,12 @@
|
||||
// default beforeDuplicate hook for required and unique fields
|
||||
import type { FieldAffectingData, FieldHook } from './config/types.js'
|
||||
|
||||
import { extractTranslations } from '../translations/extractTranslations.js'
|
||||
|
||||
const copyTranslations = extractTranslations(['general:copy'])
|
||||
|
||||
const unique: FieldHook = ({ value }) => (typeof value === 'string' ? `${value} - Copy` : undefined)
|
||||
const localizedUnique: FieldHook = ({ req, value }) =>
|
||||
value ? `${value} - ${copyTranslations?.[req.locale]?.['general:copy'] ?? 'Copy'}` : undefined
|
||||
value ? `${value} - ${req?.t('general:copy') ?? 'Copy'}` : undefined
|
||||
const uniqueRequired: FieldHook = ({ value }) => `${value} - Copy`
|
||||
const localizedUniqueRequired: FieldHook = ({ req, value }) =>
|
||||
`${value} - ${copyTranslations?.[req.locale]?.['general:copy'] ?? 'Copy'}`
|
||||
`${value} - ${req?.t('general:copy') ?? 'Copy'}`
|
||||
|
||||
export const setDefaultBeforeDuplicate = (field: FieldAffectingData) => {
|
||||
if (
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import type { TFunction } from '@payloadcms/translations'
|
||||
|
||||
import type {
|
||||
LivePreviewConfig,
|
||||
SanitizedConfig,
|
||||
@@ -30,11 +32,15 @@ export type ClientGlobalConfig = Omit<
|
||||
fields: ClientFieldConfig[]
|
||||
}
|
||||
|
||||
export const createClientGlobalConfig = (
|
||||
global: SanitizedConfig['globals'][0],
|
||||
): ClientGlobalConfig => {
|
||||
export const createClientGlobalConfig = ({
|
||||
global,
|
||||
t,
|
||||
}: {
|
||||
global: SanitizedConfig['globals'][0]
|
||||
t: TFunction
|
||||
}): ClientGlobalConfig => {
|
||||
const sanitized = { ...global }
|
||||
sanitized.fields = createClientFieldConfigs(sanitized.fields)
|
||||
sanitized.fields = createClientFieldConfigs({ fields: sanitized.fields, t })
|
||||
|
||||
const serverOnlyProperties: Partial<ServerOnlyGlobalProperties>[] = [
|
||||
'hooks',
|
||||
@@ -73,6 +79,10 @@ export const createClientGlobalConfig = (
|
||||
return sanitized
|
||||
}
|
||||
|
||||
export const createClientGlobalConfigs = (
|
||||
globals: SanitizedConfig['globals'],
|
||||
): ClientGlobalConfig[] => globals.map((global) => createClientGlobalConfig(global))
|
||||
export const createClientGlobalConfigs = ({
|
||||
globals,
|
||||
t,
|
||||
}: {
|
||||
globals: SanitizedConfig['globals']
|
||||
t: TFunction
|
||||
}): ClientGlobalConfig[] => globals.map((global) => createClientGlobalConfig({ global, t }))
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
import { extractTranslations } from 'payload/utilities'
|
||||
|
||||
import type { Config } from '../../config/types.js'
|
||||
import type { SanitizedGlobalConfig } from './types.js'
|
||||
|
||||
@@ -10,8 +8,6 @@ import mergeBaseFields from '../../fields/mergeBaseFields.js'
|
||||
import { toWords } from '../../utilities/formatLabels.js'
|
||||
import baseVersionFields from '../../versions/baseFields.js'
|
||||
|
||||
const translations = extractTranslations(['general:createdAt', 'general:updatedAt'])
|
||||
|
||||
const sanitizeGlobals = (config: Config): SanitizedGlobalConfig[] => {
|
||||
const { collections, globals } = config
|
||||
|
||||
@@ -80,7 +76,7 @@ const sanitizeGlobals = (config: Config): SanitizedGlobalConfig[] => {
|
||||
disableBulkEdit: true,
|
||||
hidden: true,
|
||||
},
|
||||
label: translations['general:updatedAt'],
|
||||
label: ({ t }) => t('general:updatedAt'),
|
||||
})
|
||||
}
|
||||
if (!hasCreatedAt) {
|
||||
@@ -91,7 +87,7 @@ const sanitizeGlobals = (config: Config): SanitizedGlobalConfig[] => {
|
||||
disableBulkEdit: true,
|
||||
hidden: true,
|
||||
},
|
||||
label: translations['general:createdAt'],
|
||||
label: ({ t }) => t('general:createdAt'),
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -65,7 +65,9 @@ const globalSchema = joi
|
||||
beforeRead: joi.array().items(joi.func()),
|
||||
beforeValidate: joi.array().items(joi.func()),
|
||||
}),
|
||||
label: joi.alternatives().try(joi.string(), joi.object().pattern(joi.string(), [joi.string()])),
|
||||
label: joi
|
||||
.alternatives()
|
||||
.try(joi.func(), joi.string(), joi.object().pattern(joi.string(), [joi.string()])),
|
||||
typescript: joi.object().keys({
|
||||
interface: joi.string(),
|
||||
}),
|
||||
|
||||
@@ -20,6 +20,7 @@ export type Options<T extends keyof GeneratedTypes['globals']> = {
|
||||
user?: Document
|
||||
}
|
||||
|
||||
// eslint-disable-next-line no-restricted-exports
|
||||
export default async function findVersionByIDLocal<T extends keyof GeneratedTypes['globals']>(
|
||||
payload: Payload,
|
||||
options: Options<T>,
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
import { translations } from '@payloadcms/translations/api'
|
||||
|
||||
export const extractTranslations = (keys: string[]): Record<string, Record<string, string>> => {
|
||||
const result = {}
|
||||
keys.forEach((key) => {
|
||||
result[key] = {}
|
||||
})
|
||||
Object.entries(translations).forEach(([language, resource]) => {
|
||||
keys.forEach((key) => {
|
||||
const [section, target] = key.split(':')
|
||||
if (resource?.[section]?.[target]) {
|
||||
result[key][language] = resource[section][target]
|
||||
} else {
|
||||
// console.error(`Missing translation for ${key} in ${language}`)
|
||||
}
|
||||
})
|
||||
})
|
||||
return result
|
||||
}
|
||||
@@ -1,18 +1,18 @@
|
||||
import type { AcceptedLanguages } from '@payloadcms/translations'
|
||||
|
||||
import { initI18n } from '@payloadcms/translations'
|
||||
import { translations } from '@payloadcms/translations/api'
|
||||
|
||||
import type { SanitizedConfig } from '../config/types.js'
|
||||
|
||||
export const getLocalI18n = ({
|
||||
export const getLocalI18n = async ({
|
||||
config,
|
||||
language = 'en',
|
||||
}: {
|
||||
config: SanitizedConfig
|
||||
language?: string
|
||||
language?: AcceptedLanguages
|
||||
}) =>
|
||||
initI18n({
|
||||
config: config.i18n,
|
||||
context: 'api',
|
||||
language,
|
||||
translations,
|
||||
})
|
||||
|
||||
@@ -3,17 +3,8 @@ import type { Config } from '../config/types.js'
|
||||
import type { Field } from '../fields/config/types.js'
|
||||
import type { UploadConfig } from './types.js'
|
||||
|
||||
import { extractTranslations } from '../translations/extractTranslations.js'
|
||||
import { mimeTypeValidator } from './mimeTypeValidator.js'
|
||||
|
||||
const labels = extractTranslations([
|
||||
'upload:width',
|
||||
'upload:height',
|
||||
'upload:fileSize',
|
||||
'upload:fileName',
|
||||
'upload:sizes',
|
||||
])
|
||||
|
||||
type GenerateURLArgs = {
|
||||
collectionSlug: string
|
||||
config: Config
|
||||
@@ -87,7 +78,7 @@ export const getBaseUploadFields = ({ collection, config }: Options): Field[] =>
|
||||
hidden: true,
|
||||
readOnly: true,
|
||||
},
|
||||
label: labels['upload:width'],
|
||||
label: ({ t }) => t('upload:width'),
|
||||
}
|
||||
|
||||
const height: Field = {
|
||||
@@ -97,7 +88,7 @@ export const getBaseUploadFields = ({ collection, config }: Options): Field[] =>
|
||||
hidden: true,
|
||||
readOnly: true,
|
||||
},
|
||||
label: labels['upload:height'],
|
||||
label: ({ t }) => t('upload:height'),
|
||||
}
|
||||
|
||||
const filesize: Field = {
|
||||
@@ -107,7 +98,7 @@ export const getBaseUploadFields = ({ collection, config }: Options): Field[] =>
|
||||
hidden: true,
|
||||
readOnly: true,
|
||||
},
|
||||
label: labels['upload:fileSize'],
|
||||
label: ({ t }) => t('upload:fileSize'),
|
||||
}
|
||||
|
||||
const filename: Field = {
|
||||
@@ -119,7 +110,7 @@ export const getBaseUploadFields = ({ collection, config }: Options): Field[] =>
|
||||
readOnly: true,
|
||||
},
|
||||
index: true,
|
||||
label: labels['upload:fileName'],
|
||||
label: ({ t }) => t('upload:fileName'),
|
||||
unique: true,
|
||||
}
|
||||
|
||||
@@ -201,7 +192,7 @@ export const getBaseUploadFields = ({ collection, config }: Options): Field[] =>
|
||||
],
|
||||
label: size.name,
|
||||
})),
|
||||
label: labels['upload:Sizes'],
|
||||
label: ({ t }) => t('upload:Sizes'),
|
||||
},
|
||||
])
|
||||
}
|
||||
|
||||
@@ -63,12 +63,12 @@ type CreateLocalReq = (
|
||||
user?: User
|
||||
},
|
||||
payload: Payload,
|
||||
) => PayloadRequest
|
||||
export const createLocalReq: CreateLocalReq = (
|
||||
) => Promise<PayloadRequest>
|
||||
export const createLocalReq: CreateLocalReq = async (
|
||||
{ context, fallbackLocale, locale: localeArg, req = {} as PayloadRequest, user },
|
||||
payload,
|
||||
) => {
|
||||
const i18n = req?.i18n || getLocalI18n({ config: payload.config })
|
||||
const i18n = req?.i18n || (await getLocalI18n({ config: payload.config }))
|
||||
|
||||
if (payload.config?.localization) {
|
||||
const locale = localeArg === '*' ? 'all' : localeArg
|
||||
|
||||
@@ -1,16 +1,12 @@
|
||||
import type { Field } from '../fields/config/types.js'
|
||||
|
||||
import { extractTranslations } from '../translations/extractTranslations.js'
|
||||
|
||||
const labels = extractTranslations(['version:draft', 'version:published', 'version:status'])
|
||||
|
||||
export const statuses = [
|
||||
{
|
||||
label: labels['version:draft'],
|
||||
label: ({ t }) => t('version:draft'),
|
||||
value: 'draft',
|
||||
},
|
||||
{
|
||||
label: labels['version:published'],
|
||||
label: ({ t }) => t('version:published'),
|
||||
value: 'published',
|
||||
},
|
||||
]
|
||||
@@ -26,7 +22,7 @@ const baseVersionFields: Field[] = [
|
||||
disableBulkEdit: true,
|
||||
},
|
||||
defaultValue: 'draft',
|
||||
label: labels['version:status'],
|
||||
label: ({ t }) => t('version:status'),
|
||||
options: statuses,
|
||||
},
|
||||
]
|
||||
|
||||
2
packages/payload/uploads.d.ts
vendored
Normal file
2
packages/payload/uploads.d.ts
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
export { getFileByPath } from './dist/uploads/getFileByPath.js';
|
||||
//# sourceMappingURL=uploads.d.ts.map
|
||||
3
packages/payload/uploads.js
Normal file
3
packages/payload/uploads.js
Normal file
@@ -0,0 +1,3 @@
|
||||
export { getFileByPath } from './dist/uploads/getFileByPath.js';
|
||||
|
||||
//# sourceMappingURL=uploads.js.map
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@payloadcms/plugin-cloud-storage",
|
||||
"description": "The official cloud storage plugin for Payload CMS",
|
||||
"version": "3.0.0-alpha.60",
|
||||
"version": "3.0.0-alpha.61",
|
||||
"main": "./src/index.ts",
|
||||
"types": "./src/index.ts",
|
||||
"type": "module",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@payloadcms/plugin-cloud",
|
||||
"description": "The official Payload Cloud plugin",
|
||||
"version": "3.0.0-alpha.60",
|
||||
"version": "3.0.0-alpha.61",
|
||||
"main": "./src/index.ts",
|
||||
"types": "./src/index.ts",
|
||||
"license": "MIT",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@payloadcms/plugin-form-builder",
|
||||
"description": "Form builder plugin for Payload CMS",
|
||||
"version": "3.0.0-alpha.60",
|
||||
"version": "3.0.0-alpha.61",
|
||||
"homepage:": "https://payloadcms.com",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/plugin-nested-docs",
|
||||
"version": "3.0.0-alpha.60",
|
||||
"version": "3.0.0-alpha.61",
|
||||
"description": "The official Nested Docs plugin for Payload",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/plugin-redirects",
|
||||
"version": "3.0.0-alpha.60",
|
||||
"version": "3.0.0-alpha.61",
|
||||
"homepage:": "https://payloadcms.com",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/plugin-search",
|
||||
"version": "3.0.0-alpha.60",
|
||||
"version": "3.0.0-alpha.61",
|
||||
"homepage:": "https://payloadcms.com",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/plugin-seo",
|
||||
"version": "3.0.0-alpha.60",
|
||||
"version": "3.0.0-alpha.61",
|
||||
"homepage:": "https://payloadcms.com",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/richtext-lexical",
|
||||
"version": "3.0.0-alpha.60",
|
||||
"version": "3.0.0-alpha.61",
|
||||
"description": "The officially supported Lexical richtext adapter for Payload",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
||||
@@ -2,21 +2,8 @@ import type { User } from 'payload/auth'
|
||||
import type { Config } from 'payload/config'
|
||||
import type { Field, RadioField, TextField } from 'payload/types'
|
||||
|
||||
import { extractTranslations } from 'payload/utilities'
|
||||
|
||||
import { validateUrl } from '../../../lexical/utils/url.js'
|
||||
|
||||
const translations = extractTranslations([
|
||||
'fields:textToDisplay',
|
||||
'fields:linkType',
|
||||
'fields:chooseBetweenCustomTextOrDocument',
|
||||
'fields:customURL',
|
||||
'fields:internalLink',
|
||||
'fields:enterURL',
|
||||
'fields:chooseDocumentToLink',
|
||||
'fields:openInNewTab',
|
||||
])
|
||||
|
||||
export const getBaseFields = (
|
||||
config: Config,
|
||||
enabledCollections: false | string[],
|
||||
@@ -49,7 +36,7 @@ export const getBaseFields = (
|
||||
{
|
||||
name: 'text',
|
||||
type: 'text',
|
||||
label: translations['fields:textToDisplay'],
|
||||
label: ({ t }) => t('fields:textToDisplay'),
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
@@ -68,13 +55,13 @@ export const getBaseFields = (
|
||||
name: 'linkType',
|
||||
type: 'radio',
|
||||
admin: {
|
||||
description: translations['fields:chooseBetweenCustomTextOrDocument'],
|
||||
description: ({ t }) => t('fields:chooseBetweenCustomTextOrDocument'),
|
||||
},
|
||||
defaultValue: 'custom',
|
||||
label: translations['fields:linkType'],
|
||||
label: ({ t }) => t('fields:linkType'),
|
||||
options: [
|
||||
{
|
||||
label: translations['fields:customURL'],
|
||||
label: ({ t }) => t('fields:customURL'),
|
||||
value: 'custom',
|
||||
},
|
||||
],
|
||||
@@ -83,7 +70,7 @@ export const getBaseFields = (
|
||||
{
|
||||
name: 'url',
|
||||
type: 'text',
|
||||
label: translations['fields:enterURL'],
|
||||
label: ({ t }) => t('fields:enterURL'),
|
||||
required: true,
|
||||
validate: (value: string) => {
|
||||
if (value && !validateUrl(value)) {
|
||||
@@ -98,7 +85,7 @@ export const getBaseFields = (
|
||||
// Only display internal link-specific fields / options / conditions if there are enabled relations
|
||||
if (enabledRelations?.length) {
|
||||
;(baseFields[1].fields[0] as RadioField).options.push({
|
||||
label: translations['fields:internalLink'],
|
||||
label: ({ t }) => t('fields:internalLink'),
|
||||
value: 'internal',
|
||||
})
|
||||
;(baseFields[1].fields[1] as TextField).admin = {
|
||||
@@ -123,7 +110,7 @@ export const getBaseFields = (
|
||||
}
|
||||
}
|
||||
: null,
|
||||
label: translations['fields:chooseDocumentToLink'],
|
||||
label: ({ t }) => t('fields:chooseDocumentToLink'),
|
||||
relationTo: enabledRelations,
|
||||
required: true,
|
||||
})
|
||||
@@ -132,7 +119,7 @@ export const getBaseFields = (
|
||||
baseFields[1].fields.push({
|
||||
name: 'newTab',
|
||||
type: 'checkbox',
|
||||
label: translations['fields:openInNewTab'],
|
||||
label: ({ t }) => t('fields:openInNewTab'),
|
||||
})
|
||||
|
||||
return baseFields as Field[]
|
||||
|
||||
@@ -2,9 +2,6 @@ import type { I18n } from '@payloadcms/translations'
|
||||
import type { SanitizedConfig } from 'payload/config'
|
||||
import type { FieldWithRichTextRequiredEditor } from 'payload/types'
|
||||
|
||||
import { initI18n } from '@payloadcms/translations'
|
||||
import { translations } from '@payloadcms/translations/client'
|
||||
|
||||
import type { HTMLConverter } from '../converters/html/converter/types.js'
|
||||
import type { FeatureProviderProviderServer } from '../types.js'
|
||||
import type { ClientProps } from './feature.client.js'
|
||||
@@ -67,9 +64,7 @@ export const LinkFeature: FeatureProviderProviderServer<LinkFeatureServerProps,
|
||||
disabledCollections: props.disabledCollections,
|
||||
enabledCollections: props.enabledCollections,
|
||||
} as ExclusiveLinkCollectionsProps,
|
||||
generateSchemaMap: ({ config, props }) => {
|
||||
const i18n = initI18n({ config: config.i18n, context: 'client', translations })
|
||||
|
||||
generateSchemaMap: ({ config, i18n, props }) => {
|
||||
return {
|
||||
fields: transformExtraFields(
|
||||
props.fields,
|
||||
|
||||
@@ -246,10 +246,10 @@ export const TOGGLE_LINK_COMMAND: LexicalCommand<LinkPayload | null> =
|
||||
export function toggleLink(payload: LinkPayload): void {
|
||||
const selection = $getSelection()
|
||||
|
||||
if (!$isRangeSelection(selection)) {
|
||||
if (!$isRangeSelection(selection) && !payload.selectedNodes.length) {
|
||||
return
|
||||
}
|
||||
const nodes = selection.extract()
|
||||
const nodes = $isRangeSelection(selection) ? selection.extract() : payload.selectedNodes
|
||||
|
||||
if (payload === null) {
|
||||
// Remove LinkNodes
|
||||
|
||||
@@ -8,6 +8,8 @@ const { useLexicalComposerContext } = lexicalComposerContextImport
|
||||
|
||||
import lexicalUtilsImport from '@lexical/utils'
|
||||
const { $findMatchingParent, mergeRegister } = lexicalUtilsImport
|
||||
import type { LexicalNode } from 'lexical'
|
||||
|
||||
import { getTranslation } from '@payloadcms/translations'
|
||||
import lexicalImport from 'lexical'
|
||||
const {
|
||||
@@ -57,6 +59,8 @@ export function LinkEditor({ anchorElem }: { anchorElem: HTMLElement }): React.R
|
||||
const { closeModal, toggleModal } = useModal()
|
||||
const editDepth = useEditDepth()
|
||||
const [isLink, setIsLink] = useState(false)
|
||||
const [selectedNodes, setSelectedNodes] = useState<LexicalNode[]>([])
|
||||
|
||||
const [isAutoLink, setIsAutoLink] = useState(false)
|
||||
|
||||
const drawerSlug = formatDrawerSlug({
|
||||
@@ -78,6 +82,7 @@ export function LinkEditor({ anchorElem }: { anchorElem: HTMLElement }): React.R
|
||||
setIsAutoLink(false)
|
||||
setLinkUrl('')
|
||||
setLinkLabel('')
|
||||
setSelectedNodes([])
|
||||
return
|
||||
}
|
||||
|
||||
@@ -115,6 +120,8 @@ export function LinkEditor({ anchorElem }: { anchorElem: HTMLElement }): React.R
|
||||
|
||||
setStateData(data)
|
||||
setIsLink(true)
|
||||
setSelectedNodes(selection ? selection?.getNodes() : [])
|
||||
|
||||
if ($isAutoLinkNode(linkParent)) {
|
||||
setIsAutoLink(true)
|
||||
} else {
|
||||
@@ -291,18 +298,26 @@ export function LinkEditor({ anchorElem }: { anchorElem: HTMLElement }): React.R
|
||||
|
||||
const newLinkPayload: LinkPayload = data as LinkPayload
|
||||
|
||||
newLinkPayload.selectedNodes = selectedNodes
|
||||
|
||||
// See: https://github.com/facebook/lexical/pull/5536. This updates autolink nodes to link nodes whenever a change was made (which is good!).
|
||||
editor.update(() => {
|
||||
const selection = $getSelection()
|
||||
let linkParent = null
|
||||
if ($isRangeSelection(selection)) {
|
||||
const parent = getSelectedNode(selection).getParent()
|
||||
if ($isAutoLinkNode(parent)) {
|
||||
const linkNode = $createLinkNode({
|
||||
fields: newLinkPayload.fields,
|
||||
})
|
||||
parent.replace(linkNode, true)
|
||||
linkParent = getSelectedNode(selection).getParent()
|
||||
} else {
|
||||
if (selectedNodes.length) {
|
||||
linkParent = selectedNodes[0].getParent()
|
||||
}
|
||||
}
|
||||
|
||||
if (linkParent && $isAutoLinkNode(linkParent)) {
|
||||
const linkNode = $createLinkNode({
|
||||
fields: newLinkPayload.fields,
|
||||
})
|
||||
linkParent.replace(linkNode, true)
|
||||
}
|
||||
})
|
||||
|
||||
// Needs to happen AFTER a potential auto link => link node conversion, as otherwise, the updated text to display may be lost due to
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import type { LexicalNode } from 'lexical'
|
||||
|
||||
import type { LinkFields } from '../../nodes/types.js'
|
||||
|
||||
/**
|
||||
@@ -6,6 +8,7 @@ import type { LinkFields } from '../../nodes/types.js'
|
||||
*/
|
||||
export type LinkPayload = {
|
||||
fields: LinkFields
|
||||
selectedNodes?: LexicalNode[]
|
||||
/**
|
||||
* The text content of the link node - will be displayed in the drawer
|
||||
*/
|
||||
|
||||
@@ -7,6 +7,7 @@ import { getBaseFields } from '../../drawer/baseFields.js'
|
||||
/**
|
||||
* This function is run to enrich the basefields which every link has with potential, custom user-added fields.
|
||||
*/
|
||||
// eslint-disable-next-line @typescript-eslint/require-await
|
||||
export function transformExtraFields(
|
||||
customFieldSchema:
|
||||
| ((args: { config: SanitizedConfig; defaultFields: Field[]; i18n: I18n }) => Field[])
|
||||
|
||||
@@ -19,7 +19,7 @@ type FilteredCollectionsT = (
|
||||
|
||||
const filterRichTextCollections: FilteredCollectionsT = (collections, options) => {
|
||||
return collections.filter(({ slug, admin: { enableRichTextRelationship }, upload }) => {
|
||||
if (options.visibleEntities.collections.includes(slug)) {
|
||||
if (!options.visibleEntities.collections.includes(slug)) {
|
||||
return false
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import type { Transformer } from '@lexical/markdown'
|
||||
import type { I18n } from '@payloadcms/translations'
|
||||
import type { JSONSchema4 } from 'json-schema'
|
||||
import type { Klass, LexicalEditor, LexicalNode, SerializedEditorState } from 'lexical'
|
||||
import type { SerializedLexicalNode } from 'lexical'
|
||||
@@ -178,6 +179,7 @@ export type ServerFeature<ServerProps, ClientFeatureProps> = {
|
||||
clientFeatureProps?: ClientFeatureProps
|
||||
generateComponentMap?: (args: {
|
||||
config: SanitizedConfig
|
||||
i18n: I18n
|
||||
props: ServerProps
|
||||
schemaPath: string
|
||||
}) => {
|
||||
@@ -185,12 +187,17 @@ export type ServerFeature<ServerProps, ClientFeatureProps> = {
|
||||
}
|
||||
generateSchemaMap?: (args: {
|
||||
config: SanitizedConfig
|
||||
i18n: I18n
|
||||
props: ServerProps
|
||||
schemaMap: Map<string, Field[]>
|
||||
schemaPath: string
|
||||
}) => {
|
||||
[key: string]: Field[]
|
||||
}
|
||||
}) =>
|
||||
| {
|
||||
[key: string]: Field[]
|
||||
}
|
||||
| Promise<{
|
||||
[key: string]: Field[]
|
||||
}>
|
||||
generatedTypes?: {
|
||||
modifyOutputSchema: ({
|
||||
collectionIDFieldTypes,
|
||||
|
||||
@@ -13,7 +13,7 @@ export const getGenerateComponentMap =
|
||||
(args: {
|
||||
resolvedFeatureMap: ResolvedServerFeatureMap
|
||||
}): RichTextAdapter['generateComponentMap'] =>
|
||||
({ config, schemaPath }) => {
|
||||
({ config, i18n, schemaPath }) => {
|
||||
const validRelationships = config.collections.map((c) => c.slug) || []
|
||||
|
||||
const componentMap = new Map()
|
||||
@@ -39,6 +39,7 @@ export const getGenerateComponentMap =
|
||||
) {
|
||||
const components = resolvedFeature.generateComponentMap({
|
||||
config,
|
||||
i18n,
|
||||
props: resolvedFeature.serverFeatureProps,
|
||||
schemaPath,
|
||||
})
|
||||
@@ -68,6 +69,7 @@ export const getGenerateComponentMap =
|
||||
) {
|
||||
const schemas = resolvedFeature.generateSchemaMap({
|
||||
config,
|
||||
i18n,
|
||||
props: resolvedFeature.serverFeatureProps,
|
||||
schemaMap: new Map(),
|
||||
schemaPath,
|
||||
@@ -87,6 +89,7 @@ export const getGenerateComponentMap =
|
||||
config,
|
||||
disableAddingID: true,
|
||||
fieldSchema: sanitizedFields,
|
||||
i18n,
|
||||
parentPath: `${schemaPath}.feature.${featureKey}.fields.${schemaKey}`,
|
||||
readOnly: false,
|
||||
})
|
||||
|
||||
@@ -8,7 +8,7 @@ import { cloneDeep } from './field/lexical/utils/cloneDeep.js'
|
||||
|
||||
export const getGenerateSchemaMap =
|
||||
(args: { resolvedFeatureMap: ResolvedServerFeatureMap }): RichTextAdapter['generateSchemaMap'] =>
|
||||
({ config, schemaMap, schemaPath }) => {
|
||||
({ config, i18n, schemaMap, schemaPath }) => {
|
||||
const validRelationships = config.collections.map((c) => c.slug) || []
|
||||
|
||||
for (const [featureKey, resolvedFeature] of args.resolvedFeatureMap.entries()) {
|
||||
@@ -20,6 +20,7 @@ export const getGenerateSchemaMap =
|
||||
}
|
||||
const schemas = resolvedFeature.generateSchemaMap({
|
||||
config,
|
||||
i18n,
|
||||
props: resolvedFeature.serverFeatureProps,
|
||||
schemaMap,
|
||||
schemaPath,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/richtext-slate",
|
||||
"version": "3.0.0-alpha.60",
|
||||
"version": "3.0.0-alpha.61",
|
||||
"description": "The officially supported Slate richtext adapter for Payload",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
||||
@@ -2,41 +2,28 @@ import type { User } from 'payload/auth'
|
||||
import type { Config } from 'payload/config'
|
||||
import type { Field } from 'payload/types'
|
||||
|
||||
import { extractTranslations } from 'payload/utilities'
|
||||
|
||||
const translations = extractTranslations([
|
||||
'fields:textToDisplay',
|
||||
'fields:linkType',
|
||||
'fields:chooseBetweenCustomTextOrDocument',
|
||||
'fields:customURL',
|
||||
'fields:internalLink',
|
||||
'fields:enterURL',
|
||||
'fields:chooseDocumentToLink',
|
||||
'fields:openInNewTab',
|
||||
])
|
||||
|
||||
export const getBaseFields = (config: Config): Field[] => [
|
||||
{
|
||||
name: 'text',
|
||||
type: 'text',
|
||||
label: translations['fields:textToDisplay'],
|
||||
label: ({ t }) => t('fields:textToDisplay'),
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
name: 'linkType',
|
||||
type: 'radio',
|
||||
admin: {
|
||||
description: translations['fields:chooseBetweenCustomTextOrDocument'],
|
||||
description: ({ t }) => t('fields:chooseBetweenCustomTextOrDocument'),
|
||||
},
|
||||
defaultValue: 'custom',
|
||||
label: translations['fields:linkType'],
|
||||
label: ({ t }) => t('fields:linkType'),
|
||||
options: [
|
||||
{
|
||||
label: translations['fields:customURL'],
|
||||
label: ({ t }) => t('fields:customURL'),
|
||||
value: 'custom',
|
||||
},
|
||||
{
|
||||
label: translations['fields:internalLink'],
|
||||
label: ({ t }) => t('fields:internalLink'),
|
||||
value: 'internal',
|
||||
},
|
||||
],
|
||||
@@ -48,7 +35,7 @@ export const getBaseFields = (config: Config): Field[] => [
|
||||
admin: {
|
||||
condition: ({ linkType }) => linkType !== 'internal',
|
||||
},
|
||||
label: translations['fields:enterURL'],
|
||||
label: ({ t }) => t('fields:enterURL'),
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
@@ -66,7 +53,7 @@ export const getBaseFields = (config: Config): Field[] => [
|
||||
return false
|
||||
}
|
||||
},
|
||||
label: translations['fields:chooseDocumentToLink'],
|
||||
label: ({ t }) => t('fields:chooseDocumentToLink'),
|
||||
relationTo: config.collections
|
||||
.filter(({ admin: { enableRichTextLink, hidden } }) => {
|
||||
if (typeof hidden !== 'function' && hidden) {
|
||||
@@ -80,6 +67,6 @@ export const getBaseFields = (config: Config): Field[] => [
|
||||
{
|
||||
name: 'newTab',
|
||||
type: 'checkbox',
|
||||
label: translations['fields:openInNewTab'],
|
||||
label: ({ t }) => t('fields:openInNewTab'),
|
||||
},
|
||||
]
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
import type { RichTextAdapter } from 'payload/types'
|
||||
|
||||
import { initI18n } from '@payloadcms/translations'
|
||||
import { translations } from '@payloadcms/translations/client'
|
||||
import { mapFields } from '@payloadcms/ui/utilities/buildComponentMap'
|
||||
import { sanitizeFields } from 'payload/config'
|
||||
import React from 'react'
|
||||
@@ -16,10 +14,9 @@ import { defaultLeaves as leafTypes } from './field/leaves/index.js'
|
||||
|
||||
export const getGenerateComponentMap =
|
||||
(args: AdapterArguments): RichTextAdapter['generateComponentMap'] =>
|
||||
({ config }) => {
|
||||
({ config, i18n }) => {
|
||||
const componentMap = new Map()
|
||||
|
||||
const i18n = initI18n({ config: config.i18n, context: 'client', translations })
|
||||
const validRelationships = config.collections.map((c) => c.slug) || []
|
||||
|
||||
;(args?.admin?.leaves || Object.values(leafTypes)).forEach((leaf) => {
|
||||
@@ -78,6 +75,7 @@ export const getGenerateComponentMap =
|
||||
const mappedFields = mapFields({
|
||||
config,
|
||||
fieldSchema: linkFields,
|
||||
i18n,
|
||||
readOnly: false,
|
||||
})
|
||||
|
||||
@@ -108,6 +106,7 @@ export const getGenerateComponentMap =
|
||||
const mappedFields = mapFields({
|
||||
config,
|
||||
fieldSchema: uploadFields,
|
||||
i18n,
|
||||
readOnly: false,
|
||||
})
|
||||
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
import type { RichTextAdapter } from 'payload/types'
|
||||
|
||||
import { initI18n } from '@payloadcms/translations'
|
||||
import { translations } from '@payloadcms/translations/client'
|
||||
import { sanitizeFields } from 'payload/config'
|
||||
|
||||
import type { AdapterArguments, RichTextCustomElement } from './types.js'
|
||||
@@ -13,8 +11,7 @@ import { uploadFieldsSchemaPath } from './field/elements/upload/shared.js'
|
||||
|
||||
export const getGenerateSchemaMap =
|
||||
(args: AdapterArguments): RichTextAdapter['generateSchemaMap'] =>
|
||||
({ config, schemaMap, schemaPath }) => {
|
||||
const i18n = initI18n({ config: config.i18n, context: 'client', translations })
|
||||
({ config, i18n, schemaMap, schemaPath }) => {
|
||||
const validRelationships = config.collections.map((c) => c.slug) || []
|
||||
|
||||
;(args?.admin?.elements || Object.values(elementTypes)).forEach((el) => {
|
||||
|
||||
@@ -43,3 +43,121 @@ These are the translations for Payload. Translations are used on both the server
|
||||
// or
|
||||
pnpm build
|
||||
```
|
||||
|
||||
Here is a full list of language keys. Note that these are not all implemented, but if you would like to contribute and add a new language, you can use this list as a reference:
|
||||
|
||||
| Language Code | Language Name |
|
||||
| -------------- | ------------------------------------------ |
|
||||
| af | Afrikaans |
|
||||
| am | Amharic |
|
||||
| ar-sa | Arabic (Saudi Arabia) |
|
||||
| as | Assamese |
|
||||
| az-Latn | Azerbaijani (Latin) |
|
||||
| be | Belarusian |
|
||||
| bg | Bulgarian |
|
||||
| bn-BD | Bangla (Bangladesh) |
|
||||
| bn-IN | Bangla (India) |
|
||||
| bs | Bosnian (Latin) |
|
||||
| ca | Catalan Spanish |
|
||||
| ca-ES-valencia | Valencian |
|
||||
| cs | Czech |
|
||||
| cy | Welsh |
|
||||
| da | Danish |
|
||||
| de | German (Germany) |
|
||||
| el | Greek |
|
||||
| en-GB | English (United Kingdom) |
|
||||
| en-US | English (United States) |
|
||||
| es | Spanish (Spain) |
|
||||
| es-ES | Spanish (Spain) |
|
||||
| es-US | Spanish (United States) |
|
||||
| es-MX | Spanish (Mexico) |
|
||||
| et | Estonian |
|
||||
| eu | Basque |
|
||||
| fa | Persian |
|
||||
| fi | Finnish |
|
||||
| fil-Latn | Filipino |
|
||||
| fr | French (France) |
|
||||
| fr-FR | French (France) |
|
||||
| fr-CA | French (Canada) |
|
||||
| ga | Irish |
|
||||
| gd-Latn | Scottish Gaelic |
|
||||
| gl | Galician |
|
||||
| gu | Gujarati |
|
||||
| ha-Latn | Hausa (Latin) |
|
||||
| he | Hebrew |
|
||||
| hi | Hindi |
|
||||
| hr | Croatian |
|
||||
| hu | Hungarian |
|
||||
| hy | Armenian |
|
||||
| id | Indonesian |
|
||||
| ig-Latn | Igbo |
|
||||
| is | Icelandic |
|
||||
| it | Italian (Italy) |
|
||||
| it-it | Italian (Italy) |
|
||||
| ja | Japanese |
|
||||
| ka | Georgian |
|
||||
| kk | Kazakh |
|
||||
| km | Khmer |
|
||||
| kn | Kannada |
|
||||
| ko | Korean |
|
||||
| kok | Konkani |
|
||||
| ku-Arab | Central Kurdish |
|
||||
| ky-Cyrl | Kyrgyz |
|
||||
| lb | Luxembourgish |
|
||||
| lt | Lithuanian |
|
||||
| lv | Latvian |
|
||||
| mi-Latn | Maori |
|
||||
| mk | Macedonian |
|
||||
| ml | Malayalam |
|
||||
| mn-Cyrl | Mongolian (Cyrillic) |
|
||||
| mr | Marathi |
|
||||
| ms | Malay (Malaysia) |
|
||||
| mt | Maltese |
|
||||
| nb | Norwegian (Bokmål) |
|
||||
| ne | Nepali (Nepal) |
|
||||
| nl | Dutch (Netherlands) |
|
||||
| nl-BE | Dutch (Netherlands) |
|
||||
| nn | Norwegian (Nynorsk) |
|
||||
| nso | Sesotho sa Leboa |
|
||||
| or | Odia |
|
||||
| pa | Punjabi (Gurmukhi) |
|
||||
| pa-Arab | Punjabi (Arabic) |
|
||||
| pl | Polish |
|
||||
| prs-Arab | Dari |
|
||||
| pt-BR | Portuguese (Brazil) |
|
||||
| pt-PT | Portuguese (Portugal) |
|
||||
| qut-Latn | K’iche’ |
|
||||
| quz | Quechua (Peru) |
|
||||
| ro | Romanian (Romania) |
|
||||
| ru | Russian |
|
||||
| rw | Kinyarwanda |
|
||||
| sd-Arab | Sindhi (Arabic) |
|
||||
| si | Sinhala |
|
||||
| sk | Slovak |
|
||||
| sl | Slovenian |
|
||||
| sq | Albanian |
|
||||
| sr-Cyrl-BA | Serbian (Cyrillic, Bosnia and Herzegovina) |
|
||||
| sr-Cyrl-RS | Serbian (Cyrillic, Serbia) |
|
||||
| sr-Latn-RS | Serbian (Latin, Serbia) |
|
||||
| sv | Swedish (Sweden) |
|
||||
| sw | Kiswahili |
|
||||
| ta | Tamil |
|
||||
| te | Telugu |
|
||||
| tg-Cyrl | Tajik (Cyrillic) |
|
||||
| th | Thai |
|
||||
| ti | Tigrinya |
|
||||
| tk-Latn | Turkmen (Latin) |
|
||||
| tn | Setswana |
|
||||
| tr | Turkish |
|
||||
| tt-Cyrl | Tatar (Cyrillic) |
|
||||
| ug-Arab | Uyghur |
|
||||
| uk | Ukrainian |
|
||||
| ur | Urdu |
|
||||
| uz-Latn | Uzbek (Latin) |
|
||||
| vi | Vietnamese |
|
||||
| wo | Wolof |
|
||||
| xh | isiXhosa |
|
||||
| yo-Latn | Yoruba |
|
||||
| zh-Hans | Chinese (Simplified) |
|
||||
| zh-Hant | Chinese (Traditional) |
|
||||
| zu | isiZulu |
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/translations",
|
||||
"version": "3.0.0-alpha.60",
|
||||
"version": "3.0.0-alpha.61",
|
||||
"main": "./src/exports/index.ts",
|
||||
"types": "./src/types.ts",
|
||||
"type": "module",
|
||||
@@ -12,9 +12,8 @@
|
||||
},
|
||||
"scripts": {
|
||||
"build:types": "tsc --outDir dist",
|
||||
"build": "pnpm writeFiles && pnpm build:types",
|
||||
"build": "pnpm build:types",
|
||||
"clean": "rimraf {dist,*.tsbuildinfo}",
|
||||
"writeFiles": "npx tsx ./writeTranslationFiles.ts",
|
||||
"prepublishOnly": "pnpm clean && pnpm turbo build"
|
||||
},
|
||||
"exports": {
|
||||
@@ -22,13 +21,13 @@
|
||||
"import": "./src/exports/index.ts",
|
||||
"require": "./src/exports/index.ts"
|
||||
},
|
||||
"./api": {
|
||||
"import": "./src/_generatedFiles_/api/index.ts",
|
||||
"require": "./src/_generatedFiles_/api/index.ts"
|
||||
"./*": {
|
||||
"import": "./src/exports/*.ts",
|
||||
"require": "./src/exports/*.ts"
|
||||
},
|
||||
"./client": {
|
||||
"import": "./src/_generatedFiles_/client/index.ts",
|
||||
"require": "./src/_generatedFiles_/client/index.ts"
|
||||
"./languages/*": {
|
||||
"import": "./src/languages/*.ts",
|
||||
"require": "./src/languages/*.ts"
|
||||
}
|
||||
},
|
||||
"publishConfig": {
|
||||
@@ -41,15 +40,15 @@
|
||||
"require": "./dist/exports/index.js",
|
||||
"types": "./dist/exports/*.d.ts"
|
||||
},
|
||||
"./api": {
|
||||
"import": "./dist/_generatedFiles_/api/index.js",
|
||||
"require": "./dist/_generatedFiles_/api/index.js",
|
||||
"types": "./dist/_generatedFiles_/exports/*.d.ts"
|
||||
"./*": {
|
||||
"import": "./dist/exports/*.js",
|
||||
"require": "./dist/exports/*.js",
|
||||
"types": "./dist/exports/*.d.ts"
|
||||
},
|
||||
"./client": {
|
||||
"import": "./dist/_generatedFiles_/client/index.js",
|
||||
"require": "./dist/_generatedFiles_/client/index.js",
|
||||
"types": "./dist/_generatedFiles_/exports/*.d.ts"
|
||||
"./languages/*": {
|
||||
"import": "./dist/languages/*.js",
|
||||
"require": "./dist/languages/*.js",
|
||||
"types": "./dist/languages/*.d.ts"
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -57,6 +56,7 @@
|
||||
"@payloadcms/eslint-config": "workspace:*",
|
||||
"@swc/core": "^1.3.102",
|
||||
"@types/react": "18.2.74",
|
||||
"date-fns": "3.3.1",
|
||||
"typescript": "5.4.4"
|
||||
},
|
||||
"files": [
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user