Merge branch 'alpha' of github.com:payloadcms/payload into alpha

This commit is contained in:
James
2024-03-13 13:59:53 -04:00
148 changed files with 876 additions and 1079 deletions

View File

@@ -8,3 +8,4 @@
**/dist/**
**/node_modules
**/temp
playwright.config.ts

View File

@@ -1,3 +1,3 @@
{
"recommendations": ["esbenp.prettier-vscode", "dbaeumer.vscode-eslint"]
"recommendations": ["esbenp.prettier-vscode", "dbaeumer.vscode-eslint", "ortoni.ortoni"]
}

View File

@@ -1,6 +1,6 @@
{
"name": "payload-monorepo",
"version": "3.0.0-alpha.46",
"version": "3.0.0-alpha.48",
"private": true,
"type": "module",
"workspaces:": [
@@ -8,7 +8,7 @@
],
"scripts": {
"build": "pnpm run build:core",
"obliterate-playwright-cache": "rm -rf ~/Library/Caches/ms-playwright && find /System/Volumes/Data/private/var/folders -type d -name 'playwright*' -exec rm -rf {} ++ && npx playwright install",
"obliterate-playwright-cache": "rm -rf ~/Library/Caches/ms-playwright && find /System/Volumes/Data/private/var/folders -type d -name 'playwright*' -exec rm -rf {} +",
"build:all": "turbo build",
"build:core": "turbo build --filter \"!@payloadcms/plugin-*\"",
"build:plugins": "turbo build --filter \"@payloadcms/plugin-*\"",
@@ -60,7 +60,7 @@
"release:beta": "tsx ./scripts/release.ts --bump prerelease --tag beta",
"test": "pnpm test:int && pnpm test:components && pnpm test:e2e",
"test:components": "cross-env NODE_OPTIONS=--no-deprecation jest --config=jest.components.config.js",
"test:e2e": "NODE_OPTIONS=--no-deprecation npx playwright install --with-deps chromium && NODE_OPTIONS=--no-deprecation tsx ./test/runE2E.ts",
"test:e2e": "NODE_OPTIONS=--no-deprecation tsx ./test/runE2E.ts",
"test:e2e:debug": "cross-env NODE_OPTIONS=--no-deprecation PWDEBUG=1 DISABLE_LOGGING=true playwright test",
"test:e2e:headed": "cross-env NODE_OPTIONS=--no-deprecation DISABLE_LOGGING=true playwright test --headed",
"test:int:postgres": "cross-env NODE_OPTIONS=--no-deprecation PAYLOAD_DATABASE=postgres DISABLE_LOGGING=true jest --forceExit --detectOpenHandles",
@@ -68,8 +68,7 @@
"translateNewKeys": "pnpm --filter payload run translateNewKeys"
},
"devDependencies": {
"drizzle-kit": "0.20.14-1f2c838",
"@aws-sdk/client-s3": "^3.142.0",
"@aws-sdk/client-s3": "^3.525.0",
"@next/bundle-analyzer": "^14.1.0",
"@octokit/core": "^5.1.0",
"@payloadcms/eslint-config": "workspace:*",
@@ -104,6 +103,7 @@
"copyfiles": "2.4.1",
"cross-env": "7.0.3",
"dotenv": "8.6.0",
"drizzle-kit": "0.20.14-1f2c838",
"drizzle-orm": "0.29.4",
"execa": "5.1.1",
"form-data": "3.0.1",
@@ -140,6 +140,7 @@
"simple-git": "^3.20.0",
"slash": "3.0.0",
"slate": "0.91.4",
"swc-plugin-transform-remove-imports": "^1.12.1",
"tempfile": "^3.0.0",
"ts-node": "10.9.1",
"tsx": "^4.7.1",

View File

@@ -1,6 +1,6 @@
{
"name": "@payloadcms/db-mongodb",
"version": "3.0.0-alpha.46",
"version": "3.0.0-alpha.48",
"description": "The officially supported MongoDB database adapter for Payload - Update 2",
"repository": "https://github.com/payloadcms/payload",
"license": "MIT",

View File

@@ -45,7 +45,10 @@ export const createMigration: CreateMigration = async function createMigration({
// Check if predefined migration exists
if (fs.existsSync(cleanPath)) {
const { down, up } = await eval(`import(${cleanPath})`)
let migration = await eval(`${require ? 'require' : 'import'}(${cleanPath})`)
if ('default' in migration) migration = migration.default
const { down, up } = migration
migrationFileContent = migrationTemplate(up, down)
} else {
payload.logger.error({

View File

@@ -1,6 +1,6 @@
{
"name": "@payloadcms/db-postgres",
"version": "3.0.0-alpha.46",
"version": "3.0.0-alpha.48",
"description": "The officially supported Postgres database adapter for Payload",
"repository": "https://github.com/payloadcms/payload",
"license": "MIT",

View File

@@ -3,13 +3,10 @@ import type { DrizzleSnapshotJSON } from 'drizzle-kit/payload'
import type { CreateMigration } from 'payload/database'
import fs from 'fs'
import { createRequire } from 'module'
import prompts from 'prompts'
import type { PostgresAdapter } from './types.js'
const require = createRequire(import.meta.url)
const migrationTemplate = (
upSQL?: string,
downSQL?: string,
@@ -63,7 +60,9 @@ export const createMigration: CreateMigration = async function createMigration(
fs.mkdirSync(dir)
}
const { generateDrizzleJson, generateMigration } = require('drizzle-kit/payload')
const { generateDrizzleJson, generateMigration } = require
? require('drizzle-kit/payload')
: await import('drizzle-kit/payload')
const [yyymmdd, hhmmss] = new Date().toISOString().split('T')
const formattedDate = yyymmdd.replace(/\D/g, '')

View File

@@ -3,7 +3,6 @@ import type { Payload } from 'payload'
import type { Migration } from 'payload/database'
import type { PayloadRequest } from 'payload/types'
import { createRequire } from 'module'
import {
commitTransaction,
initTransaction,
@@ -18,8 +17,6 @@ import { createMigrationTable } from './utilities/createMigrationTable.js'
import { migrationTableExists } from './utilities/migrationTableExists.js'
import { parseError } from './utilities/parseError.js'
const require = createRequire(import.meta.url)
export async function migrate(this: PostgresAdapter): Promise<void> {
const { payload } = this
const migrationFiles = await readMigrationFiles({ payload })
@@ -85,7 +82,9 @@ export async function migrate(this: PostgresAdapter): Promise<void> {
}
async function runMigrationFile(payload: Payload, migration: Migration, batch: number) {
const { generateDrizzleJson } = require('drizzle-kit/payload')
const { generateDrizzleJson } = require
? require('drizzle-kit/payload')
: await import('drizzle-kit/payload')
const start = Date.now()
const req = { payload } as PayloadRequest

View File

@@ -1,12 +1,9 @@
import { eq } from 'drizzle-orm'
import { numeric, timestamp, varchar } from 'drizzle-orm/pg-core'
import { createRequire } from 'module'
import prompts from 'prompts'
import type { PostgresAdapter } from '../types.js'
const require = createRequire(import.meta.url)
/**
* Pushes the development schema to the database using Drizzle.
*
@@ -14,7 +11,9 @@ const require = createRequire(import.meta.url)
* @returns {Promise<void>} - A promise that resolves once the schema push is complete.
*/
export const pushDevSchema = async (db: PostgresAdapter) => {
const { pushSchema } = require('drizzle-kit/payload')
const { pushSchema } = require
? require('drizzle-kit/payload')
: await import('drizzle-kit/payload')
// This will prompt if clarifications are needed for Drizzle to push new schema
const { apply, hasDataLoss, statementsToExecute, warnings } = await pushSchema(

View File

@@ -1,3 +1,61 @@
const sharedRules = {
'@typescript-eslint/ban-ts-comment': 'off',
'@typescript-eslint/consistent-type-imports': 'warn',
'@typescript-eslint/no-explicit-any': 'warn',
// Type-aware any rules:
'@typescript-eslint/no-unsafe-assignment': 'off',
'@typescript-eslint/no-unsafe-member-access': 'off',
'@typescript-eslint/no-unsafe-call': 'off',
'@typescript-eslint/no-unsafe-argument': 'off',
'@typescript-eslint/no-unsafe-return': 'off',
// This rule doesn't work well in .tsx files
'@typescript-eslint/no-misused-promises': 'off',
// Type-aware any rules end
// ts-expect should always be preferred over ts-ignore
'@typescript-eslint/prefer-ts-expect-error': 'warn',
// This rule makes no sense when overriding class methods. This is used a lot in richtext-lexical.
'class-methods-use-this': 'off',
// By default, it errors for unused variables. This is annoying, warnings are enough.
'@typescript-eslint/no-unused-vars': [
'warn',
{
vars: 'all',
args: 'after-used',
ignoreRestSiblings: false,
argsIgnorePattern: '^_',
varsIgnorePattern: '^_',
destructuredArrayIgnorePattern: '^_',
caughtErrorsIgnorePattern: '^ignore',
},
],
'@typescript-eslint/no-use-before-define': 'off',
'arrow-body-style': 0,
'import/prefer-default-export': 'off',
'no-restricted-exports': ['warn', { restrictDefaultExports: { direct: true } }],
'no-console': 'warn',
'no-sparse-arrays': 'off',
'no-underscore-dangle': 'off',
'no-use-before-define': 'off',
'object-shorthand': 'warn',
'react/no-unused-prop-types': 'off',
'react/prop-types': 'off',
'react/require-default-props': 'off',
'perfectionist/sort-objects': [
'error',
{
type: 'natural',
order: 'asc',
'partition-by-comment': true,
groups: ['top', 'unknown'],
'custom-groups': {
top: ['_id', 'id', 'name', 'slug', 'type'],
},
},
],
}
/** @type {import('eslint').Linter.Config} */
module.exports = {
env: {
@@ -8,15 +66,9 @@ module.exports = {
extends: [
'eslint:recommended',
'plugin:perfectionist/recommended-natural',
'plugin:@typescript-eslint/recommended-type-checked',
'plugin:regexp/recommended',
'plugin:react/recommended',
'plugin:react-hooks/recommended',
'./configs/jest/index.js',
'./configs/react/index.js',
'prettier',
],
parser: '@typescript-eslint/parser',
parserOptions: {
ecmaFeatures: {
jsx: true,
@@ -24,71 +76,70 @@ module.exports = {
ecmaVersion: 'latest',
sourceType: 'module',
},
plugins: ['@typescript-eslint'],
plugins: [],
overrides: [
{
files: ['*.js', '*.cjs'],
extends: ['plugin:@typescript-eslint/disable-type-checked'],
files: ['**/*.ts'],
plugins: ['@typescript-eslint'],
extends: [
'eslint:recommended',
'plugin:perfectionist/recommended-natural',
'plugin:@typescript-eslint/recommended-type-checked',
'plugin:regexp/recommended',
'prettier',
],
parser: '@typescript-eslint/parser',
rules: sharedRules,
},
{
files: ['**/*.tsx'],
plugins: ['@typescript-eslint'],
extends: [
'eslint:recommended',
'plugin:perfectionist/recommended-natural',
'plugin:@typescript-eslint/recommended-type-checked',
'plugin:regexp/recommended',
'plugin:react/recommended',
'plugin:react-hooks/recommended',
'./configs/react/index.js',
'prettier',
],
parser: '@typescript-eslint/parser',
rules: sharedRules,
},
{
files: ['**/*.spec.ts'],
plugins: ['@typescript-eslint'],
extends: [
'eslint:recommended',
'plugin:perfectionist/recommended-natural',
'plugin:@typescript-eslint/recommended-type-checked',
'plugin:regexp/recommended',
'./configs/jest/index.js',
'prettier',
],
parser: '@typescript-eslint/parser',
rules: {
...sharedRules,
'@typescript-eslint/unbound-method': 'off',
},
},
{
files: ['*.config.ts'],
rules: {
...sharedRules,
'no-restricted-exports': 'off',
},
},
{
files: ['config.ts'],
rules: {
...sharedRules,
'no-restricted-exports': 'off',
},
},
],
rules: {
'@typescript-eslint/ban-ts-comment': 'off',
'@typescript-eslint/consistent-type-imports': 'warn',
'@typescript-eslint/no-explicit-any': 'warn',
// Type-aware any rules:
'@typescript-eslint/no-unsafe-assignment': 'off',
'@typescript-eslint/no-unsafe-member-access': 'off',
'@typescript-eslint/no-unsafe-call': 'off',
'@typescript-eslint/no-unsafe-argument': 'off',
'@typescript-eslint/no-unsafe-return': 'off',
// This rule doesn't work well in .tsx files
'@typescript-eslint/no-misused-promises': 'off',
// Type-aware any rules end
// ts-expect should always be preferred over ts-ignore
'@typescript-eslint/prefer-ts-expect-error': 'warn',
// This rule makes no sense when overriding class methods. This is used a lot in richtext-lexical.
'class-methods-use-this': 'off',
// By default, it errors for unused variables. This is annoying, warnings are enough.
'@typescript-eslint/no-unused-vars': 'warn',
'@typescript-eslint/no-use-before-define': 'off',
'arrow-body-style': 0,
'import/prefer-default-export': 'off',
'no-restricted-exports': ['warn', { restrictDefaultExports: { direct: true } }],
'no-console': 'warn',
'no-sparse-arrays': 'off',
'no-underscore-dangle': 'off',
'no-use-before-define': 'off',
'object-shorthand': 'warn',
'react/no-unused-prop-types': 'off',
'react/prop-types': 'off',
'react/require-default-props': 'off',
'perfectionist/sort-objects': [
'error',
{
type: 'natural',
order: 'asc',
'partition-by-comment': true,
groups: ['top', 'unknown'],
'custom-groups': {
top: ['_id', 'id', 'name', 'slug', 'type'],
},
},
],
},
rules: sharedRules,
settings: {
'import/parsers': {
'@typescript-eslint/parser': ['.ts', '.tsx'],

View File

@@ -1,6 +1,6 @@
{
"name": "@payloadcms/graphql",
"version": "3.0.0-alpha.46",
"version": "3.0.0-alpha.48",
"main": "./src/index.ts",
"types": "./src/index.d.ts",
"type": "module",

View File

@@ -1,6 +1,6 @@
{
"name": "@payloadcms/next",
"version": "3.0.0-alpha.46",
"version": "3.0.0-alpha.48",
"main": "./src/index.ts",
"types": "./src/index.d.ts",
"type": "module",

View File

@@ -11,7 +11,7 @@ import 'react-toastify/dist/ReactToastify.css'
import { ClearRouteCache } from '../../elements/ClearRouteCache/index.js'
import { auth } from '../../utilities/auth.js'
import { getPayload } from '../../utilities/getPayload.js'
import { getPayloadHMR } from '../../utilities/getPayloadHMR.js'
import { getRequestLanguage } from '../../utilities/getRequestLanguage.js'
import { DefaultEditView } from '../../views/Edit/Default/index.js'
import { DefaultCell } from '../../views/List/Default/Cell/index.js'
@@ -36,7 +36,7 @@ export const RootLayout = async ({
const headers = getHeaders()
const payload = await getPayload({ config: configPromise })
const payload = await getPayloadHMR({ config: configPromise })
const { cookies, permissions } = await auth({
headers,

View File

@@ -24,7 +24,33 @@ export const getFieldSchemaMap = (config: SanitizedConfig): FieldSchemaMap => {
export const buildFormState = async ({ req }: { req: PayloadRequest }) => {
const reqData: BuildFormStateArgs = req.data as BuildFormStateArgs
// TODO: run ADMIN access control for user
const incomingUserSlug = req.user?.collection
const adminUserSlug = req.payload.config.admin.user
// If we have a user slug, test it against the functions
if (incomingUserSlug) {
const adminAccessFunction = req.payload.collections[incomingUserSlug].config.access?.admin
// Run the admin access function from the config if it exists
if (adminAccessFunction) {
const canAccessAdmin = await adminAccessFunction(req)
if (!canAccessAdmin) {
return Response.json(null, {
status: httpStatus.UNAUTHORIZED,
})
}
// Match the user collection to the global admin config
} else if (adminUserSlug !== incomingUserSlug) {
return Response.json(null, {
status: httpStatus.UNAUTHORIZED,
})
}
} else {
return Response.json(null, {
status: httpStatus.UNAUTHORIZED,
})
}
const fieldSchemaMap = getFieldSchemaMap(req.payload.config)

View File

@@ -14,7 +14,7 @@ import QueryString from 'qs'
import { URL } from 'url'
import { getDataAndFile } from './getDataAndFile.js'
import { getPayload } from './getPayload.js'
import { getPayloadHMR } from './getPayloadHMR.js'
import { getRequestLanguage } from './getRequestLanguage.js'
import { getRequestLocales } from './getRequestLocales.js'
@@ -32,7 +32,7 @@ export const createPayloadRequest = async ({
request,
}: Args): Promise<PayloadRequest> => {
const cookies = parseCookies(request.headers)
const payload = await getPayload({ config: configPromise })
const payload = await getPayloadHMR({ config: configPromise })
const { collections, config } = payload
@@ -113,6 +113,8 @@ export const createPayloadRequest = async ({
}
const req: PayloadRequest = Object.assign(request, customRequest)
if (data) req.json = () => Promise.resolve(data)
req.payloadDataLoader = getDataLoader(req)
req.user = await getAuthenticatedUser({

View File

@@ -11,7 +11,7 @@ if (!cached) {
cached = global._payload = { payload: null, promise: null, reload: false }
}
export const getPayload = async (options: InitOptions): Promise<Payload> => {
export const getPayloadHMR = async (options: InitOptions): Promise<Payload> => {
if (!options?.config) {
throw new Error('Error: the payload config is required for getPayload to work.')
}

View File

@@ -14,7 +14,7 @@ import { notFound, redirect } from 'next/navigation.js'
import { createLocalReq } from 'payload/utilities'
import qs from 'qs'
import { getPayload } from '../utilities/getPayload.js'
import { getPayloadHMR } from '../utilities/getPayloadHMR.js'
import { auth } from './auth.js'
import { getRequestLanguage } from './getRequestLanguage.js'
@@ -33,7 +33,7 @@ export const initPage = async ({
}: Args): Promise<InitPageResult> => {
const headers = getHeaders()
const localeParam = searchParams?.locale as string
const payload = await getPayload({ config: configPromise })
const payload = await getPayloadHMR({ config: configPromise })
const { cookies, permissions, user } = await auth({
headers,

View File

@@ -1,4 +1,4 @@
import type { Data, DocumentPreferences, ServerSideEditViewProps } from 'payload/types'
import type { DocumentPreferences, ServerSideEditViewProps, TypeWithID } from 'payload/types'
import {
DocumentHeader,
@@ -7,6 +7,7 @@ import {
HydrateClientUser,
RenderCustomComponent,
buildStateFromSchema,
formatDocTitle,
formatFields,
} from '@payloadcms/ui'
import { notFound } from 'next/navigation.js'
@@ -14,7 +15,6 @@ import React from 'react'
import type { AdminViewProps } from '../Root/index.js'
import { formatTitle } from '../Edit/Default/SetDocumentTitle/formatTitle.js'
import { EditView } from '../Edit/index.js'
import { Settings } from './Settings/index.js'
@@ -46,7 +46,7 @@ export const Account: React.FC<AdminViewProps> = async ({ initPageResult, search
if (collectionConfig) {
const { fields } = collectionConfig
let data: Data
let data: TypeWithID
try {
data = await payload.findByID({
@@ -77,7 +77,7 @@ export const Account: React.FC<AdminViewProps> = async ({ initPageResult, search
equals: preferencesKey,
},
},
})) as any as { docs: { value: DocumentPreferences }[] }
})) as any as { docs: { value: DocumentPreferences }[] } // eslint-disable-line @typescript-eslint/no-explicit-any
const initialState = await buildStateFromSchema({
id: user?.id,
@@ -107,11 +107,12 @@ export const Account: React.FC<AdminViewProps> = async ({ initPageResult, search
initialData={data}
initialState={initialState}
isEditing
title={formatTitle({
title={formatDocTitle({
collectionConfig,
data,
dateFormat: config.admin.dateFormat,
fallback: data?.id?.toString(),
i18n,
value: data?.[collectionConfig?.admin?.useAsTitle] || data?.id?.toString(),
})}
>
<DocumentHeader

View File

@@ -15,6 +15,7 @@ import {
HydrateClientUser,
RenderCustomComponent,
buildStateFromSchema,
formatDocTitle,
formatFields,
} from '@payloadcms/ui'
import React from 'react'
@@ -22,7 +23,6 @@ import React from 'react'
import type { AdminViewProps } from '../Root/index.js'
import type { GenerateEditViewMetadata } from './getMetaBySegment.js'
import { formatTitle } from '../Edit/Default/SetDocumentTitle/formatTitle.js'
import { NotFoundClient } from '../NotFound/index.client.js'
import { getMetaBySegment } from './getMetaBySegment.js'
import { getViewsFromConfig } from './getViewsFromConfig.js'
@@ -201,12 +201,13 @@ export const Document: React.FC<AdminViewProps> = async ({
initialData={data}
initialState={initialState}
isEditing={isEditing}
title={formatTitle({
title={formatDocTitle({
collectionConfig,
data,
dateFormat: config.admin.dateFormat,
fallback: id?.toString(),
globalConfig,
i18n,
value: data?.[collectionConfig?.admin?.useAsTitle] || id?.toString(),
})}
>
<DocumentHeader

View File

@@ -1,47 +0,0 @@
import type { I18n } from '@payloadcms/translations'
import type {
SanitizedCollectionConfig,
SanitizedConfig,
SanitizedGlobalConfig,
} from 'payload/types'
import { getTranslation } from '@payloadcms/translations'
import { formatDate } from '@payloadcms/ui'
export const formatTitle = ({
collectionConfig,
dateFormat: dateFormatFromConfig,
globalConfig,
i18n,
value,
}: {
collectionConfig?: SanitizedCollectionConfig
dateFormat: SanitizedConfig['admin']['dateFormat']
globalConfig?: SanitizedGlobalConfig
i18n: I18n
value: string
}): string => {
let title: string = value
const useAsTitle = collectionConfig?.admin?.useAsTitle
if (collectionConfig && useAsTitle) {
const fieldConfig = collectionConfig.fields.find((f) => 'name' in f && f.name === useAsTitle)
const isDate = fieldConfig?.type === 'date'
if (title && isDate) {
const dateFormat = fieldConfig?.admin?.date?.displayFormat || dateFormatFromConfig
title = formatDate(title, dateFormat, i18n.language)
}
}
if (globalConfig) {
title = getTranslation(globalConfig?.label, i18n) || globalConfig?.slug
}
if (!title) {
title = `[${i18n.t('general:untitled')}]`
}
return title
}

View File

@@ -1,17 +1,16 @@
'use client'
import type { ClientConfig } from 'payload/types'
import { useDocumentInfo, useFormFields, useTranslation } from '@payloadcms/ui'
import { formatDocTitle, useDocumentInfo, useFormFields, useTranslation } from '@payloadcms/ui'
import { useEffect, useRef } from 'react'
import { formatTitle } from './formatTitle.js'
export const SetDocumentTitle: React.FC<{
collectionConfig?: ClientConfig['collections'][0]
config?: ClientConfig
fallback: string
globalConfig?: ClientConfig['globals'][0]
}> = (props) => {
const { collectionConfig, config, globalConfig } = props
const { collectionConfig, config, fallback, globalConfig } = props
const useAsTitle = collectionConfig?.admin?.useAsTitle
@@ -25,17 +24,18 @@ export const SetDocumentTitle: React.FC<{
const dateFormatFromConfig = config?.admin?.dateFormat
const title = formatTitle({
const title = formatDocTitle({
collectionConfig,
data: { id: '' },
dateFormat: dateFormatFromConfig,
globalConfig,
i18n,
value:
fallback:
typeof field === 'string'
? field
: typeof field === 'number'
? String(field)
: (field?.value as string),
: (field?.value as string) || fallback,
globalConfig,
i18n,
})
useEffect(() => {

View File

@@ -13,6 +13,7 @@ import {
useConfig,
useDocumentEvents,
useDocumentInfo,
useEditDepth,
} from '@payloadcms/ui'
import { Upload } from '@payloadcms/ui/elements'
import React, { Fragment, useCallback } from 'react'
@@ -60,6 +61,8 @@ export const DefaultEditView: React.FC = () => {
const { getComponentMap, getFieldMap } = useComponentMap()
const depth = useEditDepth()
const componentMap = getComponentMap({ collectionSlug, globalSlug })
const collectionConfig =
@@ -89,7 +92,7 @@ export const DefaultEditView: React.FC = () => {
const classes = [baseClass, id && `${baseClass}--is-editing`].filter(Boolean).join(' ')
const onSave = useCallback(
async (json) => {
(json) => {
reportUpdate({
id,
entitySlug,
@@ -117,7 +120,7 @@ export const DefaultEditView: React.FC = () => {
)
const onChange: FormProps['onChange'][0] = useCallback(
async ({ formState: prevFormState }) =>
({ formState: prevFormState }) =>
getFormState({
apiRoute,
body: {
@@ -171,6 +174,7 @@ export const DefaultEditView: React.FC = () => {
<SetDocumentTitle
collectionConfig={collectionConfig}
config={config}
fallback={depth <= 1 ? id?.toString() : undefined}
globalConfig={globalConfig}
/>
<DocumentControls

View File

@@ -74,16 +74,18 @@ export const RelationshipCell: React.FC<RelationshipCellProps> = ({
const relatedCollection = collections.find(({ slug }) => slug === relationTo)
const label = formatDocTitle({
doc: document === false ? null : document,
collectionConfig: relatedCollection,
data: document || null,
dateFormat: config.admin.dateFormat,
fallback: `${t('general:untitled')} - ID: ${value}`,
i18n,
useAsTitle: relatedCollection?.admin?.useAsTitle,
})
return (
<React.Fragment key={i}>
{document === false && `${t('general:untitled')} - ID: ${value}`}
{document === null && `${t('general:loading')}...`}
{document && (label || `${t('general:untitled')} - ID: ${value}`)}
{document ? label : null}
{values.length > i + 1 && ', '}
</React.Fragment>
)

View File

@@ -79,7 +79,7 @@ const PreviewView: React.FC = (props) => {
const { previewWindowType } = useLivePreviewContext()
const onSave = useCallback(
async (json) => {
(json) => {
// reportUpdate({
// id,
// entitySlug: collectionConfig.slug,
@@ -91,7 +91,7 @@ const PreviewView: React.FC = (props) => {
// }
if (typeof onSaveFromProps === 'function') {
onSaveFromProps({
void onSaveFromProps({
...json,
operation: id ? 'update' : 'create',
})
@@ -106,7 +106,7 @@ const PreviewView: React.FC = (props) => {
)
const onChange: FormProps['onChange'][0] = useCallback(
async ({ formState: prevFormState }) =>
({ formState: prevFormState }) =>
getFormState({
apiRoute,
body: {
@@ -154,6 +154,7 @@ const PreviewView: React.FC = (props) => {
<SetDocumentTitle
collectionConfig={collectionConfig}
config={config}
fallback={id?.toString() || ''}
globalConfig={globalConfig}
/>
<DocumentControls

View File

@@ -1,6 +1,6 @@
{
"name": "payload",
"version": "3.0.0-alpha.46",
"version": "3.0.0-alpha.48",
"description": "Node, React and MongoDB Headless CMS and Application Framework",
"license": "MIT",
"main": "./src/index.js",

View File

@@ -37,7 +37,9 @@ export const APIKeyAuthentication =
const userQuery = await payload.find({
collection: collectionConfig.slug,
depth: collectionConfig.auth.depth,
limit: 1,
overrideAccess: true,
pagination: false,
where,
})

View File

@@ -31,6 +31,7 @@ export const incrementLoginAttempts = async ({
lockUntil: null,
loginAttempts: 1,
},
depth: 0,
req,
})
}
@@ -52,6 +53,7 @@ export const incrementLoginAttempts = async ({
id: doc.id,
collection: collection.slug,
data,
depth: 0,
req,
})
}

View File

@@ -23,6 +23,9 @@ export const registerLocalStrategy = async ({
const existingUser = await payload.find({
collection: collection.slug,
depth: 0,
limit: 1,
pagination: false,
req,
where: {
email: {
equals: doc.email,

View File

@@ -23,6 +23,7 @@ export const resetLoginAttempts = async ({
lockUntil: null,
loginAttempts: 0,
},
depth: 0,
overrideAccess: true,
req,
})

View File

@@ -693,7 +693,7 @@ export type ClientConfig = Omit<SanitizedConfig, 'admin' | 'db' | 'endpoints'> &
SanitizedCollectionConfig,
'access' | 'admin' | 'endpoints' | 'fields' | 'hooks'
> & {
admin: Omit<SanitizedCollectionConfig['admin'], 'components'>
admin: Omit<SanitizedCollectionConfig['admin'], 'components' | 'useAsTitle'>
fields: ClientConfigField[]
})[]
globals: (Omit<SanitizedGlobalConfig, 'access' | 'admin' | 'endpoints' | 'fields' | 'hooks'> & {

View File

@@ -36,7 +36,10 @@ export const readMigrationFiles = async ({
return Promise.all(
files.map(async (filePath) => {
// eval used to circumvent errors bundling
const migration = await eval(`import('${filePath.replaceAll('\\', '/')}')`)
let migration = await eval(
`${require ? 'require' : 'import'}('${filePath.replaceAll('\\', '/')}')`,
)
if ('default' in migration) migration = migration.default
const result: Migration = {
name: path.basename(filePath).split('.')?.[0],

View File

@@ -8,6 +8,7 @@ async function findOne(
const {
key,
req: { payload },
req,
user,
} = args
@@ -21,17 +22,11 @@ async function findOne(
],
}
const { docs } = await payload.find({
return await payload.db.findOne({
collection: 'payload-preferences',
depth: 0,
pagination: false,
user,
req,
where,
})
if (docs.length === 0) return null
return docs[0]
}
export default findOne

View File

@@ -65,6 +65,7 @@ const replaceWithDraftIfAvailable = async <T extends TypeWithID>({
global: entity.slug,
limit: 1,
locale,
pagination: false,
req,
sort: '-updatedAt',
where: combineQueries(queryToBuild, versionAccessResult),

View File

@@ -44,6 +44,7 @@ export const enforceMaxVersions = async ({
} else if (global) {
const query = await payload.db.findGlobalVersions({
global: global.slug,
pagination: false,
req,
skip: max,
sort: '-updatedAt',

View File

@@ -25,6 +25,8 @@ export const getLatestCollectionVersion = async <T extends TypeWithID = any>({
if (config.versions?.drafts) {
const { docs } = await payload.db.findVersions<T>({
collection: config.slug,
limit: 1,
pagination: false,
req,
sort: '-updatedAt',
where: { parent: { equals: id } },

View File

@@ -29,6 +29,7 @@ export const getLatestGlobalVersion = async ({
global: slug,
limit: 1,
locale,
pagination: false,
req,
sort: '-updatedAt',
})

View File

@@ -40,6 +40,7 @@ export const saveVersion = async ({
let docs
const findVersionArgs = {
limit: 1,
pagination: false,
req,
sort: '-updatedAt',
}

View File

@@ -1,3 +1,10 @@
azure.d.ts
azure.js
gcs.d.ts
gcs.js
s3.d.ts
s3.js
dev/tmp
dev/yarn.lock

View File

@@ -1 +0,0 @@
export * from './dist/adapters/azure'

View File

@@ -1 +0,0 @@
exports.azureBlobStorageAdapter = require('./dist/adapters/azure').azureBlobStorageAdapter

View File

@@ -1 +0,0 @@
export * from './dist/adapters/gcs'

View File

@@ -1 +0,0 @@
exports.gcsAdapter = require('./dist/adapters/gcs').gcsAdapter

View File

@@ -1,13 +1,13 @@
{
"name": "@payloadcms/plugin-cloud-storage",
"description": "The official cloud storage plugin for Payload CMS",
"version": "3.0.0-alpha.46",
"version": "3.0.0-alpha.48",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"type": "module",
"license": "MIT",
"scripts": {
"build": "pnpm build:swc && pnpm build:types",
"build": "pnpm build:swc && pnpm build:types && tsx ../../scripts/exportPointerFiles.ts ../packages/plugin-cloud-storage dist/exports",
"build:swc": "swc ./src -d ./dist --config-file .swcrc",
"build:types": "tsc --emitDeclarationOnly --outDir dist",
"clean": "rimraf {dist,*.tsbuildinfo}",
@@ -55,5 +55,44 @@
"dependencies": {
"find-node-modules": "^2.1.3",
"range-parser": "^1.2.1"
},
"exports": {
".": {
"import": "./src/index.ts",
"require": "./src/index.ts",
"types": "./src/index.ts"
},
"./*": {
"import": "./src/exports/*.ts",
"require": "./src/exports/*.ts",
"types": "./src/exports/*.ts"
},
"./dist/*": {
"import": "./src/*.ts",
"require": "./src/*.ts",
"types": "./src/*.ts"
}
},
"publishConfig": {
"exports": {
".": {
"import": "./dist/index.js",
"require": "./dist/index.js",
"types": "./dist/index.d.ts"
},
"./*": {
"import": "./dist/exports/*.js",
"require": "./dist/exports/*.js",
"types": "./dist/exports/*.d.ts"
},
"./dist/*": {
"import": "./dist/*.js",
"require": "./dist/*.js",
"types": "./dist/*.d.ts"
}
},
"main": "./dist/index.js",
"registry": "https://registry.npmjs.org/",
"types": "./dist/index.d.ts"
}
}

View File

@@ -1 +0,0 @@
export * from './dist/adapters/s3'

View File

@@ -1 +0,0 @@
exports.s3Adapter = require('./dist/adapters/s3').s3Adapter

View File

@@ -22,10 +22,27 @@ export const azureBlobStorageAdapter = ({
connectionString,
containerName,
}: Args): Adapter => {
if (!BlobServiceClient) {
throw new Error(
'The package @azure/storage-blob is not installed, but is required for the plugin-cloud-storage Azure adapter. Please install it.',
)
}
let storageClient: ContainerClient | null = null
const getStorageClient = () => {
if (storageClient) return storageClient
const blobServiceClient = BlobServiceClient.fromConnectionString(connectionString)
let blobServiceClient = null
try {
blobServiceClient = BlobServiceClient.fromConnectionString(connectionString)
} catch (error) {
if (/is not a constructor$/.test(error.message)) {
throw new Error(
'The package @azure/storage-blob is not installed, but is required for the plugin-cloud-storage Azure adapter. Please install it.',
)
}
// Re-throw other unexpected errors.
throw error
}
return (storageClient = blobServiceClient.getContainerClient(containerName))
}

View File

@@ -18,11 +18,27 @@ export interface Args {
export const gcsAdapter =
({ acl, bucket, options }: Args): Adapter =>
({ collection, prefix }): GeneratedAdapter => {
if (!Storage) {
throw new Error(
'The package @google-cloud/storage is not installed, but is required for the plugin-cloud-storage GCS adapter. Please install it.',
)
}
let storageClient: Storage | null = null
const getStorageClient = (): Storage => {
if (storageClient) return storageClient
storageClient = new Storage(options)
try {
storageClient = new Storage(options)
} catch (error) {
if (/is not a constructor$/.test(error.message)) {
throw new Error(
'The package @google-cloud/storage is not installed, but is required for the plugin-cloud-storage GCS adapter. Please install it.',
)
}
// Re-throw other unexpected errors.
throw error
}
return storageClient
}

View File

@@ -26,10 +26,25 @@ export interface Args {
export const s3Adapter =
({ acl, bucket, config = {} }: Args): Adapter =>
({ collection, prefix }): GeneratedAdapter => {
if (!AWS) {
throw new Error(
'The packages @aws-sdk/client-s3, @aws-sdk/lib-storage and aws-crt are not installed, but are required for the plugin-cloud-storage S3 adapter. Please install them.',
)
}
let storageClient: AWS.S3 | null = null
const getStorageClient: () => AWS.S3 = () => {
if (storageClient) return storageClient
storageClient = new AWS.S3(config)
try {
storageClient = new AWS.S3(config)
} catch (error) {
if (/is not a constructor$/.test(error.message)) {
throw new Error(
'The packages @aws-sdk/client-s3, @aws-sdk/lib-storage and aws-crt are not installed, but are required for the plugin-cloud-storage S3 adapter. Please install them.',
)
}
// Re-throw other unexpected errors.
throw error
}
return storageClient
}

View File

@@ -0,0 +1 @@
export { azureBlobStorageAdapter } from '../adapters/azure/index.js'

View File

@@ -0,0 +1 @@
export { gcsAdapter } from '../adapters/gcs/index.js'

View File

@@ -0,0 +1 @@
export { s3Adapter } from '../adapters/s3/index.js'

View File

@@ -1,7 +1,7 @@
{
"name": "@payloadcms/plugin-cloud",
"description": "The official Payload Cloud plugin",
"version": "3.0.0-alpha.46",
"version": "3.0.0-alpha.48",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"license": "MIT",

View File

@@ -1,6 +1,6 @@
{
"name": "@payloadcms/plugin-nested-docs",
"version": "3.0.0-alpha.46",
"version": "3.0.0-alpha.48",
"description": "The official Nested Docs plugin for Payload",
"repository": "https://github.com/payloadcms/payload",
"license": "MIT",

View File

@@ -1,6 +1,6 @@
{
"name": "@payloadcms/plugin-redirects",
"version": "3.0.0-alpha.46",
"version": "3.0.0-alpha.48",
"homepage:": "https://payloadcms.com",
"repository": "git@github.com:payloadcms/plugin-redirects.git",
"description": "Redirects plugin for Payload",

View File

@@ -1,6 +1,6 @@
{
"name": "@payloadcms/plugin-search",
"version": "3.0.0-alpha.46",
"version": "3.0.0-alpha.48",
"homepage:": "https://payloadcms.com",
"repository": "git@github.com:payloadcms/plugin-search.git",
"description": "Search plugin for Payload",

View File

@@ -1,6 +1,6 @@
{
"name": "@payloadcms/plugin-seo",
"version": "3.0.0-alpha.46",
"version": "3.0.0-alpha.48",
"homepage:": "https://payloadcms.com",
"repository": "git@github.com:payloadcms/plugin-seo.git",
"description": "SEO plugin for Payload",

View File

@@ -23,7 +23,7 @@ type MetaDescriptionProps = FormFieldBase & {
export const MetaDescription: React.FC<MetaDescriptionProps> = (props) => {
const { Label, hasGenerateDescriptionFn, path, required } = props
const { path: pathFromContext, schemaPath } = useFieldPath()
const { path: pathFromContext } = useFieldPath()
const { t } = useTranslation()

View File

@@ -23,7 +23,7 @@ type MetaImageProps = UploadInputProps & {
}
export const MetaImage: React.FC<MetaImageProps> = (props) => {
const { Label, hasGenerateImageFn, path, relationTo, required } = props || {}
const { Label, hasGenerateImageFn, relationTo, required } = props || {}
const field: FieldType<string> = useField(props as Options)

View File

@@ -28,7 +28,7 @@ type MetaTitleProps = FormFieldBase & {
export const MetaTitle: React.FC<MetaTitleProps> = (props) => {
const { Label, hasGenerateTitleFn, path, required } = props || {}
const { path: pathFromContext, schemaPath } = useFieldPath()
const { path: pathFromContext } = useFieldPath()
const { t } = useTranslation()

View File

@@ -15,7 +15,7 @@ import type {
import { MetaDescription } from './fields/MetaDescription.js'
import { MetaImage } from './fields/MetaImage.js'
import { MetaTitle } from './fields/MetaTitle.js'
import translations from './translations/index.js'
import { translations } from './translations/index.js'
import { Overview } from './ui/Overview.js'
import { Preview } from './ui/Preview.js'
@@ -139,8 +139,8 @@ const seo =
tabs: [
// append a new tab onto the end of the tabs array, if there is one at the first index
// if needed, create a new `Content` tab in the first index for this collection's base fields
...(collection?.fields?.[0]?.type === 'tabs'
? collection.fields[0]?.tabs
...(collection?.fields?.[0]?.type === 'tabs' && collection?.fields?.[0]?.tabs
? collection.fields[0].tabs
: [
{
fields: [
@@ -234,8 +234,8 @@ const seo =
tabs: [
// append a new tab onto the end of the tabs array, if there is one at the first index
// if needed, create a new `Content` tab in the first index for this global's base fields
...(global?.fields?.[0].type === 'tabs'
? global.fields[0]?.tabs
...(global?.fields?.[0].type === 'tabs' && global?.fields?.[0].tabs
? global.fields[0].tabs
: [
{
fields: [...(global?.fields || [])],
@@ -254,7 +254,7 @@ const seo =
...global,
fields: [
...seoTabs,
...(global?.fields?.[0].type === 'tabs' ? global?.fields?.slice(1) : []),
...(global?.fields?.[0].type === 'tabs' ? global.fields.slice(1) : []),
],
}
}
@@ -276,4 +276,4 @@ const seo =
}
}
export default seo
export { seo }

View File

@@ -4,10 +4,4 @@ import fa from './fa.json'
import fr from './fr.json'
import pl from './pl.json'
export default {
en,
es,
fa,
fr,
pl,
}
export const translations = { en, es, fa, fr, pl }

View File

@@ -72,7 +72,7 @@ export const LengthIndicator: React.FC<{
setBarWidth(1)
}
}
}, [minLength, maxLength, text])
}, [minLength, maxLength, text, t])
const textLength = text?.length || 0

View File

@@ -1,32 +0,0 @@
import type { Config } from 'payload/config'
import type { Configuration as WebpackConfig } from 'webpack'
import path from 'path'
export const extendWebpackConfig =
(config: Config): ((webpackConfig: WebpackConfig) => WebpackConfig) =>
(webpackConfig) => {
const existingWebpackConfig =
typeof config.admin?.webpack === 'function'
? config.admin.webpack(webpackConfig)
: webpackConfig
const mockModulePath = path.resolve(__dirname, './mocks/mockFile.js')
return {
...existingWebpackConfig,
resolve: {
...(existingWebpackConfig.resolve || {}),
alias: {
...(existingWebpackConfig.resolve?.alias ? existingWebpackConfig.resolve.alias : {}),
'@payloadcms/plugin-stripe': path.resolve(__dirname, './admin.js'),
express: mockModulePath,
[path.resolve(__dirname, './hooks/createNewInStripe')]: mockModulePath,
[path.resolve(__dirname, './hooks/deleteFromStripe')]: mockModulePath,
[path.resolve(__dirname, './hooks/syncExistingWithStripe')]: mockModulePath,
[path.resolve(__dirname, './routes/rest')]: mockModulePath,
[path.resolve(__dirname, './routes/webhooks')]: mockModulePath,
},
},
}
}

View File

@@ -1,18 +1,13 @@
import type { NextFunction, Response } from 'express'
import type { Config, Endpoint } from 'payload/config'
import type { PayloadRequest } from 'payload/types'
import express from 'express'
import type { SanitizedStripeConfig, StripeConfig } from './types.js'
import type { SanitizedStripeConfig, StripeConfig } from './types'
import { extendWebpackConfig } from './extendWebpackConfig'
import { getFields } from './fields/getFields'
import { createNewInStripe } from './hooks/createNewInStripe'
import { deleteFromStripe } from './hooks/deleteFromStripe'
import { syncExistingWithStripe } from './hooks/syncExistingWithStripe'
import { stripeREST } from './routes/rest'
import { stripeWebhooks } from './routes/webhooks'
import { getFields } from './fields/getFields.js'
import { createNewInStripe } from './hooks/createNewInStripe.js'
import { deleteFromStripe } from './hooks/deleteFromStripe.js'
import { syncExistingWithStripe } from './hooks/syncExistingWithStripe.js'
import { stripeREST } from './routes/rest.js'
import { stripeWebhooks } from './routes/webhooks.js'
const stripePlugin =
(incomingStripeConfig: StripeConfig) =>
@@ -31,12 +26,40 @@ const stripePlugin =
// unfortunately we must set the 'isTestKey' property on the config instead of using the following code:
// const isTestKey = stripeConfig.stripeSecretKey?.startsWith('sk_test_');
const endpoints: Endpoint[] = [
...(config?.endpoints || []),
{
handler: async (req) => {
const res = await stripeWebhooks({
config,
req,
stripeConfig,
})
return res
},
method: 'post',
path: '/stripe/webhooks',
},
]
if (incomingStripeConfig?.rest) {
endpoints.push({
handler: async (req) => {
const res = await stripeREST({
req,
stripeConfig,
})
return res
},
method: 'post' as Endpoint['method'],
path: '/stripe/rest',
})
}
return {
...config,
admin: {
...config.admin,
webpack: extendWebpackConfig(config),
},
collections: collections?.map((collection) => {
const { hooks: existingHooks } = collection
@@ -86,42 +109,7 @@ const stripePlugin =
return collection
}),
endpoints: [
...(config?.endpoints || []),
{
handler: [
express.raw({ type: 'application/json' }),
async (req, res, next) => {
await stripeWebhooks({
config,
next,
req,
res,
stripeConfig,
})
},
],
method: 'post',
path: '/stripe/webhooks',
root: true,
},
...(incomingStripeConfig?.rest
? [
{
handler: async (req: PayloadRequest, res: Response, next: NextFunction) => {
await stripeREST({
next,
req,
res,
stripeConfig,
})
},
method: 'post' as Endpoint['method'],
path: '/stripe/rest',
},
]
: []),
],
endpoints,
}
}

View File

@@ -1,22 +1,22 @@
import type { Response } from 'express'
import type { PayloadRequest } from 'payload/types'
import { Forbidden } from 'payload/errors'
import type { StripeConfig } from '../types'
import type { StripeConfig } from '../types.js'
import { stripeProxy } from '../utilities/stripeProxy'
import { stripeProxy } from '../utilities/stripeProxy.js'
export const stripeREST = async (args: {
next: any
req: PayloadRequest
res: Response
stripeConfig: StripeConfig
}): Promise<any> => {
const { req, res, stripeConfig } = args
let responseStatus = 200
let responseJSON
const { req, stripeConfig } = args
const {
body: {
data: {
stripeArgs, // example: ['cus_MGgt3Tuj3D66f2'] or [{ limit: 100 }, { stripeAccount: 'acct_1J9Z4pKZ4Z4Z4Z4Z' }]
stripeMethod, // example: 'subscriptions.list',
},
@@ -32,20 +32,26 @@ export const stripeREST = async (args: {
throw new Forbidden(req.t)
}
const pluginRes = await stripeProxy({
responseJSON = await stripeProxy({
stripeArgs,
stripeMethod,
stripeSecretKey,
})
const { status } = pluginRes
res.status(status).json(pluginRes)
const { status } = responseJSON
responseStatus = status
} catch (error: unknown) {
const message = `An error has occurred in the Stripe plugin REST handler: '${error}'`
const message = `An error has occurred in the Stripe plugin REST handler: '${JSON.stringify(
error,
)}'`
payload.logger.error(message)
return res.status(500).json({
responseStatus = 500
responseJSON = {
message,
})
}
}
return Response.json(responseJSON, {
status: responseStatus,
})
}

View File

@@ -1,21 +1,19 @@
import type { Response } from 'express'
import type { Config as PayloadConfig } from 'payload/config'
import type { PayloadRequest } from 'payload/types'
import Stripe from 'stripe'
import type { StripeConfig } from '../types'
import type { StripeConfig } from '../types.js'
import { handleWebhooks } from '../webhooks'
import { handleWebhooks } from '../webhooks/index.js'
export const stripeWebhooks = async (args: {
config: PayloadConfig
next: any
req: PayloadRequest
res: Response
stripeConfig: StripeConfig
}): Promise<any> => {
const { config, req, res, stripeConfig } = args
const { config, req, stripeConfig } = args
let returnStatus = 200
const { stripeSecretKey, stripeWebhooksEndpointSecret, webhooks } = stripeConfig
@@ -28,21 +26,21 @@ export const stripeWebhooks = async (args: {
},
})
const stripeSignature = req.headers['stripe-signature']
const stripeSignature = req.headers.get('stripe-signature')
if (stripeSignature) {
let event: Stripe.Event | undefined
try {
event = stripe.webhooks.constructEvent(
req.body,
await req.text(),
stripeSignature,
stripeWebhooksEndpointSecret,
)
} catch (err: unknown) {
const msg = err instanceof Error ? err.message : err
const msg: string = err instanceof Error ? err.message : JSON.stringify(err)
req.payload.logger.error(`Error constructing Stripe event: ${msg}`)
res.status(400)
returnStatus = 400
}
if (event) {
@@ -81,5 +79,10 @@ export const stripeWebhooks = async (args: {
}
}
res.json({ received: true })
return Response.json(
{ received: true },
{
status: returnStatus,
},
)
}

View File

@@ -1,6 +1,6 @@
{
"name": "@payloadcms/richtext-lexical",
"version": "3.0.0-alpha.46",
"version": "3.0.0-alpha.48",
"description": "The officially supported Lexical richtext adapter for Payload",
"repository": "https://github.com/payloadcms/payload",
"license": "MIT",

View File

@@ -1,6 +1,6 @@
{
"name": "@payloadcms/richtext-slate",
"version": "3.0.0-alpha.46",
"version": "3.0.0-alpha.48",
"description": "The officially supported Slate richtext adapter for Payload",
"repository": "https://github.com/payloadcms/payload",
"license": "MIT",

View File

@@ -5,38 +5,41 @@ These are the translations for Payload. Translations are used on both the server
## How to contribute
#### Updating a translation
1. Open the language file you wish to edit located within the `src/all` folder
2. Update the translation value
3. Run one of the following:
```sh
yarn build
// or
npm build
// or
pnpm build
```
```sh
yarn build
// or
npm build
// or
pnpm build
```
#### Adding a new translation
1. Add the new translation key/value pair for all languages located in the `src/all` folder
2. Open the `src/build.ts` file and add the key to either `clientTranslationKeys` or `serverTranslationKeys` depending on where the translation will be used.
2. Open the `writeTranslationFiles.ts` file and add the key to either `clientTranslationKeys` or `serverTranslationKeys` depending on where the translation will be used.
3. Run one of the following:
```sh
yarn build
// or
npm build
// or
pnpm build
```
```sh
yarn build
// or
npm build
// or
pnpm build
```
#### Adding a new language
1. Create a new JSON file in the `src/all` folder with the language code as the file name (e.g. `en.json` for English)
2. Translate all of the keys in the new file
3. Open the `src/index.ts` file and import your json file and then export it inside the `translations` object
4. Run one of the following:
```sh
yarn build
// or
npm build
// or
pnpm build
```
```sh
yarn build
// or
npm build
// or
pnpm build
```

View File

@@ -1,6 +1,6 @@
{
"name": "@payloadcms/translations",
"version": "3.0.0-alpha.46",
"version": "3.0.0-alpha.48",
"main": "./dist/exports/index.ts",
"types": "./dist/types.d.ts",
"type": "module",

View File

@@ -9,6 +9,7 @@ export default {
changePassword: 'تغيير كلمة المرور',
confirmGeneration: 'تأكيد التّوليد',
confirmPassword: 'تأكيد كلمة المرور',
createFirstUser: 'إنشاء المستخدم الأوّل',
emailNotValid: 'البريد الإلكتروني غير صالح',
emailSent: 'تمّ ارسال البريد الإلكتروني',
enableAPIKey: 'تفعيل مفتاح API',
@@ -51,6 +52,7 @@ export default {
previewing: 'حدث خطأ في اثناء معاينة هذا المستند.',
unableToDeleteCount: 'يتعذّر حذف {{count}} من {{total}} {{label}}.',
unableToUpdateCount: 'يتعذّر تحديث {{count}} من {{total}} {{label}}.',
unauthorized: 'غير مصرّح لك ، عليك أن تقوم بتسجيل الدّخول لتتمكّن من تقديم هذا الطّلب.',
unknown: 'حدث خطأ غير معروف.',
unspecific: 'حدث خطأ.',
},

View File

@@ -9,6 +9,7 @@ export default {
changePassword: 'Parolu dəyişdir',
confirmGeneration: 'Generasiyani təsdiqlə',
confirmPassword: 'Şifrəni təsdiq et',
createFirstUser: 'İlk istifadəçini yaradın',
emailNotValid: 'Təqdim olunan e-poçt etibarlı deyil',
emailSent: 'E-poçt göndərildi',
enableAPIKey: 'API açarını aktivləşdir',
@@ -51,6 +52,7 @@ export default {
previewing: 'Bu sənədin ön baxışı zamanı problem yarandı.',
unableToDeleteCount: '{{count}} dən {{total}} {{label}} silinə bilmir.',
unableToUpdateCount: '{{count}} dən {{total}} {{label}} yenilənə bilmir.',
unauthorized: 'İcazəniz yoxdur, bu tələbi yerinə yetirmək üçün daxil olmalısınız.',
unknown: 'Naməlum bir xəta baş verdi.',
unspecific: 'Xəta baş verdi.',
},

View File

@@ -9,6 +9,7 @@ export default {
changePassword: 'Промяна на паролата',
confirmGeneration: 'Потвърди генерация',
confirmPassword: 'Потвърди парола',
createFirstUser: 'Създай първи потребител',
emailNotValid: 'Даденият имейл не е валиден',
emailSent: 'Имейлът е изпратен',
enableAPIKey: 'Активирай API ключ',
@@ -51,6 +52,7 @@ export default {
previewing: 'Имаше проблем при предварителното разглеждане на документа.',
unableToDeleteCount: 'Не беше възможно да се изтрият {{count}} от {{total}} {{label}}.',
unableToUpdateCount: 'Не беше възможно да се обновят {{count}} от {{total}} {{label}}.',
unauthorized: 'Неавторизиран, трябва да влезеш, за да извършиш тази заявка.',
unknown: 'Неизвестна грешка.',
unspecific: 'Грешка.',
},

View File

@@ -9,6 +9,7 @@ export default {
changePassword: 'Změnit heslo',
confirmGeneration: 'Potvrdit generaci',
confirmPassword: 'Potvrdit heslo',
createFirstUser: 'Vytvořit prvního uživatele',
emailNotValid: 'Zadaný email není platný',
emailSent: 'Email odeslán',
enableAPIKey: 'Povolit klíč API',
@@ -51,6 +52,7 @@ export default {
previewing: 'Při náhledu tohoto dokumentu došlo k chybě.',
unableToDeleteCount: 'Nelze smazat {{count}} z {{total}} {{label}}',
unableToUpdateCount: 'Nelze aktualizovat {{count}} z {{total}} {{label}}.',
unauthorized: 'Neautorizováno, pro zadání tohoto požadavku musíte být přihlášeni.',
unknown: 'Došlo k neznámé chybě.',
unspecific: 'Došlo k chybě.',
},

View File

@@ -9,6 +9,7 @@ export default {
changePassword: 'Passwort ändern',
confirmGeneration: 'Generierung bestätigen',
confirmPassword: 'Passwort bestätigen',
createFirstUser: 'Ersten Benutzer erstellen',
emailNotValid: 'Die angegebene E-Mail-Adresse ist ungültig',
emailSent: 'E-Mail verschickt',
enableAPIKey: 'API-Key aktivieren',
@@ -51,6 +52,7 @@ export default {
previewing: 'Es gab ein Problem beim Vorschauen dieses Dokuments.',
unableToDeleteCount: '{{count}} von {{total}} {{label}} konnte nicht gelöscht werden.',
unableToUpdateCount: '{{count}} von {{total}} {{label}} konnte nicht aktualisiert werden.',
unauthorized: 'Nicht autorisiert - du musst angemeldet sein, um diese Anfrage zu stellen.',
unknown: 'Ein unbekannter Fehler ist aufgetreten.',
unspecific: 'Ein Fehler ist aufgetreten.',
},

View File

@@ -9,6 +9,7 @@ export default {
changePassword: 'Change Password',
confirmGeneration: 'Confirm Generation',
confirmPassword: 'Confirm Password',
createFirstUser: 'Create first user',
emailNotValid: 'The email provided is not valid',
emailSent: 'Email Sent',
enableAPIKey: 'Enable API Key',
@@ -53,6 +54,7 @@ export default {
previewing: 'There was a problem previewing this document.',
unableToDeleteCount: 'Unable to delete {{count}} out of {{total}} {{label}}.',
unableToUpdateCount: 'Unable to update {{count}} out of {{total}} {{label}}.',
unauthorized: 'Unauthorized, you must be logged in to make this request.',
unknown: 'An unknown error has occurred.',
unspecific: 'An error has occurred.',
},

View File

@@ -9,6 +9,7 @@ export default {
changePassword: 'Cambiar contraseña',
confirmGeneration: 'Confirmar Generación',
confirmPassword: 'Confirmar Contraseña',
createFirstUser: 'Crear al primer usuario',
emailNotValid: 'El correo proporcionado es inválido',
emailSent: 'Correo Enviado',
enableAPIKey: 'Habilitar Clave API',
@@ -51,6 +52,7 @@ export default {
previewing: 'Ocurrió un problema al previsualizar este documento.',
unableToDeleteCount: 'No se pudo eliminar {{count}} de {{total}} {{label}}.',
unableToUpdateCount: 'No se puede actualizar {{count}} de {{total}} {{label}}.',
unauthorized: 'No autorizado, debes iniciar sesión para realizar esta solicitud.',
unknown: 'Ocurrió un error desconocido.',
unspecific: 'Ocurrió un error.',
},

View File

@@ -9,6 +9,7 @@ export default {
changePassword: 'تغییر گذرواژه',
confirmGeneration: 'تأیید ساخت',
confirmPassword: 'تأیید گذرواژه',
createFirstUser: 'ایجاد کاربر نخست',
emailNotValid: 'رایانامه ارائه‌شده درست نیست',
emailSent: 'رایانامه فرستاده شد',
enableAPIKey: 'فعال‌سازی کلید اِی‌پی‌آی',
@@ -50,6 +51,7 @@ export default {
previewing: 'مشکلی در پیش‌نمایش این رسانه رخ داد.',
unableToDeleteCount: 'نمی‌توان {{count}} از {{total}} {{label}} را حذف کرد.',
unableToUpdateCount: 'امکان به روز رسانی {{count}} خارج از {{total}} {{label}} وجود ندارد.',
unauthorized: 'درخواست نامعتبر، جهت فرستادن این درخواست باید وارد شوید.',
unknown: 'یک خطای ناشناخته رخ داد.',
unspecific: 'خطایی رخ داد.',
},

View File

@@ -9,6 +9,7 @@ export default {
changePassword: 'Changer le mot de passe',
confirmGeneration: 'Confirmer la génération',
confirmPassword: 'Confirmez le mot de passe',
createFirstUser: 'Créer le premier utilisateur',
emailNotValid: "L'adresse e-mail fourni n'est pas valide",
emailSent: 'E-mail envoyé',
enableAPIKey: 'Activer la clé API',
@@ -52,6 +53,7 @@ export default {
previewing: "Un problème est survenu lors de l'aperçu de ce document.",
unableToDeleteCount: 'Impossible de supprimer {{count}} sur {{total}} {{label}}.',
unableToUpdateCount: 'Impossible de mettre à jour {{count}} sur {{total}} {{label}}.',
unauthorized: 'Non autorisé, vous devez être connecté pour effectuer cette demande.',
unknown: "Une erreur inconnue s'est produite.",
unspecific: 'Une erreur est survenue.',
},

View File

@@ -9,6 +9,7 @@ export default {
changePassword: 'Promjeni lozinku',
confirmGeneration: 'Potvrdi kreiranje',
confirmPassword: 'Potvrdi lozinku',
createFirstUser: 'Kreiraj prvog korisnika',
emailNotValid: 'Email nije ispravan',
emailSent: 'Email poslan',
enableAPIKey: 'Omogući API ključ',
@@ -51,6 +52,7 @@ export default {
previewing: 'Pojavio se problem pri pregledavanju ovog dokumenta.',
unableToDeleteCount: 'Nije moguće izbrisati {{count}} od {{total}} {{label}}.',
unableToUpdateCount: 'Nije moguće ažurirati {{count}} od {{total}} {{label}}.',
unauthorized: 'Neovlašten, morate biti prijavljeni da biste uputili ovaj zahtjev.',
unknown: 'Došlo je do nepoznate pogreške.',
unspecific: 'Došlo je do pogreške.',
},

View File

@@ -9,6 +9,7 @@ export default {
changePassword: 'Jelszó módosítása',
confirmGeneration: 'Generálás megerősítése',
confirmPassword: 'Jelszó megerősítése',
createFirstUser: 'Első felhasználó létrehozása',
emailNotValid: 'A megadott e-mail cím érvénytelen',
emailSent: 'E-mail elküldve',
enableAPIKey: 'API-kulcs engedélyezése',
@@ -51,6 +52,7 @@ export default {
previewing: 'Hiba történt a dokumentum előnézetének megtekintése közben.',
unableToDeleteCount: 'Nem sikerült törölni {{count}}/{{total}} {{label}}.',
unableToUpdateCount: 'Nem sikerült frissíteni {{count}}/{{total}} {{label}}.',
unauthorized: 'Jogosulatlan, a kéréshez be kell jelentkeznie.',
unknown: 'Ismeretlen hiba történt.',
unspecific: 'Hiba történt.',
},

View File

@@ -9,6 +9,7 @@ export default {
changePassword: 'Cambia Password',
confirmGeneration: 'Conferma Generazione',
confirmPassword: 'Conferma Password',
createFirstUser: 'Crea il primo utente',
emailNotValid: "L'email fornita non è valida",
emailSent: 'Email Inviata',
enableAPIKey: 'Abilita la Chiave API',
@@ -53,6 +54,7 @@ export default {
previewing: "Si è verificato un problema durante l'anteprima di questo documento.",
unableToDeleteCount: 'Impossibile eliminare {{count}} su {{total}} {{label}}.',
unableToUpdateCount: 'Impossibile aggiornare {{count}} su {{total}} {{label}}.',
unauthorized: 'Non autorizzato, devi essere loggato per effettuare questa richiesta.',
unknown: 'Si è verificato un errore sconosciuto.',
unspecific: 'Si è verificato un errore.',
},

View File

@@ -9,6 +9,7 @@ export default {
changePassword: 'パスワードを変更',
confirmGeneration: '生成の確認',
confirmPassword: 'パスワードの確認',
createFirstUser: '最初のユーザーを作成',
emailNotValid: '入力されたメールアドレスは無効です。',
emailSent: 'Emailが送信されました。',
enableAPIKey: 'API Keyを許可',
@@ -53,6 +54,7 @@ export default {
previewing: 'このデータをプレビューする際に問題が発生しました。',
unableToDeleteCount: '{{total}} {{label}} から {{count}} を削除できません。',
unableToUpdateCount: '{{total}} {{label}} のうち {{count}} 個を更新できません。',
unauthorized: '認証されていません。このリクエストを行うにはログインが必要です。',
unknown: '不明なエラーが発生しました。',
unspecific: 'エラーが発生しました。',
},

View File

@@ -9,6 +9,7 @@ export default {
changePassword: '비밀번호 변경',
confirmGeneration: '생성 확인',
confirmPassword: '비밀번호 확인',
createFirstUser: '첫 번째 사용자 생성',
emailNotValid: '입력한 이메일은 유효하지 않습니다.',
emailSent: '이메일 전송됨',
enableAPIKey: 'API 키 활성화',
@@ -51,6 +52,7 @@ export default {
previewing: '이 문서를 미리보는 중에 문제가 발생했습니다.',
unableToDeleteCount: '총 {{total}}개 중 {{count}}개의 {{label}}을(를) 삭제할 수 없습니다.',
unableToUpdateCount: '총 {{total}}개 중 {{count}}개의 {{label}}을(를) 업데이트할 수 없습니다.',
unauthorized: '권한 없음, 이 요청을 수행하려면 로그인해야 합니다.',
unknown: '알 수 없는 오류가 발생했습니다.',
unspecific: '오류가 발생했습니다.',
},

View File

@@ -9,6 +9,7 @@ export default {
changePassword: 'စကားဝှက် ပြောင်းလဲမည်။',
confirmGeneration: 'Generation အတည်ပြု',
confirmPassword: 'စကားဝှက်အား ထပ်မံ ရိုက်ထည့်ပါ။',
createFirstUser: 'ပထမဆုံး အသုံးပြုသူကို ဖန်တီးပါ။',
emailNotValid: 'ထည့်သွင်းထားသော အီးမေလ်မှာ မှားယွင်းနေပါသည်။',
emailSent: 'မေးလ် ပို့ထားပါသည်။',
enableAPIKey: 'API Key ကိုဖွင့်ရန်',
@@ -51,6 +52,7 @@ export default {
previewing: 'ဖိုင်ကို အစမ်းကြည့်ရန် ပြဿနာရှိနေသည်။',
unableToDeleteCount: '{{total}} {{label}} မှ {{count}} ကို ဖျက်၍မရပါ။',
unableToUpdateCount: '{{total}} {{label}} မှ {{count}} ကို အပ်ဒိတ်လုပ်၍မရပါ။',
unauthorized: 'အခွင့်မရှိပါ။ ဤတောင်းဆိုချက်ကို လုပ်ဆောင်နိုင်ရန် သင်သည် လော့ဂ်အင်ဝင်ရပါမည်။',
unknown: 'ဘာမှန်းမသိသော error တက်သွားပါသည်။',
unspecific: 'Error တက်နေပါသည်။',
},

View File

@@ -9,6 +9,7 @@ export default {
changePassword: 'Endre passord',
confirmGeneration: 'Bekreft generering',
confirmPassword: 'Bekreft passord',
createFirstUser: 'Opprett første bruker',
emailNotValid: 'E-posten er ikke gyldig',
emailSent: 'E-post sendt',
enableAPIKey: 'Aktiver API-nøkkel',
@@ -51,6 +52,7 @@ export default {
previewing: 'Det oppstod et problem under forhåndsvisning av dokumentet.',
unableToDeleteCount: 'Kan ikke slette {{count}} av {{total}} {{label}}.',
unableToUpdateCount: 'Kan ikke oppdatere {{count}} av {{total}} {{label}}.',
unauthorized: 'Uautorisert, du må være innlogget for å gjøre denne forespørselen.',
unknown: 'En ukjent feil har oppstått.',
unspecific: 'En feil har oppstått.',
},

View File

@@ -9,6 +9,7 @@ export default {
changePassword: 'Wachtwoord wijzigen',
confirmGeneration: 'Bevestigen',
confirmPassword: 'Wachtwoord bevestigen',
createFirstUser: 'Eerste gebruiker aanmaken',
emailNotValid: 'Het ingevoerde e-mailadres is niet geldig',
emailSent: 'E-mail verzonden',
enableAPIKey: 'Activeer API-sleutel',
@@ -51,6 +52,7 @@ export default {
previewing: 'Er was een probleem met het voorvertonen van dit document.',
unableToDeleteCount: 'Kan {{count}} van {{total}} {{label}} niet verwijderen.',
unableToUpdateCount: 'Kan {{count}} van {{total}} {{label}} niet updaten.',
unauthorized: 'Ongeautoriseerd, u moet ingelogd zijn om dit verzoek te doen.',
unknown: 'Er is een onbekende fout opgetreden.',
unspecific: 'Er is een fout opgetreden.',
},

View File

@@ -9,6 +9,7 @@ export default {
changePassword: 'Zmień hasło',
confirmGeneration: 'Potwierdź wygenerowanie',
confirmPassword: 'Potwierdź hasło',
createFirstUser: 'Utwórz pierwszego użytkownika',
emailNotValid: 'Podany email jest nieprawidłowy',
emailSent: 'Wysłano email',
enableAPIKey: 'Aktywuj klucz API',
@@ -51,6 +52,7 @@ export default {
previewing: 'Wystąpił problem podczas podglądu tego dokumentu.',
unableToDeleteCount: 'Nie można usunąć {{count}} z {{total}} {{label}}.',
unableToUpdateCount: 'Nie można zaktualizować {{count}} z {{total}} {{label}}.',
unauthorized: 'Brak dostępu, musisz być zalogowany.',
unknown: 'Wystąpił nieznany błąd.',
unspecific: 'Wystąpił błąd',
},

View File

@@ -9,6 +9,7 @@ export default {
changePassword: 'Mudar senha',
confirmGeneration: 'Confirmar Geração',
confirmPassword: 'Confirmar Senha',
createFirstUser: 'Criar primeiro usuário',
emailNotValid: 'O email fornecido não é válido',
emailSent: 'Email Enviado',
enableAPIKey: 'Habilitar Chave API',
@@ -51,6 +52,7 @@ export default {
previewing: 'Ocorreu um problema ao visualizar esse documento.',
unableToDeleteCount: 'Não é possível excluir {{count}} de {{total}} {{label}}.',
unableToUpdateCount: 'Não foi possível atualizar {{count}} de {{total}} {{label}}.',
unauthorized: 'Não autorizado. Você deve estar logado para fazer essa requisição',
unknown: 'Ocorreu um erro desconhecido.',
unspecific: 'Ocorreu um erro.',
},

View File

@@ -9,6 +9,7 @@ export default {
changePassword: 'Schimbați parola',
confirmGeneration: 'Confirmați generarea',
confirmPassword: 'Confirmați parola',
createFirstUser: 'Creați primul utilizator',
emailNotValid: 'Emailul furnizat nu este valid',
emailSent: 'Email trimis',
enableAPIKey: 'Activați cheia API',
@@ -51,6 +52,7 @@ export default {
previewing: 'A existat o problemă la previzualizarea acestui document.',
unableToDeleteCount: 'Nu se poate șterge {{count}} din {{total}} {{label}}.',
unableToUpdateCount: 'Nu se poate șterge {{count}} din {{total}} {{label}}.',
unauthorized: 'neautorizat, trebuie să vă conectați pentru a face această cerere.',
unknown: 'S-a produs o eroare necunoscută.',
unspecific: 'S-a produs o eroare.',
},

View File

@@ -9,6 +9,7 @@ export default {
changePassword: 'Promeni lozinku',
confirmGeneration: 'Potvrdi kreiranje',
confirmPassword: 'Potvrdi lozinku',
createFirstUser: 'Kreiraj prvog korisnika',
emailNotValid: 'Adresa e-pošte nije validna',
emailSent: 'Poruka e-pošte prosleđena',
enableAPIKey: 'Omogući API ključ',
@@ -51,6 +52,7 @@ export default {
previewing: 'Postoji problem pri pregledu ovog dokumenta.',
unableToDeleteCount: 'Nije moguće izbrisati {{count}} od {{total}} {{label}}.',
unableToUpdateCount: 'Nije moguće ažurirati {{count}} od {{total}} {{label}}.',
unauthorized: 'Niste autorizovani da biste uputili ovaj zahtev.',
unknown: 'Došlo je do nepoznate greške.',
unspecific: 'Došlo je do greške.',
},

View File

@@ -9,6 +9,7 @@ export default {
changePassword: 'Промени лозинку',
confirmGeneration: 'Потврди креирање',
confirmPassword: 'Потврди лозинку',
createFirstUser: 'Креирај првог корисника',
emailNotValid: 'Адреса е-поште није валидна',
emailSent: 'Порука е-поште прослеђена',
enableAPIKey: 'Омогући API кључ',
@@ -51,6 +52,7 @@ export default {
previewing: 'Постоји проблем при прегледу овог документа.',
unableToDeleteCount: 'Није могуће избрисати {{count}} од {{total}} {{label}}.',
unableToUpdateCount: 'Није могуће ажурирати {{count}} од {{total}} {{label}}.',
unauthorized: 'Нисте ауторизовани да бисте упутили овај захтев.',
unknown: 'Дошло је до непознате грешке.',
unspecific: 'Дошло је до грешке.',
},

View File

@@ -9,6 +9,7 @@ export default {
changePassword: 'Сменить пароль',
confirmGeneration: 'Подтвердить генерацию',
confirmPassword: 'Подтверждение пароля',
createFirstUser: 'Создание первого пользователя',
emailNotValid: 'Указанный адрес электронной почты неверен',
emailSent: 'Email отправлен',
enableAPIKey: 'Активировать API ключ',
@@ -51,6 +52,7 @@ export default {
previewing: 'При предварительном просмотре этого документа возникла проблема.',
unableToDeleteCount: 'Не удалось удалить {{count}} из {{total}} {{label}}.',
unableToUpdateCount: 'Не удалось обновить {{count}} из {{total}} {{label}}.',
unauthorized: 'Нет доступа, вы должны войти, чтобы сделать этот запрос.',
unknown: 'Произошла неизвестная ошибка.',
unspecific: 'Произошла ошибка.',
},

View File

@@ -9,6 +9,7 @@ export default {
changePassword: 'Byt Lösenord',
confirmGeneration: 'Bekräfta Generering',
confirmPassword: 'Bekräfta Lösenord',
createFirstUser: 'Skapa första användaren',
emailNotValid: 'Angiven e-postadress är inte giltig',
emailSent: 'E-posten Skickad',
enableAPIKey: 'Aktivera API nyckel',
@@ -51,6 +52,7 @@ export default {
previewing: 'Det uppstod ett problem när det här dokumentet skulle förhandsgranskas.',
unableToDeleteCount: 'Det gick inte att ta bort {{count}} av {{total}} {{label}}.',
unableToUpdateCount: 'Det gick inte att uppdatera {{count}} av {{total}} {{label}}.',
unauthorized: 'Obehörig, du måste vara inloggad för att göra denna begäran.',
unknown: 'Ett okänt fel har uppstått.',
unspecific: 'Ett fel har uppstått.',
},

View File

@@ -9,6 +9,7 @@ export default {
changePassword: 'เปลี่ยนรหัสผ่าน',
confirmGeneration: 'ยืนยันการสร้าง',
confirmPassword: 'ยืนยันรหัสผ่าน',
createFirstUser: 'สร้างผู้ใช้แรก',
emailNotValid: 'อีเมลไม่ถูกต้อง',
emailSent: 'ส่งอีเมลเรียบร้อยแล้ว',
enableAPIKey: 'เปิดใช้ API Key',
@@ -50,6 +51,7 @@ export default {
previewing: 'เกิดปัญหาระหว่างการแสดงตัวอย่างเอกสาร',
unableToDeleteCount: 'ไม่สามารถลบ {{count}} จาก {{total}} {{label}}',
unableToUpdateCount: 'ไม่สามารถอัปเดต {{count}} จาก {{total}} {{label}}',
unauthorized: 'คุณไม่ได้รับอนุญาต กรุณาเข้าสู่ระบบเพื่อทำคำขอนี้',
unknown: 'เกิดปัญหาบางอย่างที่ไม่ทราบสาเหตุ',
unspecific: 'เกิดปัญหาบางอย่าง',
},

View File

@@ -9,6 +9,7 @@ export default {
changePassword: 'Parolayı Değiştir',
confirmGeneration: 'Oluştumayı Onayla',
confirmPassword: 'Parolayı Onayla',
createFirstUser: 'İlk kullanıcı oluştur',
emailNotValid: 'Girilen e-posta geçersiz',
emailSent: 'E-posta gönderildi',
enableAPIKey: 'Api anahtarını etkinleştir',
@@ -51,6 +52,7 @@ export default {
previewing: 'Önizleme başarısız oldu',
unableToDeleteCount: '{{total}} {{label}} içinden {{count}} silinemiyor.',
unableToUpdateCount: '{{total}} {{label}} içinden {{count}} güncellenemiyor.',
unauthorized: 'Bu işlemi gerçekleştirmek için lütfen giriş yapın.',
unknown: 'Bilinmeyen bir hata oluştu.',
unspecific: 'Bir hata oluştu.',
},

View File

@@ -9,6 +9,7 @@ export default {
changePassword: 'Змінити пароль',
confirmGeneration: 'Підтвердити генерацію',
confirmPassword: 'Підтвердження паролю',
createFirstUser: 'Створення першого користувача',
emailNotValid: 'Вказана адреса електронної пошти недійсна',
emailSent: 'Лист відправлено',
enableAPIKey: 'Активувати API ключ',
@@ -51,6 +52,7 @@ export default {
previewing: 'Виникла помилка під час попереднього перегляду цього документа.',
unableToDeleteCount: 'Не вдалося видалити {{count}} із {{total}} {{label}}.',
unableToUpdateCount: 'Не вдалося оновити {{count}} із {{total}} {{label}}.',
unauthorized: 'Немає доступу, ви повинні увійти, щоб виконати цей запит.',
unknown: 'Виникла невідома помилка.',
unspecific: 'Виникла помилка.',
},

View File

@@ -9,6 +9,7 @@ export default {
changePassword: 'Đổi mật khẩu',
confirmGeneration: 'Xác nhận, tạo API Key',
confirmPassword: 'Xác nhận mật khẩu',
createFirstUser: 'Tạo người dùng đầu tiên',
emailNotValid: 'Email không chính xác',
emailSent: 'Email đã được gửi',
enableAPIKey: 'Kích hoạt API Key',
@@ -50,6 +51,7 @@ export default {
previewing: 'Lỗi - Đã xảy ra vấn đề khi xem trước bản tài liệu này.',
unableToDeleteCount: 'Không thể xóa {{count}} trong số {{total}} {{label}}.',
unableToUpdateCount: 'Không thể cập nhật {{count}} trên {{total}} {{label}}.',
unauthorized: 'Lỗi - Bạn cần phải đăng nhập trước khi gửi request sau.',
unknown: 'Lỗi - Không xác định (unknown error).',
unspecific: 'Lỗi - Đã xảy ra (unspecific error).',
},

View File

@@ -9,6 +9,7 @@ export default {
changePassword: '更改密碼',
confirmGeneration: '確認生成',
confirmPassword: '確認密碼',
createFirstUser: '建立第一個使用者',
emailNotValid: '提供的電子郵件無效',
emailSent: '電子郵件已寄出',
enableAPIKey: '啟用API金鑰',
@@ -52,6 +53,7 @@ export default {
previewing: '預覽文件時出現了問題。',
unableToDeleteCount: '無法從 {{total}} 個中刪除 {{count}} 個 {{label}}。',
unableToUpdateCount: '無法從 {{total}} 個中更新 {{count}} 個 {{label}}。',
unauthorized: '未經授權,您必須登錄才能提出這個請求。',
unknown: '發生了一個未知的錯誤。',
unspecific: '發生了一個錯誤。',
},

View File

@@ -9,6 +9,7 @@ export default {
changePassword: '更改密码',
confirmGeneration: '确认生成',
confirmPassword: '确认密码',
createFirstUser: '创建第一个用户',
emailNotValid: '所提供的电子邮件时无效的',
emailSent: '电子邮件已发送',
enableAPIKey: '启用API密钥',
@@ -50,6 +51,7 @@ export default {
previewing: '预览文件时出现了问题。',
unableToDeleteCount: '无法从 {{total}} {{label}} 中删除 {{count}}。',
unableToUpdateCount: '无法更新 {{count}} 个,共 {{total}} 个 {{label}}。',
unauthorized: '未经授权,您必须登录才能提出这个请求。',
unknown: '发生了一个未知的错误。',
unspecific: '发生了一个错误。',
},

Some files were not shown because too many files have changed in this diff Show More