diff --git a/packages/plugin-search/package.json b/packages/plugin-search/package.json index 6616a91299d..79ee7609074 100644 --- a/packages/plugin-search/package.json +++ b/packages/plugin-search/package.json @@ -41,6 +41,16 @@ "import": "./src/exports/client.ts", "types": "./src/exports/client.ts", "default": "./src/exports/client.ts" + }, + "./translations/languages/all": { + "import": "./src/translations/index.ts", + "types": "./src/translations/index.ts", + "default": "./src/translations/index.ts" + }, + "./translations/languages/*": { + "import": "./src/translations/languages/*.ts", + "types": "./src/translations/languages/*.ts", + "default": "./src/translations/languages/*.ts" } }, "main": "./src/index.ts", @@ -60,6 +70,7 @@ "test": "echo \"Error: no tests specified\"" }, "dependencies": { + "@payloadcms/translations": "workspace:*", "@payloadcms/next": "workspace:*", "@payloadcms/ui": "workspace:*" }, diff --git a/packages/plugin-search/src/Search/index.ts b/packages/plugin-search/src/Search/index.ts index 9fb14dc9e09..4b7c54d95d2 100644 --- a/packages/plugin-search/src/Search/index.ts +++ b/packages/plugin-search/src/Search/index.ts @@ -20,6 +20,8 @@ export const generateSearchCollection = ( admin: { readOnly: true, }, + // @ts-expect-error - translations are not typed in plugins yet + label: ({ t }) => t('plugin-search:resultTitle'), localized: pluginConfig.localize, }, { @@ -28,6 +30,8 @@ export const generateSearchCollection = ( admin: { position: 'sidebar', }, + // @ts-expect-error - translations are not typed in plugins yet + label: ({ t }) => t('plugin-search:resultPriority'), }, { name: 'doc', @@ -37,6 +41,8 @@ export const generateSearchCollection = ( readOnly: true, }, index: true, + // @ts-expect-error - translations are not typed in plugins yet + label: ({ t }) => t('plugin-search:resultDocument'), maxDepth: 0, relationTo: searchCollections, required: true, @@ -52,6 +58,8 @@ export const generateSearchCollection = ( }, position: 'sidebar', }, + // @ts-expect-error - translations are not typed in plugins yet + label: ({ t }) => t('plugin-search:resultDocumentUrl'), }, ] @@ -85,8 +93,8 @@ export const generateSearchCollection = ( }, }, defaultColumns: ['title'], - description: - 'This is a collection of automatically created search results. These results are used by the global site search and will be updated automatically as documents in the CMS are created or updated.', + // @ts-expect-error - translations are not typed in plugins yet + description: ({ t }) => t('plugin-search:searchResultsDescription'), enableRichTextRelationship: false, useAsTitle: 'title', ...(pluginConfig?.searchOverrides?.admin || {}), @@ -106,8 +114,10 @@ export const generateSearchCollection = ( : defaultFields, labels: { ...(pluginConfig?.searchOverrides?.labels || { - plural: 'Search Results', - singular: 'Search Result', + // @ts-expect-error - translations are not typed in plugins yet + plural: ({ t }): string => t('plugin-search:searchResults'), + // @ts-expect-error - translations are not typed in plugins yet + singular: ({ t }): string => t('plugin-search:searchResult'), }), }, versions: pluginConfig?.searchOverrides?.versions ?? false, diff --git a/packages/plugin-search/src/Search/ui/LinkToDoc/index.client.tsx b/packages/plugin-search/src/Search/ui/LinkToDoc/index.client.tsx index 94d42373072..e6a72dd9d66 100644 --- a/packages/plugin-search/src/Search/ui/LinkToDoc/index.client.tsx +++ b/packages/plugin-search/src/Search/ui/LinkToDoc/index.client.tsx @@ -1,15 +1,14 @@ 'use client' -import { CopyToClipboard, FieldLabel, Link, useConfig, useField } from '@payloadcms/ui' +import { CopyToClipboard, Link, useConfig, useField, useTranslation } from '@payloadcms/ui' import { formatAdminURL } from 'payload/shared' import React from 'react' -import './index.css' +import type { PluginSearchTranslationKeys, PluginSearchTranslations } from '../../../translations/index.js' -const baseClass = 'link-to-doc' - -export const LinkToDocClient: React.FC = () => { +export const LinkToDocClient: React.FC<{ label?: React.JSX.Element | string }> = ({ label }) => { const { config } = useConfig() + const { t } = useTranslation() const { routes: { @@ -31,9 +30,16 @@ export const LinkToDocClient: React.FC = () => { }) return ( -
-
- +
+
+ + {typeof label === 'string' ? label : t('plugin-search:resultDocumentUrl')} +
diff --git a/packages/plugin-search/src/Search/ui/LinkToDoc/index.tsx b/packages/plugin-search/src/Search/ui/LinkToDoc/index.tsx index 3b3a8185a57..a79586ded20 100644 --- a/packages/plugin-search/src/Search/ui/LinkToDoc/index.tsx +++ b/packages/plugin-search/src/Search/ui/LinkToDoc/index.tsx @@ -1,9 +1,13 @@ -import type { UIField } from 'payload' +import type { UIFieldServerComponent } from 'payload' +import { getTranslation } from '@payloadcms/translations' import React from 'react' import { LinkToDocClient } from './index.client.js' -export const LinkToDoc: React.FC = () => { - return +export const LinkToDoc: UIFieldServerComponent = ({ field, i18n }) => { + const label = field.label ? getTranslation(field.label, + i18n, + ) : undefined + return } diff --git a/packages/plugin-search/src/Search/ui/ReindexButton/index.tsx b/packages/plugin-search/src/Search/ui/ReindexButton/index.tsx index 6f08a481fb5..7da129bf64c 100644 --- a/packages/plugin-search/src/Search/ui/ReindexButton/index.tsx +++ b/packages/plugin-search/src/Search/ui/ReindexButton/index.tsx @@ -12,8 +12,7 @@ export const ReindexButton: SearchReindexButtonServerComponent = (props) => { const pluralLabel = labels?.plural if (typeof pluralLabel === 'function') { - // @ts-expect-error - I don't know why it gives an error. pluralLabel and i18n.t should both resolve to TFunction - return [collection, pluralLabel({ t: i18n.t })] + return [collection, pluralLabel({ i18n, t: i18n.t })] } if (pluralLabel) { diff --git a/packages/plugin-search/src/index.ts b/packages/plugin-search/src/index.ts index ea28d9ccb0a..1fa4b483934 100644 --- a/packages/plugin-search/src/index.ts +++ b/packages/plugin-search/src/index.ts @@ -2,11 +2,16 @@ import type { CollectionAfterChangeHook } from 'payload' import { definePlugin } from 'payload' +import { deepMergeSimple } from 'payload/shared' + import type { SanitizedSearchPluginConfig, SearchPluginConfig } from './types.js' import { deleteFromSearch } from './Search/hooks/deleteFromSearch.js' import { syncWithSearch } from './Search/hooks/syncWithSearch.js' import { generateSearchCollection } from './Search/index.js' +import { translations } from './translations/index.js' + +export { translations as searchTranslations } from './translations/index.js' type CollectionAfterChangeHookArgs = Parameters[0] @@ -83,6 +88,10 @@ export const searchPlugin = definePlugin({ ...(collectionsWithSearchHooks || []), generateSearchCollection(pluginConfig), ], + i18n: { + ...config.i18n, + translations: deepMergeSimple(translations, config.i18n?.translations ?? {}), + }, } } diff --git a/packages/plugin-search/src/translations/index.ts b/packages/plugin-search/src/translations/index.ts new file mode 100644 index 00000000000..8db3181865e --- /dev/null +++ b/packages/plugin-search/src/translations/index.ts @@ -0,0 +1,15 @@ +import type { GenericTranslationsObject, NestedKeysStripped } from '@payloadcms/translations' + +import { de } from './languages/de.js' +import { en } from './languages/en.js' +import { it } from './languages/it.js' + +export const translations = { + de, + en, + it, +} + +export type PluginSearchTranslations = GenericTranslationsObject + +export type PluginSearchTranslationKeys = NestedKeysStripped diff --git a/packages/plugin-search/src/translations/languages/de.ts b/packages/plugin-search/src/translations/languages/de.ts new file mode 100644 index 00000000000..ea2376b1ab4 --- /dev/null +++ b/packages/plugin-search/src/translations/languages/de.ts @@ -0,0 +1,15 @@ +import type { GenericTranslationsObject } from '@payloadcms/translations' + +export const de: GenericTranslationsObject = { + $schema: '../translation-schema.json', + 'plugin-search': { + resultDocument: 'Dokument', + resultDocumentUrl: 'Dokumenten-URL', + resultPriority: 'Priorität', + resultTitle: 'Titel', + searchResult: 'Suchergebnis', + searchResults: 'Suchergebnisse', + searchResultsDescription: + 'Dies ist eine Sammlung automatisch erstellter Suchergebnisse. Diese Ergebnisse werden von der globalen Site-Suche verwendet und automatisch aktualisiert, wenn Dokumente im CMS erstellt oder aktualisiert werden.', + }, +} diff --git a/packages/plugin-search/src/translations/languages/en.ts b/packages/plugin-search/src/translations/languages/en.ts new file mode 100644 index 00000000000..927dfaa9bb1 --- /dev/null +++ b/packages/plugin-search/src/translations/languages/en.ts @@ -0,0 +1,15 @@ +import type { GenericTranslationsObject } from '@payloadcms/translations' + +export const en: GenericTranslationsObject = { + $schema: '../translation-schema.json', + 'plugin-search': { + resultDocument: 'Document', + resultDocumentUrl: 'Document URL', + resultPriority: 'Priority', + resultTitle: 'Title', + searchResult: 'Search Result', + searchResults: 'Search Results', + searchResultsDescription: + 'This is a collection of automatically created search results. These results are used by the global site search and will be updated automatically as documents in the CMS are created or updated.', + }, +} diff --git a/packages/plugin-search/src/translations/languages/it.ts b/packages/plugin-search/src/translations/languages/it.ts new file mode 100644 index 00000000000..99db1c4486e --- /dev/null +++ b/packages/plugin-search/src/translations/languages/it.ts @@ -0,0 +1,15 @@ +import type { GenericTranslationsObject } from '@payloadcms/translations' + +export const it: GenericTranslationsObject = { + $schema: '../translation-schema.json', + 'plugin-search': { + resultDocument: 'Documento', + resultDocumentUrl: 'URL del documento', + resultPriority: 'Priorità', + resultTitle: 'Titolo', + searchResult: 'Risultato della ricerca', + searchResults: 'Risultati della ricerca', + searchResultsDescription: + 'Questa è una raccolta di risultati di ricerca creati automaticamente. Questi risultati sono utilizzati dalla ricerca globale del sito e verranno aggiornati automaticamente quando i documenti nel CMS vengono creati o aggiornati.', + }, +} diff --git a/packages/plugin-search/src/translations/translation-schema.json b/packages/plugin-search/src/translations/translation-schema.json new file mode 100644 index 00000000000..61b8c7be5d4 --- /dev/null +++ b/packages/plugin-search/src/translations/translation-schema.json @@ -0,0 +1,47 @@ +{ + "type": "object", + "$schema": "http://json-schema.org/draft-04/schema#", + "additionalProperties": false, + "properties": { + "$schema": { + "type": "string" + }, + "plugin-search": { + "type": "object", + "additionalProperties": false, + "properties": { + "resultDocument": { + "type": "string" + }, + "resultDocumentUrl": { + "type": "string" + }, + "resultPriority": { + "type": "string" + }, + "resultTitle": { + "type": "string" + }, + "searchResult": { + "type": "string" + }, + "searchResults": { + "type": "string" + }, + "searchResultsDescription": { + "type": "string" + } + }, + "required": [ + "resultDocument", + "resultDocumentUrl", + "resultPriority", + "resultTitle", + "searchResult", + "searchResults", + "searchResultsDescription" + ] + } + }, + "required": ["plugin-search"] +} diff --git a/packages/plugin-search/src/translations/types.ts b/packages/plugin-search/src/translations/types.ts new file mode 100644 index 00000000000..97b072aed80 --- /dev/null +++ b/packages/plugin-search/src/translations/types.ts @@ -0,0 +1,3 @@ +import type { en } from './languages/en.js' + +export type PluginDefaultTranslationsObject = typeof en diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a6f8e375471..6a8042a5819 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1287,6 +1287,9 @@ importers: '@payloadcms/next': specifier: workspace:* version: link:../next + '@payloadcms/translations': + specifier: workspace:* + version: link:../translations '@payloadcms/ui': specifier: workspace:* version: link:../ui diff --git a/test/plugin-search/payload-types.ts b/test/plugin-search/payload-types.ts index 2df2eda9f54..164c5047c9a 100644 --- a/test/plugin-search/payload-types.ts +++ b/test/plugin-search/payload-types.ts @@ -208,8 +208,6 @@ export interface FilteredLocale { createdAt: string; } /** - * This is a collection of automatically created search results. These results are used by the global site search and will be updated automatically as documents in the CMS are created or updated. - * * This interface was referenced by `Config`'s JSON-Schema * via the `definition` "search". */ diff --git a/test/plugin-search/seed/index.ts b/test/plugin-search/seed/index.ts index 769fbd5e2f9..ed49764af56 100644 --- a/test/plugin-search/seed/index.ts +++ b/test/plugin-search/seed/index.ts @@ -14,6 +14,65 @@ export const seed = async (payload: Payload): Promise => { req, }) + await payload.create({ + collection: 'pages', + data: { + title: 'Page 1', + _status: 'published', + }, + }) + + await payload.create({ + collection: 'pages', + data: { + title: 'Page 2', + _status: 'published', + }, + }) + + await payload.create({ + collection: 'pages', + data: { + title: 'Page 3', + _status: 'published', + }, + }) + + await payload.create({ + collection: 'pages', + data: { + title: 'Page 4', + _status: 'published', + }, + }) + + await payload.create({ + collection: 'posts', + data: { + slug: 'post-1', + title: 'Post 1', + _status: 'published', + }, + }) + + await payload.create({ + collection: 'posts', + data: { + slug: 'post-2', + title: 'Post 2', + _status: 'published', + }, + }) + + await payload.create({ + collection: 'posts', + data: { + slug: 'post-3', + title: 'Post 3', + _status: 'published', + }, + }) + return true } catch (err) { console.error(err)