diff --git a/packages/sanity/src/core/components/index.ts b/packages/sanity/src/core/components/index.ts index 8f94ba95874..71fd7ad4366 100644 --- a/packages/sanity/src/core/components/index.ts +++ b/packages/sanity/src/core/components/index.ts @@ -23,3 +23,4 @@ export * from './transitional' export * from './userAvatar' export * from './WithReferringDocuments' export * from './zOffsets' +export * from './RelativeTime' diff --git a/packages/sanity/src/core/i18n/Translate.tsx b/packages/sanity/src/core/i18n/Translate.tsx index ffe6041d933..89bfa32fa9a 100644 --- a/packages/sanity/src/core/i18n/Translate.tsx +++ b/packages/sanity/src/core/i18n/Translate.tsx @@ -2,7 +2,10 @@ import React, {ComponentType, ReactNode, useMemo} from 'react' import type {TFunction} from 'i18next' import {CloseTagToken, simpleParser, TextToken, Token} from './simpleParser' -type ComponentMap = Record> +type ComponentMap = Record< + string, + ComponentType<{children?: ReactNode}> | keyof JSX.IntrinsicElements +> /** * @beta @@ -11,7 +14,7 @@ export interface TranslationProps { t: TFunction i18nKey: string components: ComponentMap - values?: Record + values?: Record } function render(tokens: Token[], componentMap: ComponentMap): ReactNode { diff --git a/packages/sanity/src/desk/components/DocTitle.tsx b/packages/sanity/src/desk/components/DocTitle.tsx index 261cbbdce5c..40780cb9f84 100644 --- a/packages/sanity/src/desk/components/DocTitle.tsx +++ b/packages/sanity/src/desk/components/DocTitle.tsx @@ -1,6 +1,7 @@ import {SanityDocumentLike} from '@sanity/types' import React from 'react' -import {useSchema, unstable_useValuePreview as useValuePreview} from 'sanity' +import {deskLocaleNamespace} from '../i18n' +import {useSchema, useTranslation, unstable_useValuePreview as useValuePreview} from 'sanity' export interface DocTitleProps { document: SanityDocumentLike @@ -10,6 +11,7 @@ export function DocTitle(props: DocTitleProps) { const {document: documentValue} = props const schema = useSchema() const schemaType = schema.get(documentValue._type) + const {t} = useTranslation(deskLocaleNamespace) const {error, value} = useValuePreview({ schemaType: schemaType!, @@ -17,12 +19,18 @@ export function DocTitle(props: DocTitleProps) { }) if (!schemaType) { - return Unknown schema type: {documentValue._type} + return {t('doc-title.unknown-schema-type.text', {schemaType: documentValue._type})} } if (error) { - return <>Error: {error.message} + return <>{t('doc-title.error.text', {errorMessage: error.message})} } - return <>{value?.title || Untitled} + return ( + <> + {value?.title || ( + {t('doc-title.fallback.text')} + )} + + ) } diff --git a/packages/sanity/src/desk/components/DraftStatus.tsx b/packages/sanity/src/desk/components/DraftStatus.tsx index 19c2e04b2fa..563c3713afd 100644 --- a/packages/sanity/src/desk/components/DraftStatus.tsx +++ b/packages/sanity/src/desk/components/DraftStatus.tsx @@ -2,12 +2,13 @@ import React from 'react' import {EditIcon} from '@sanity/icons' import {PreviewValue, SanityDocument} from '@sanity/types' import {Box, Text, Tooltip} from '@sanity/ui' -import {TimeAgo} from './TimeAgo' -import {TextWithTone} from 'sanity' +import {deskLocaleNamespace} from '../i18n' +import {TextWithTone, Translate, useTranslation, RelativeTime} from 'sanity' export function DraftStatus(props: {document?: PreviewValue | Partial | null}) { const {document} = props const updatedAt = document && '_updatedAt' in document && document._updatedAt + const {t} = useTranslation(deskLocaleNamespace) return ( {document ? ( - <>Edited {updatedAt && } + ( + <>{updatedAt && } + ), + }} + /> ) : ( - <>No unpublished edits + t('pane-item.draft-status.no-draft.tooltip') )} diff --git a/packages/sanity/src/desk/components/MissingDocumentTypesMessage.tsx b/packages/sanity/src/desk/components/MissingDocumentTypesMessage.tsx deleted file mode 100644 index 06f882cdf18..00000000000 --- a/packages/sanity/src/desk/components/MissingDocumentTypesMessage.tsx +++ /dev/null @@ -1,63 +0,0 @@ -import React from 'react' -import {Box, Card, Container, Flex, Stack, Text} from '@sanity/ui' -import {WarningOutlineIcon} from '@sanity/icons' -import {useSource} from 'sanity' - -export function MissingDocumentTypesMessage() { - const {name: sourceName} = useSource() - - return ( - - - - - - - - - - - - - No schema types in the {sourceName} source! - - - Please add schema types in your source configuration. - - - - Learn how to add a schema types → - - - - - - - - - {/* - - Empty schema - - - Your schema does not contain any document types. If it did, those types would be listed - here.{' '} - - Read more about how to add schema types - - . - - - */} - - ) -} diff --git a/packages/sanity/src/desk/components/MissingSchemaType.tsx b/packages/sanity/src/desk/components/MissingSchemaType.tsx index fdc8f2f0b95..da3f4f6c6e9 100644 --- a/packages/sanity/src/desk/components/MissingSchemaType.tsx +++ b/packages/sanity/src/desk/components/MissingSchemaType.tsx @@ -1,31 +1,41 @@ import {WarningOutlineIcon} from '@sanity/icons' import {SanityDocument} from '@sanity/types' import React from 'react' -import {GeneralPreviewLayoutKey, SanityDefaultPreview} from 'sanity' +import {deskLocaleNamespace} from '../i18n' +import {GeneralPreviewLayoutKey, SanityDefaultPreview, Translate, useTranslation} from 'sanity' export interface MissingSchemaTypeProps { layout?: GeneralPreviewLayoutKey value: SanityDocument } -const getUnknownTypeFallback = (id: string, typeName: string) => ({ - title: ( - - No schema found for type {typeName} - - ), - subtitle: ( - - Document: {id} - - ), - media: () => , -}) - export function MissingSchemaType(props: MissingSchemaTypeProps) { + const {t} = useTranslation(deskLocaleNamespace) const {layout, value} = props return ( - + + + + } + subtitle={ + + } + // eslint-disable-next-line react/jsx-no-bind + media={() => } + layout={layout} + /> ) } diff --git a/packages/sanity/src/desk/components/NotPublishedStatus.tsx b/packages/sanity/src/desk/components/NotPublishedStatus.tsx deleted file mode 100644 index 58bffa5d6d6..00000000000 --- a/packages/sanity/src/desk/components/NotPublishedStatus.tsx +++ /dev/null @@ -1,13 +0,0 @@ -import React from 'react' -import {UnpublishIcon} from '@sanity/icons' -import {Text, Tooltip} from '@sanity/ui' - -export function NotPublishedStatus() { - return ( - Not published}> - - - - - ) -} diff --git a/packages/sanity/src/desk/components/PublishedStatus.tsx b/packages/sanity/src/desk/components/PublishedStatus.tsx index 0f257979df1..baf381920b7 100644 --- a/packages/sanity/src/desk/components/PublishedStatus.tsx +++ b/packages/sanity/src/desk/components/PublishedStatus.tsx @@ -2,13 +2,14 @@ import React from 'react' import {PublishIcon} from '@sanity/icons' import {PreviewValue, SanityDocument} from '@sanity/types' import {Box, Text, Tooltip} from '@sanity/ui' -import {TimeAgo} from './TimeAgo' -import {TextWithTone} from 'sanity' +import {deskLocaleNamespace} from '../i18n' +import {RelativeTime, TextWithTone, Translate, useTranslation} from 'sanity' export function PublishedStatus(props: {document?: PreviewValue | Partial | null}) { const {document} = props const updatedAt = document && '_updatedAt' in document && document._updatedAt const statusLabel = document ? 'Published' : 'Not published' + const {t} = useTranslation(deskLocaleNamespace) return ( {document ? ( - <>Published {updatedAt && } + ( + <>{updatedAt && } + ), + }} + /> ) : ( - <>Not published + t('pane-item.published-status.no-published.tooltip') )} diff --git a/packages/sanity/src/desk/components/ReferringDocumentsList.tsx b/packages/sanity/src/desk/components/ReferringDocumentsList.tsx deleted file mode 100644 index f82aee1bd9c..00000000000 --- a/packages/sanity/src/desk/components/ReferringDocumentsList.tsx +++ /dev/null @@ -1,73 +0,0 @@ -import {EditIcon} from '@sanity/icons' -import {Box, Card, Flex, Stack, Text} from '@sanity/ui' -import React, {useCallback, useMemo} from 'react' -import {useRouter} from 'sanity/router' -import {useSchema, Preview} from 'sanity' - -export interface ReferringDocumentsListProps { - documents: Record[] -} - -export function ReferringDocumentsList(props: ReferringDocumentsListProps) { - const {documents} = props - - return ( - - - {documents.map((document) => ( - - ))} - - - ) -} - -interface DocumentPreviewLinkProps { - document: Record -} - -function DocumentPreviewLink(props: DocumentPreviewLinkProps) { - const {document} = props - const schema = useSchema() - const router = useRouter() - const intent = useMemo( - () => ({action: 'edit', params: {id: document._id, type: document._type}}), - [document], - ) - const href = router.resolveIntentLink(intent.action, intent.params) - const schemaType = schema.get(document._type) - - const handleClick = useCallback( - (event: any) => { - if (event.shiftKey || event.metaKey) return - event.preventDefault() - router.navigateIntent(intent.action, intent.params) - }, - [intent, router], - ) - - if (!schemaType) { - return ( - - A document of the unknown type {document._type} - - ) - } - - return ( - - - - - - {document._hasDraft && ( - - - - - - )} - - - ) -} diff --git a/packages/sanity/src/desk/components/TimeAgo.tsx b/packages/sanity/src/desk/components/TimeAgo.tsx deleted file mode 100644 index b3ae9c1290d..00000000000 --- a/packages/sanity/src/desk/components/TimeAgo.tsx +++ /dev/null @@ -1,16 +0,0 @@ -import React from 'react' -import {useRelativeTime} from 'sanity' - -export interface TimeAgoProps { - time: string | Date -} - -/** - * @deprecated Use {@link RelativeTime} instead - * @internal - */ -export function TimeAgo({time}: TimeAgoProps) { - const timeAgo = useRelativeTime(time) - - return {timeAgo} ago -} diff --git a/packages/sanity/src/desk/components/confirmDeleteDialog/ConfirmDeleteDialog.tsx b/packages/sanity/src/desk/components/confirmDeleteDialog/ConfirmDeleteDialog.tsx index bbe98e93da5..1ef6b098c8d 100644 --- a/packages/sanity/src/desk/components/confirmDeleteDialog/ConfirmDeleteDialog.tsx +++ b/packages/sanity/src/desk/components/confirmDeleteDialog/ConfirmDeleteDialog.tsx @@ -2,8 +2,10 @@ import React, {useMemo, useId} from 'react' import styled from 'styled-components' import {Box, Dialog, Button, Text, Spinner, Grid, Flex} from '@sanity/ui' import {DocTitle} from '../DocTitle' +import {deskLocaleNamespace} from '../../i18n' import {useReferringDocuments} from './useReferringDocuments' import {ConfirmDeleteDialogBody} from './ConfirmDeleteDialogBody' +import {useTranslation} from 'sanity' /** @internal */ export const DialogBody = styled(Box).attrs({ @@ -37,7 +39,7 @@ export interface ConfirmDeleteDialogProps { * The name of the action being done. (e.g. the `'unpublish'` action requires * the same document deletion confirmation). */ - action?: string + action?: 'delete' | 'unpublish' onCancel: () => void onConfirm: () => void } @@ -56,6 +58,7 @@ export function ConfirmDeleteDialog({ onCancel, onConfirm, }: ConfirmDeleteDialogProps) { + const {t} = useTranslation(deskLocaleNamespace) const dialogId = `deletion-confirmation-${useId()}` const { internalReferences, @@ -66,8 +69,6 @@ export function ConfirmDeleteDialog({ datasetNames, hasUnknownDatasetNames, } = useReferringDocuments(id) - const capitalizedAction = `${action.substring(0, 1).toUpperCase()}${action.substring(1)}` - const documentTitle = ({_id: id, _type: type}), [id, type])} /> const showConfirmButton = !isLoading @@ -75,15 +76,23 @@ export function ConfirmDeleteDialog({ - ) : ( diff --git a/packages/sanity/src/desk/components/deskTool/NoDocumentTypesScreen.tsx b/packages/sanity/src/desk/components/deskTool/NoDocumentTypesScreen.tsx index 9ec8c561df5..b80f7766f7a 100644 --- a/packages/sanity/src/desk/components/deskTool/NoDocumentTypesScreen.tsx +++ b/packages/sanity/src/desk/components/deskTool/NoDocumentTypesScreen.tsx @@ -1,8 +1,12 @@ import {WarningOutlineIcon} from '@sanity/icons' import {Box, Card, Container, Flex, Stack, Text} from '@sanity/ui' import React from 'react' +import {deskLocaleNamespace} from '../../i18n' +import {useTranslation} from 'sanity' export function NoDocumentTypesScreen() { + const {t} = useTranslation(deskLocaleNamespace) + return ( @@ -16,10 +20,10 @@ export function NoDocumentTypesScreen() { - No document types + {t('no-document-types-screen.title')} - Please define at least one document type in your schema. + {t('no-document-types-screen.subtitle')} - Learn how to add a document type → + {t('no-document-types-screen.link-text')} diff --git a/packages/sanity/src/desk/components/deskTool/StructureError.tsx b/packages/sanity/src/desk/components/deskTool/StructureError.tsx index 7c75783a73b..badcb4635b9 100644 --- a/packages/sanity/src/desk/components/deskTool/StructureError.tsx +++ b/packages/sanity/src/desk/components/deskTool/StructureError.tsx @@ -5,6 +5,8 @@ import styled from 'styled-components' import {SyncIcon} from '@sanity/icons' import {SerializeError} from '../../structureBuilder' import {PaneResolutionError} from '../../structureResolvers' +import {deskLocaleNamespace} from '../../i18n' +import {useTranslation} from 'sanity' const PathSegment = styled.span` &:not(:last-child)::after { @@ -36,6 +38,7 @@ export function StructureError({error}: StructureErrorProps) { throw error } const {cause} = error + const {t} = useTranslation(deskLocaleNamespace) // Serialize errors are well-formatted and should be readable, in these cases a stack trace is // usually not helpful. Build errors in dev (with HMR) usually also contains a bunch of garbage @@ -54,12 +57,12 @@ export function StructureError({error}: StructureErrorProps) { return ( - Encountered an error while reading structure + {t('structure-error.header.text')} {path.length > 0 && ( - + {/* TODO: it seems like the path is off by one and includes */} {/* `root` twice */} @@ -72,7 +75,7 @@ export function StructureError({error}: StructureErrorProps) { )} - + {showStack ? formatStack(stack) : error.message} @@ -80,14 +83,19 @@ export function StructureError({error}: StructureErrorProps) { - View documentation + {t('structure-error.docs-link.text')} )} -