diff --git a/eslint.config.js b/eslint.config.js index b63fa17cc4..f808f18b4d 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -74,6 +74,7 @@ export const rootEslintConfig = [ 'no-console': 'off', 'perfectionist/sort-object-types': 'off', 'perfectionist/sort-objects': 'off', + 'payload/no-relative-monorepo-imports': 'off', }, }, ] diff --git a/packages/plugin-multi-tenant/package.json b/packages/plugin-multi-tenant/package.json index 573c98b489..fb4d6e804d 100644 --- a/packages/plugin-multi-tenant/package.json +++ b/packages/plugin-multi-tenant/package.json @@ -56,6 +56,16 @@ "import": "./src/exports/utilities.ts", "types": "./src/exports/utilities.ts", "default": "./src/exports/utilities.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", @@ -118,6 +128,16 @@ "import": "./dist/exports/utilities.js", "types": "./dist/exports/utilities.d.ts", "default": "./dist/exports/utilities.js" + }, + "./translations/languages/all": { + "import": "./dist/translations/index.js", + "types": "./dist/translations/index.d.ts", + "default": "./dist/translations/index.js" + }, + "./translations/languages/*": { + "import": "./dist/translations/languages/*.js", + "types": "./dist/translations/languages/*.d.ts", + "default": "./dist/translations/languages/*.js" } }, "main": "./dist/index.js", diff --git a/packages/plugin-multi-tenant/src/components/TenantSelector/index.tsx b/packages/plugin-multi-tenant/src/components/TenantSelector/index.tsx index 38d11df84a..16cba01693 100644 --- a/packages/plugin-multi-tenant/src/components/TenantSelector/index.tsx +++ b/packages/plugin-multi-tenant/src/components/TenantSelector/index.tsx @@ -3,18 +3,52 @@ import type { ReactSelectOption } from '@payloadcms/ui' import type { ViewTypes } from 'payload' import { getTranslation } from '@payloadcms/translations' -import { SelectInput, useTranslation } from '@payloadcms/ui' +import { + ConfirmationModal, + SelectInput, + Translation, + useModal, + useTranslation, +} from '@payloadcms/ui' import React from 'react' +import type { + PluginMultiTenantTranslationKeys, + PluginMultiTenantTranslations, +} from '../../translations/index.js' + import { useTenantSelection } from '../../providers/TenantSelectionProvider/index.client.js' import './index.scss' -export const TenantSelector = ({ label, viewType }: { label: string; viewType?: ViewTypes }) => { - const { options, selectedTenantID, setTenant } = useTenantSelection() - const { i18n } = useTranslation() +const confirmSwitchTenantSlug = 'confirmSwitchTenant' - const handleChange = React.useCallback( - (option: ReactSelectOption | ReactSelectOption[]) => { +export const TenantSelector = ({ label, viewType }: { label: string; viewType?: ViewTypes }) => { + const { options, preventRefreshOnChange, selectedTenantID, setTenant } = useTenantSelection() + const { openModal } = useModal() + const { i18n, t } = useTranslation< + PluginMultiTenantTranslations, + PluginMultiTenantTranslationKeys + >() + const [tenantSelection, setTenantSelection] = React.useState< + ReactSelectOption | ReactSelectOption[] + >() + + const selectedValue = React.useMemo(() => { + if (selectedTenantID) { + return options.find((option) => option.value === selectedTenantID) + } + return undefined + }, [options, selectedTenantID]) + + const newSelectedValue = React.useMemo(() => { + if (tenantSelection && 'value' in tenantSelection) { + return options.find((option) => option.value === tenantSelection.value) + } + return undefined + }, [options, tenantSelection]) + + const switchTenant = React.useCallback( + (option: ReactSelectOption | ReactSelectOption[] | undefined) => { if (option && 'value' in option) { setTenant({ id: option.value as string, refresh: true }) } else { @@ -24,6 +58,19 @@ export const TenantSelector = ({ label, viewType }: { label: string; viewType?: [setTenant], ) + const onChange = React.useCallback( + (option: ReactSelectOption | ReactSelectOption[]) => { + if (!preventRefreshOnChange) { + switchTenant(option) + return + } else { + setTenantSelection(option) + openModal(confirmSwitchTenantSlug) + } + }, + [openModal, preventRefreshOnChange, switchTenant], + ) + if (options.length <= 1) { return null } @@ -34,11 +81,46 @@ export const TenantSelector = ({ label, viewType }: { label: string; viewType?: isClearable={viewType === 'list'} label={getTranslation(label, i18n)} name="setTenant" - onChange={handleChange} + onChange={onChange} options={options} path="setTenant" value={selectedTenantID as string | undefined} /> + + { + return {children} + }, + }} + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-expect-error + i18nKey="plugin-multi-tenant:confirm-tenant-switch--body" + t={t} + variables={{ + fromTenant: selectedValue?.label, + toTenant: newSelectedValue?.label, + }} + /> + } + heading={ + + } + modalSlug={confirmSwitchTenantSlug} + onConfirm={() => { + switchTenant(tenantSelection) + }} + /> ) } diff --git a/packages/plugin-multi-tenant/src/components/WatchTenantCollection/index.tsx b/packages/plugin-multi-tenant/src/components/WatchTenantCollection/index.tsx new file mode 100644 index 0000000000..b20a559b31 --- /dev/null +++ b/packages/plugin-multi-tenant/src/components/WatchTenantCollection/index.tsx @@ -0,0 +1,35 @@ +'use client' + +import type { ClientCollectionConfig } from 'payload' + +import { useConfig, useDocumentInfo, useEffectEvent, useFormFields } from '@payloadcms/ui' +import React from 'react' + +import { useTenantSelection } from '../../providers/TenantSelectionProvider/index.client.js' + +export const WatchTenantCollection = () => { + const { id, collectionSlug, title } = useDocumentInfo() + const { getEntityConfig } = useConfig() + const [useAsTitleName] = React.useState( + () => (getEntityConfig({ collectionSlug }) as ClientCollectionConfig).admin.useAsTitle, + ) + const titleField = useFormFields(([fields]) => fields[useAsTitleName]) + + const { updateTenants } = useTenantSelection() + + const syncTenantTitle = useEffectEvent(() => { + if (id) { + updateTenants({ id, label: title }) + } + }) + + React.useEffect(() => { + // only update the tenant selector when the document saves + // → aka when initial value changes + if (id && titleField?.initialValue) { + syncTenantTitle() + } + }, [id, titleField?.initialValue]) + + return null +} diff --git a/packages/plugin-multi-tenant/src/exports/client.ts b/packages/plugin-multi-tenant/src/exports/client.ts index cd6fb65b94..d14df7a70c 100644 --- a/packages/plugin-multi-tenant/src/exports/client.ts +++ b/packages/plugin-multi-tenant/src/exports/client.ts @@ -1,3 +1,4 @@ export { TenantField } from '../components/TenantField/index.client.js' export { TenantSelector } from '../components/TenantSelector/index.js' +export { WatchTenantCollection } from '../components/WatchTenantCollection/index.js' export { useTenantSelection } from '../providers/TenantSelectionProvider/index.client.js' diff --git a/packages/plugin-multi-tenant/src/index.ts b/packages/plugin-multi-tenant/src/index.ts index 6d5bf30859..4b47f24594 100644 --- a/packages/plugin-multi-tenant/src/index.ts +++ b/packages/plugin-multi-tenant/src/index.ts @@ -1,6 +1,9 @@ import type { AcceptedLanguages } from '@payloadcms/translations' import type { CollectionConfig, Config } from 'payload' +import { deepMergeSimple } from 'payload' + +import type { PluginDefaultTranslationsObject } from './translations/types.js' import type { MultiTenantPluginConfig } from './types.js' import { defaults } from './defaults.js' @@ -10,6 +13,7 @@ import { addTenantCleanup } from './hooks/afterTenantDelete.js' import { filterDocumentsBySelectedTenant } from './list-filters/filterDocumentsBySelectedTenant.js' import { filterTenantsBySelectedTenant } from './list-filters/filterTenantsBySelectedTenant.js' import { filterUsersBySelectedTenant } from './list-filters/filterUsersBySelectedTenant.js' +import { translations } from './translations/index.js' import { addCollectionAccess } from './utilities/addCollectionAccess.js' import { addFilterOptionsToFields } from './utilities/addFilterOptionsToFields.js' import { combineListFilters } from './utilities/combineListFilters.js' @@ -229,6 +233,21 @@ export const multiTenantPlugin = usersTenantsArrayTenantFieldName: tenantsArrayTenantFieldName, }) } + + /** + * Add custom tenant field that watches and dispatches updates to the selector + */ + collection.fields.push({ + name: '_watchTenant', + type: 'ui', + admin: { + components: { + Field: { + path: '@payloadcms/plugin-multi-tenant/client#WatchTenantCollection', + }, + }, + }, + }) } else if (pluginConfig.collections?.[collection.slug]) { const isGlobal = Boolean(pluginConfig.collections[collection.slug]?.isGlobal) @@ -340,5 +359,25 @@ export const multiTenantPlugin = path: '@payloadcms/plugin-multi-tenant/client#TenantSelector', }) + /** + * Merge plugin translations + */ + + const simplifiedTranslations = Object.entries(translations).reduce( + (acc, [key, value]) => { + acc[key] = value.translations + return acc + }, + {} as Record, + ) + + incomingConfig.i18n = { + ...incomingConfig.i18n, + translations: deepMergeSimple( + simplifiedTranslations, + incomingConfig.i18n?.translations ?? {}, + ), + } + return incomingConfig } diff --git a/packages/plugin-multi-tenant/src/providers/TenantSelectionProvider/index.client.tsx b/packages/plugin-multi-tenant/src/providers/TenantSelectionProvider/index.client.tsx index 4aad06e231..be7828e36b 100644 --- a/packages/plugin-multi-tenant/src/providers/TenantSelectionProvider/index.client.tsx +++ b/packages/plugin-multi-tenant/src/providers/TenantSelectionProvider/index.client.tsx @@ -11,6 +11,7 @@ type ContextType = { * Array of options to select from */ options: OptionObject[] + preventRefreshOnChange: boolean /** * The currently selected tenant ID */ @@ -28,20 +29,26 @@ type ContextType = { * @param args.refresh - Whether to refresh the page after changing the tenant */ setTenant: (args: { id: number | string | undefined; refresh?: boolean }) => void + /** + * + */ + updateTenants: (args: { id: number | string; label: string }) => void } const Context = createContext({ options: [], + preventRefreshOnChange: false, selectedTenantID: undefined, setPreventRefreshOnChange: () => null, setTenant: () => null, + updateTenants: () => null, }) export const TenantSelectionProviderClient = ({ children, initialValue, tenantCookie, - tenantOptions, + tenantOptions: tenantOptionsFromProps, }: { children: React.ReactNode initialValue?: number | string @@ -54,6 +61,9 @@ export const TenantSelectionProviderClient = ({ const [preventRefreshOnChange, setPreventRefreshOnChange] = React.useState(false) const { user } = useAuth() const userID = React.useMemo(() => user?.id, [user?.id]) + const [tenantOptions, setTenantOptions] = React.useState( + () => tenantOptionsFromProps, + ) const selectedTenantLabel = React.useMemo( () => tenantOptions.find((option) => option.value === selectedTenantID)?.label, [selectedTenantID, tenantOptions], @@ -91,6 +101,20 @@ export const TenantSelectionProviderClient = ({ [deleteCookie, preventRefreshOnChange, router, setCookie, setSelectedTenantID, tenantOptions], ) + const updateTenants = React.useCallback(({ id, label }) => { + setTenantOptions((prev) => { + return prev.map((currentTenant) => { + if (id === currentTenant.value) { + return { + label, + value: id, + } + } + return currentTenant + }) + }) + }, []) + React.useEffect(() => { if (selectedTenantID && !tenantOptions.find((option) => option.value === selectedTenantID)) { if (tenantOptions?.[0]?.value) { @@ -105,13 +129,14 @@ export const TenantSelectionProviderClient = ({ if (userID && !tenantCookie) { // User is logged in, but does not have a tenant cookie, set it setSelectedTenantID(initialValue) + setTenantOptions(tenantOptionsFromProps) if (initialValue) { setCookie(String(initialValue)) } else { deleteCookie() } } - }, [userID, tenantCookie, initialValue, setCookie, deleteCookie, router]) + }, [userID, tenantCookie, initialValue, setCookie, deleteCookie, router, tenantOptionsFromProps]) React.useEffect(() => { if (!userID && tenantCookie) { @@ -132,9 +157,11 @@ export const TenantSelectionProviderClient = ({ {children} diff --git a/packages/plugin-multi-tenant/src/translations/index.ts b/packages/plugin-multi-tenant/src/translations/index.ts new file mode 100644 index 0000000000..f8e7816818 --- /dev/null +++ b/packages/plugin-multi-tenant/src/translations/index.ts @@ -0,0 +1,91 @@ +import type { + GenericTranslationsObject, + NestedKeysStripped, + SupportedLanguages, +} from '@payloadcms/translations' + +import type { PluginDefaultTranslationsObject } from './types.js' + +import { ar } from './languages/ar.js' +import { az } from './languages/az.js' +import { bg } from './languages/bg.js' +import { ca } from './languages/ca.js' +import { cs } from './languages/cs.js' +import { da } from './languages/da.js' +import { de } from './languages/de.js' +import { en } from './languages/en.js' +import { es } from './languages/es.js' +import { et } from './languages/et.js' +import { fa } from './languages/fa.js' +import { fr } from './languages/fr.js' +import { he } from './languages/he.js' +import { hr } from './languages/hr.js' +import { hu } from './languages/hu.js' +import { hy } from './languages/hy.js' +import { it } from './languages/it.js' +import { ja } from './languages/ja.js' +import { ko } from './languages/ko.js' +import { lt } from './languages/lt.js' +import { my } from './languages/my.js' +import { nb } from './languages/nb.js' +import { nl } from './languages/nl.js' +import { pl } from './languages/pl.js' +import { pt } from './languages/pt.js' +import { ro } from './languages/ro.js' +import { rs } from './languages/rs.js' +import { rsLatin } from './languages/rsLatin.js' +import { ru } from './languages/ru.js' +import { sk } from './languages/sk.js' +import { sl } from './languages/sl.js' +import { sv } from './languages/sv.js' +import { th } from './languages/th.js' +import { tr } from './languages/tr.js' +import { uk } from './languages/uk.js' +import { vi } from './languages/vi.js' +import { zh } from './languages/zh.js' +import { zhTw } from './languages/zhTw.js' + +export const translations = { + ar, + az, + bg, + ca, + cs, + da, + de, + en, + es, + et, + fa, + fr, + he, + hr, + hu, + hy, + it, + ja, + ko, + lt, + my, + nb, + nl, + pl, + pt, + ro, + rs, + 'rs-latin': rsLatin, + ru, + sk, + sl, + sv, + th, + tr, + uk, + vi, + zh, + 'zh-TW': zhTw, +} as SupportedLanguages + +export type PluginMultiTenantTranslations = GenericTranslationsObject + +export type PluginMultiTenantTranslationKeys = NestedKeysStripped diff --git a/packages/plugin-multi-tenant/src/translations/languages/ar.ts b/packages/plugin-multi-tenant/src/translations/languages/ar.ts new file mode 100644 index 0000000000..ff50feeb56 --- /dev/null +++ b/packages/plugin-multi-tenant/src/translations/languages/ar.ts @@ -0,0 +1,14 @@ +import type { PluginDefaultTranslationsObject, PluginLanguage } from '../types.js' + +export const arTranslations: PluginDefaultTranslationsObject = { + 'plugin-multi-tenant': { + 'confirm-tenant-switch--body': + 'أنت على وشك تغيير الملكية من <0>{{fromTenant}} إلى <0>{{toTenant}}', + 'confirm-tenant-switch--heading': 'تأكيد تغيير {{tenantLabel}}', + }, +} + +export const ar: PluginLanguage = { + dateFNSKey: 'ar', + translations: arTranslations, +} diff --git a/packages/plugin-multi-tenant/src/translations/languages/az.ts b/packages/plugin-multi-tenant/src/translations/languages/az.ts new file mode 100644 index 0000000000..3c7ace19b4 --- /dev/null +++ b/packages/plugin-multi-tenant/src/translations/languages/az.ts @@ -0,0 +1,14 @@ +import type { PluginDefaultTranslationsObject, PluginLanguage } from '../types.js' + +export const azTranslations: PluginDefaultTranslationsObject = { + 'plugin-multi-tenant': { + 'confirm-tenant-switch--body': + 'Siz <0>{{fromTenant}} mülkiyyətini <0>{{toTenant}} mülkiyyətinə dəyişdirəcəksiniz.', + 'confirm-tenant-switch--heading': '{{tenantLabel}} dəyişikliyini təsdiqləyin', + }, +} + +export const az: PluginLanguage = { + dateFNSKey: 'az', + translations: azTranslations, +} diff --git a/packages/plugin-multi-tenant/src/translations/languages/bg.ts b/packages/plugin-multi-tenant/src/translations/languages/bg.ts new file mode 100644 index 0000000000..488b0b9b1a --- /dev/null +++ b/packages/plugin-multi-tenant/src/translations/languages/bg.ts @@ -0,0 +1,14 @@ +import type { PluginDefaultTranslationsObject, PluginLanguage } from '../types.js' + +export const bgTranslations: PluginDefaultTranslationsObject = { + 'plugin-multi-tenant': { + 'confirm-tenant-switch--body': + 'Предстои да промените собствеността от <0>{{fromTenant}} на <0>{{toTenant}}', + 'confirm-tenant-switch--heading': 'Потвърдете промяната на {{tenantLabel}}', + }, +} + +export const bg: PluginLanguage = { + dateFNSKey: 'bg', + translations: bgTranslations, +} diff --git a/packages/plugin-multi-tenant/src/translations/languages/ca.ts b/packages/plugin-multi-tenant/src/translations/languages/ca.ts new file mode 100644 index 0000000000..0de5a291cf --- /dev/null +++ b/packages/plugin-multi-tenant/src/translations/languages/ca.ts @@ -0,0 +1,14 @@ +import type { PluginDefaultTranslationsObject, PluginLanguage } from '../types.js' + +export const caTranslations: PluginDefaultTranslationsObject = { + 'plugin-multi-tenant': { + 'confirm-tenant-switch--body': + 'Estàs a punt de canviar la propietat de <0>{{fromTenant}} a <0>{{toTenant}}', + 'confirm-tenant-switch--heading': 'Confirmeu el canvi de {{tenantLabel}}', + }, +} + +export const ca: PluginLanguage = { + dateFNSKey: 'ca', + translations: caTranslations, +} diff --git a/packages/plugin-multi-tenant/src/translations/languages/cs.ts b/packages/plugin-multi-tenant/src/translations/languages/cs.ts new file mode 100644 index 0000000000..30d024ad51 --- /dev/null +++ b/packages/plugin-multi-tenant/src/translations/languages/cs.ts @@ -0,0 +1,14 @@ +import type { PluginDefaultTranslationsObject, PluginLanguage } from '../types.js' + +export const csTranslations: PluginDefaultTranslationsObject = { + 'plugin-multi-tenant': { + 'confirm-tenant-switch--body': + 'Chystáte se změnit vlastnictví z <0>{{fromTenant}} na <0>{{toTenant}}', + 'confirm-tenant-switch--heading': 'Potvrďte změnu {{tenantLabel}}', + }, +} + +export const cs: PluginLanguage = { + dateFNSKey: 'cs', + translations: csTranslations, +} diff --git a/packages/plugin-multi-tenant/src/translations/languages/da.ts b/packages/plugin-multi-tenant/src/translations/languages/da.ts new file mode 100644 index 0000000000..a7c3898058 --- /dev/null +++ b/packages/plugin-multi-tenant/src/translations/languages/da.ts @@ -0,0 +1,14 @@ +import type { PluginDefaultTranslationsObject, PluginLanguage } from '../types.js' + +export const daTranslations: PluginDefaultTranslationsObject = { + 'plugin-multi-tenant': { + 'confirm-tenant-switch--body': + 'Du er ved at ændre ejerskab fra <0>{{fromTenant}} til <0>{{toTenant}}', + 'confirm-tenant-switch--heading': 'Bekræft {{tenantLabel}} ændring', + }, +} + +export const da: PluginLanguage = { + dateFNSKey: 'da', + translations: daTranslations, +} diff --git a/packages/plugin-multi-tenant/src/translations/languages/de.ts b/packages/plugin-multi-tenant/src/translations/languages/de.ts new file mode 100644 index 0000000000..d36e28346a --- /dev/null +++ b/packages/plugin-multi-tenant/src/translations/languages/de.ts @@ -0,0 +1,14 @@ +import type { PluginDefaultTranslationsObject, PluginLanguage } from '../types.js' + +export const deTranslations: PluginDefaultTranslationsObject = { + 'plugin-multi-tenant': { + 'confirm-tenant-switch--body': + 'Sie sind dabei, den Besitz von <0>{{fromTenant}} auf <0>{{toTenant}} zu übertragen.', + 'confirm-tenant-switch--heading': 'Bestätigen Sie die Änderung von {{tenantLabel}}.', + }, +} + +export const de: PluginLanguage = { + dateFNSKey: 'de', + translations: deTranslations, +} diff --git a/packages/plugin-multi-tenant/src/translations/languages/en.ts b/packages/plugin-multi-tenant/src/translations/languages/en.ts new file mode 100644 index 0000000000..4e790e89d8 --- /dev/null +++ b/packages/plugin-multi-tenant/src/translations/languages/en.ts @@ -0,0 +1,14 @@ +import type { PluginLanguage } from '../types.js' + +export const enTranslations = { + 'plugin-multi-tenant': { + 'confirm-tenant-switch--body': + 'You are about to change ownership from <0>{{fromTenant}} to <0>{{toTenant}}', + 'confirm-tenant-switch--heading': 'Confirm {{tenantLabel}} change', + }, +} + +export const en: PluginLanguage = { + dateFNSKey: 'en-US', + translations: enTranslations, +} diff --git a/packages/plugin-multi-tenant/src/translations/languages/es.ts b/packages/plugin-multi-tenant/src/translations/languages/es.ts new file mode 100644 index 0000000000..4e72ff9d0b --- /dev/null +++ b/packages/plugin-multi-tenant/src/translations/languages/es.ts @@ -0,0 +1,14 @@ +import type { PluginDefaultTranslationsObject, PluginLanguage } from '../types.js' + +export const esTranslations: PluginDefaultTranslationsObject = { + 'plugin-multi-tenant': { + 'confirm-tenant-switch--body': + 'Está a punto de cambiar la propiedad de <0>{{fromTenant}} a <0>{{toTenant}}', + 'confirm-tenant-switch--heading': 'Confirme el cambio de {{tenantLabel}}', + }, +} + +export const es: PluginLanguage = { + dateFNSKey: 'es', + translations: esTranslations, +} diff --git a/packages/plugin-multi-tenant/src/translations/languages/et.ts b/packages/plugin-multi-tenant/src/translations/languages/et.ts new file mode 100644 index 0000000000..1b86bf72a5 --- /dev/null +++ b/packages/plugin-multi-tenant/src/translations/languages/et.ts @@ -0,0 +1,14 @@ +import type { PluginDefaultTranslationsObject, PluginLanguage } from '../types.js' + +export const etTranslations: PluginDefaultTranslationsObject = { + 'plugin-multi-tenant': { + 'confirm-tenant-switch--body': + 'Te olete tegemas omandiõiguse muudatust <0>{{fromTenant}}lt <0>{{toTenant}}le.', + 'confirm-tenant-switch--heading': 'Kinnita {{tenantLabel}} muutus', + }, +} + +export const et: PluginLanguage = { + dateFNSKey: 'et', + translations: etTranslations, +} diff --git a/packages/plugin-multi-tenant/src/translations/languages/fa.ts b/packages/plugin-multi-tenant/src/translations/languages/fa.ts new file mode 100644 index 0000000000..d64610a729 --- /dev/null +++ b/packages/plugin-multi-tenant/src/translations/languages/fa.ts @@ -0,0 +1,14 @@ +import type { PluginDefaultTranslationsObject, PluginLanguage } from '../types.js' + +export const faTranslations: PluginDefaultTranslationsObject = { + 'plugin-multi-tenant': { + 'confirm-tenant-switch--body': + 'شما در حال تغییر مالکیت از <0>{{fromTenant}} به <0>{{toTenant}} هستید', + 'confirm-tenant-switch--heading': 'تایید تغییر {{tenantLabel}}', + }, +} + +export const fa: PluginLanguage = { + dateFNSKey: 'fa-IR', + translations: faTranslations, +} diff --git a/packages/plugin-multi-tenant/src/translations/languages/fr.ts b/packages/plugin-multi-tenant/src/translations/languages/fr.ts new file mode 100644 index 0000000000..720cb3d797 --- /dev/null +++ b/packages/plugin-multi-tenant/src/translations/languages/fr.ts @@ -0,0 +1,14 @@ +import type { PluginDefaultTranslationsObject, PluginLanguage } from '../types.js' + +export const frTranslations: PluginDefaultTranslationsObject = { + 'plugin-multi-tenant': { + 'confirm-tenant-switch--body': + 'Vous êtes sur le point de changer la propriété de <0>{{fromTenant}} à <0>{{toTenant}}', + 'confirm-tenant-switch--heading': 'Confirmer le changement de {{tenantLabel}}', + }, +} + +export const fr: PluginLanguage = { + dateFNSKey: 'fr', + translations: frTranslations, +} diff --git a/packages/plugin-multi-tenant/src/translations/languages/he.ts b/packages/plugin-multi-tenant/src/translations/languages/he.ts new file mode 100644 index 0000000000..1a522ec86f --- /dev/null +++ b/packages/plugin-multi-tenant/src/translations/languages/he.ts @@ -0,0 +1,14 @@ +import type { PluginDefaultTranslationsObject, PluginLanguage } from '../types.js' + +export const heTranslations: PluginDefaultTranslationsObject = { + 'plugin-multi-tenant': { + 'confirm-tenant-switch--body': + 'אתה עומד לשנות בעלות מ- <0>{{fromTenant}} ל- <0>{{toTenant}}', + 'confirm-tenant-switch--heading': 'אשר שינוי {{tenantLabel}}', + }, +} + +export const he: PluginLanguage = { + dateFNSKey: 'he', + translations: heTranslations, +} diff --git a/packages/plugin-multi-tenant/src/translations/languages/hr.ts b/packages/plugin-multi-tenant/src/translations/languages/hr.ts new file mode 100644 index 0000000000..292ec35218 --- /dev/null +++ b/packages/plugin-multi-tenant/src/translations/languages/hr.ts @@ -0,0 +1,14 @@ +import type { PluginDefaultTranslationsObject, PluginLanguage } from '../types.js' + +export const hrTranslations: PluginDefaultTranslationsObject = { + 'plugin-multi-tenant': { + 'confirm-tenant-switch--body': + 'Upravo ćete promijeniti vlasništvo sa <0>{{fromTenant}} na <0>{{toTenant}}', + 'confirm-tenant-switch--heading': 'Potvrdi promjenu {{tenantLabel}}', + }, +} + +export const hr: PluginLanguage = { + dateFNSKey: 'hr', + translations: hrTranslations, +} diff --git a/packages/plugin-multi-tenant/src/translations/languages/hu.ts b/packages/plugin-multi-tenant/src/translations/languages/hu.ts new file mode 100644 index 0000000000..5e7a03bf2e --- /dev/null +++ b/packages/plugin-multi-tenant/src/translations/languages/hu.ts @@ -0,0 +1,14 @@ +import type { PluginDefaultTranslationsObject, PluginLanguage } from '../types.js' + +export const huTranslations: PluginDefaultTranslationsObject = { + 'plugin-multi-tenant': { + 'confirm-tenant-switch--body': + 'Ön azon van, hogy megváltoztassa a tulajdonjogot <0>{{fromTenant}}-ről <0>{{toTenant}}-re.', + 'confirm-tenant-switch--heading': 'Erősítse meg a(z) {{tenantLabel}} változtatást', + }, +} + +export const hu: PluginLanguage = { + dateFNSKey: 'hu', + translations: huTranslations, +} diff --git a/packages/plugin-multi-tenant/src/translations/languages/hy.ts b/packages/plugin-multi-tenant/src/translations/languages/hy.ts new file mode 100644 index 0000000000..e46f11ac5f --- /dev/null +++ b/packages/plugin-multi-tenant/src/translations/languages/hy.ts @@ -0,0 +1,14 @@ +import type { PluginDefaultTranslationsObject, PluginLanguage } from '../types.js' + +export const hyTranslations: PluginDefaultTranslationsObject = { + 'plugin-multi-tenant': { + 'confirm-tenant-switch--body': + 'Դուք պատրաստ եք փոխել գերեցդիմատնին ընկերությունը <0>{{fromTenant}}-ից <0>{{toTenant}}-ին', + 'confirm-tenant-switch--heading': 'Հաստատեք {{tenantLabel}} փոփոխությունը', + }, +} + +export const hy: PluginLanguage = { + dateFNSKey: 'hy-AM', + translations: hyTranslations, +} diff --git a/packages/plugin-multi-tenant/src/translations/languages/it.ts b/packages/plugin-multi-tenant/src/translations/languages/it.ts new file mode 100644 index 0000000000..af0ce98a75 --- /dev/null +++ b/packages/plugin-multi-tenant/src/translations/languages/it.ts @@ -0,0 +1,14 @@ +import type { PluginDefaultTranslationsObject, PluginLanguage } from '../types.js' + +export const itTranslations: PluginDefaultTranslationsObject = { + 'plugin-multi-tenant': { + 'confirm-tenant-switch--body': + 'Stai per cambiare proprietà da <0>{{fromTenant}} a <0>{{toTenant}}', + 'confirm-tenant-switch--heading': 'Conferma il cambiamento di {{tenantLabel}}', + }, +} + +export const it: PluginLanguage = { + dateFNSKey: 'it', + translations: itTranslations, +} diff --git a/packages/plugin-multi-tenant/src/translations/languages/ja.ts b/packages/plugin-multi-tenant/src/translations/languages/ja.ts new file mode 100644 index 0000000000..23adbe4131 --- /dev/null +++ b/packages/plugin-multi-tenant/src/translations/languages/ja.ts @@ -0,0 +1,14 @@ +import type { PluginDefaultTranslationsObject, PluginLanguage } from '../types.js' + +export const jaTranslations: PluginDefaultTranslationsObject = { + 'plugin-multi-tenant': { + 'confirm-tenant-switch--body': + 'あなたは所有権を<0>{{fromTenant}}から<0>{{toTenant}}へ変更しようとしています', + 'confirm-tenant-switch--heading': '{{tenantLabel}}の変更を確認してください', + }, +} + +export const ja: PluginLanguage = { + dateFNSKey: 'ja', + translations: jaTranslations, +} diff --git a/packages/plugin-multi-tenant/src/translations/languages/ko.ts b/packages/plugin-multi-tenant/src/translations/languages/ko.ts new file mode 100644 index 0000000000..7836ab8f9e --- /dev/null +++ b/packages/plugin-multi-tenant/src/translations/languages/ko.ts @@ -0,0 +1,14 @@ +import type { PluginDefaultTranslationsObject, PluginLanguage } from '../types.js' + +export const koTranslations: PluginDefaultTranslationsObject = { + 'plugin-multi-tenant': { + 'confirm-tenant-switch--body': + '<0>{{fromTenant}}에서 <0>{{toTenant}}으로 소유권을 변경하려고 합니다.', + 'confirm-tenant-switch--heading': '{{tenantLabel}} 변경을 확인하세요', + }, +} + +export const ko: PluginLanguage = { + dateFNSKey: 'ko', + translations: koTranslations, +} diff --git a/packages/plugin-multi-tenant/src/translations/languages/lt.ts b/packages/plugin-multi-tenant/src/translations/languages/lt.ts new file mode 100644 index 0000000000..396855ada9 --- /dev/null +++ b/packages/plugin-multi-tenant/src/translations/languages/lt.ts @@ -0,0 +1,14 @@ +import type { PluginDefaultTranslationsObject, PluginLanguage } from '../types.js' + +export const ltTranslations: PluginDefaultTranslationsObject = { + 'plugin-multi-tenant': { + 'confirm-tenant-switch--body': + 'Jūs ketinate pakeisti nuosavybės teisę iš <0>{{fromTenant}} į <0>{{toTenant}}', + 'confirm-tenant-switch--heading': 'Patvirtinkite {{tenantLabel}} pakeitimą', + }, +} + +export const lt: PluginLanguage = { + dateFNSKey: 'lt', + translations: ltTranslations, +} diff --git a/packages/plugin-multi-tenant/src/translations/languages/my.ts b/packages/plugin-multi-tenant/src/translations/languages/my.ts new file mode 100644 index 0000000000..ae1a6349b6 --- /dev/null +++ b/packages/plugin-multi-tenant/src/translations/languages/my.ts @@ -0,0 +1,14 @@ +import type { PluginDefaultTranslationsObject, PluginLanguage } from '../types.js' + +export const myTranslations: PluginDefaultTranslationsObject = { + 'plugin-multi-tenant': { + 'confirm-tenant-switch--body': + 'Anda akan mengubah pemilikan dari <0>{{fromTenant}} ke <0>{{toTenant}}', + 'confirm-tenant-switch--heading': 'Sahkan perubahan {{tenantLabel}}', + }, +} + +export const my: PluginLanguage = { + dateFNSKey: 'en-US', + translations: myTranslations, +} diff --git a/packages/plugin-multi-tenant/src/translations/languages/nb.ts b/packages/plugin-multi-tenant/src/translations/languages/nb.ts new file mode 100644 index 0000000000..c7f85e270d --- /dev/null +++ b/packages/plugin-multi-tenant/src/translations/languages/nb.ts @@ -0,0 +1,14 @@ +import type { PluginDefaultTranslationsObject, PluginLanguage } from '../types.js' + +export const nbTranslations: PluginDefaultTranslationsObject = { + 'plugin-multi-tenant': { + 'confirm-tenant-switch--body': + 'Du er i ferd med å endre eierskap fra <0>{{fromTenant}} til <0>{{toTenant}}', + 'confirm-tenant-switch--heading': 'Bekreft {{tenantLabel}} endring', + }, +} + +export const nb: PluginLanguage = { + dateFNSKey: 'nb', + translations: nbTranslations, +} diff --git a/packages/plugin-multi-tenant/src/translations/languages/nl.ts b/packages/plugin-multi-tenant/src/translations/languages/nl.ts new file mode 100644 index 0000000000..21ee10b6d0 --- /dev/null +++ b/packages/plugin-multi-tenant/src/translations/languages/nl.ts @@ -0,0 +1,14 @@ +import type { PluginDefaultTranslationsObject, PluginLanguage } from '../types.js' + +export const nlTranslations: PluginDefaultTranslationsObject = { + 'plugin-multi-tenant': { + 'confirm-tenant-switch--body': + 'U staat op het punt het eigendom te wijzigen van <0>{{fromTenant}} naar <0>{{toTenant}}', + 'confirm-tenant-switch--heading': 'Bevestig wijziging van {{tenantLabel}}', + }, +} + +export const nl: PluginLanguage = { + dateFNSKey: 'nl', + translations: nlTranslations, +} diff --git a/packages/plugin-multi-tenant/src/translations/languages/pl.ts b/packages/plugin-multi-tenant/src/translations/languages/pl.ts new file mode 100644 index 0000000000..4f1a732246 --- /dev/null +++ b/packages/plugin-multi-tenant/src/translations/languages/pl.ts @@ -0,0 +1,14 @@ +import type { PluginDefaultTranslationsObject, PluginLanguage } from '../types.js' + +export const plTranslations: PluginDefaultTranslationsObject = { + 'plugin-multi-tenant': { + 'confirm-tenant-switch--body': + 'Za chwilę nastąpi zmiana właściciela z <0>{{fromTenant}} na <0>{{toTenant}}', + 'confirm-tenant-switch--heading': 'Potwierdź zmianę {{tenantLabel}}', + }, +} + +export const pl: PluginLanguage = { + dateFNSKey: 'pl', + translations: plTranslations, +} diff --git a/packages/plugin-multi-tenant/src/translations/languages/pt.ts b/packages/plugin-multi-tenant/src/translations/languages/pt.ts new file mode 100644 index 0000000000..1e52af5ec7 --- /dev/null +++ b/packages/plugin-multi-tenant/src/translations/languages/pt.ts @@ -0,0 +1,14 @@ +import type { PluginDefaultTranslationsObject, PluginLanguage } from '../types.js' + +export const ptTranslations: PluginDefaultTranslationsObject = { + 'plugin-multi-tenant': { + 'confirm-tenant-switch--body': + 'Você está prestes a alterar a propriedade de <0>{{fromTenant}} para <0>{{toTenant}}', + 'confirm-tenant-switch--heading': 'Confirme a alteração de {{tenantLabel}}', + }, +} + +export const pt: PluginLanguage = { + dateFNSKey: 'pt', + translations: ptTranslations, +} diff --git a/packages/plugin-multi-tenant/src/translations/languages/rn.sh b/packages/plugin-multi-tenant/src/translations/languages/rn.sh new file mode 100644 index 0000000000..ef6b3ed6c4 --- /dev/null +++ b/packages/plugin-multi-tenant/src/translations/languages/rn.sh @@ -0,0 +1,3 @@ +for file in *.js; do + mv -- "$file" "${file%.js}.ts" +done diff --git a/packages/plugin-multi-tenant/src/translations/languages/ro.ts b/packages/plugin-multi-tenant/src/translations/languages/ro.ts new file mode 100644 index 0000000000..b6a40cd36f --- /dev/null +++ b/packages/plugin-multi-tenant/src/translations/languages/ro.ts @@ -0,0 +1,14 @@ +import type { PluginDefaultTranslationsObject, PluginLanguage } from '../types.js' + +export const roTranslations: PluginDefaultTranslationsObject = { + 'plugin-multi-tenant': { + 'confirm-tenant-switch--body': + 'Sunteți pe punctul de a schimba proprietatea de la <0>{{fromTenant}} la <0>{{toTenant}}', + 'confirm-tenant-switch--heading': 'Confirmați schimbarea {{tenantLabel}}', + }, +} + +export const ro: PluginLanguage = { + dateFNSKey: 'ro', + translations: roTranslations, +} diff --git a/packages/plugin-multi-tenant/src/translations/languages/rs.ts b/packages/plugin-multi-tenant/src/translations/languages/rs.ts new file mode 100644 index 0000000000..19c63dc59e --- /dev/null +++ b/packages/plugin-multi-tenant/src/translations/languages/rs.ts @@ -0,0 +1,14 @@ +import type { PluginDefaultTranslationsObject, PluginLanguage } from '../types.js' + +export const rsTranslations: PluginDefaultTranslationsObject = { + 'plugin-multi-tenant': { + 'confirm-tenant-switch--body': + 'Upravo ćete promeniti vlasništvo sa <0>{{fromTenant}} na <0>{{toTenant}}', + 'confirm-tenant-switch--heading': 'Potvrdi promena {{tenantLabel}}', + }, +} + +export const rs: PluginLanguage = { + dateFNSKey: 'rs', + translations: rsTranslations, +} diff --git a/packages/plugin-multi-tenant/src/translations/languages/rsLatin.ts b/packages/plugin-multi-tenant/src/translations/languages/rsLatin.ts new file mode 100644 index 0000000000..c4f56096f0 --- /dev/null +++ b/packages/plugin-multi-tenant/src/translations/languages/rsLatin.ts @@ -0,0 +1,14 @@ +import type { PluginDefaultTranslationsObject, PluginLanguage } from '../types.js' + +export const rsLatinTranslations: PluginDefaultTranslationsObject = { + 'plugin-multi-tenant': { + 'confirm-tenant-switch--body': + 'Uskoro ćete promeniti vlasništvo sa <0>{{fromTenant}} na <0>{{toTenant}}', + 'confirm-tenant-switch--heading': 'Potvrdite promenu {{tenantLabel}}', + }, +} + +export const rsLatin: PluginLanguage = { + dateFNSKey: 'rs-Latin', + translations: rsLatinTranslations, +} diff --git a/packages/plugin-multi-tenant/src/translations/languages/ru.ts b/packages/plugin-multi-tenant/src/translations/languages/ru.ts new file mode 100644 index 0000000000..66bfaa76cb --- /dev/null +++ b/packages/plugin-multi-tenant/src/translations/languages/ru.ts @@ -0,0 +1,14 @@ +import type { PluginDefaultTranslationsObject, PluginLanguage } from '../types.js' + +export const ruTranslations: PluginDefaultTranslationsObject = { + 'plugin-multi-tenant': { + 'confirm-tenant-switch--body': + 'Вы собираетесь изменить владельца с <0>{{fromTenant}} на <0>{{toTenant}}', + 'confirm-tenant-switch--heading': 'Подтвердите изменение {{tenantLabel}}', + }, +} + +export const ru: PluginLanguage = { + dateFNSKey: 'ru', + translations: ruTranslations, +} diff --git a/packages/plugin-multi-tenant/src/translations/languages/sk.ts b/packages/plugin-multi-tenant/src/translations/languages/sk.ts new file mode 100644 index 0000000000..22148c870f --- /dev/null +++ b/packages/plugin-multi-tenant/src/translations/languages/sk.ts @@ -0,0 +1,14 @@ +import type { PluginDefaultTranslationsObject, PluginLanguage } from '../types.js' + +export const skTranslations: PluginDefaultTranslationsObject = { + 'plugin-multi-tenant': { + 'confirm-tenant-switch--body': + 'Chystáte sa zmeniť vlastníctvo z <0>{{fromTenant}} na <0>{{toTenant}}', + 'confirm-tenant-switch--heading': 'Potvrďte zmenu {{tenantLabel}}', + }, +} + +export const sk: PluginLanguage = { + dateFNSKey: 'sk', + translations: skTranslations, +} diff --git a/packages/plugin-multi-tenant/src/translations/languages/sl.ts b/packages/plugin-multi-tenant/src/translations/languages/sl.ts new file mode 100644 index 0000000000..c2f6bb2bf6 --- /dev/null +++ b/packages/plugin-multi-tenant/src/translations/languages/sl.ts @@ -0,0 +1,14 @@ +import type { PluginDefaultTranslationsObject, PluginLanguage } from '../types.js' + +export const slTranslations: PluginDefaultTranslationsObject = { + 'plugin-multi-tenant': { + 'confirm-tenant-switch--body': + 'Ravno ste pred spremembo lastništva iz <0>{{fromTenant}} na <0>{{toTenant}}', + 'confirm-tenant-switch--heading': 'Potrdi spremembo {{tenantLabel}}', + }, +} + +export const sl: PluginLanguage = { + dateFNSKey: 'sl-SI', + translations: slTranslations, +} diff --git a/packages/plugin-multi-tenant/src/translations/languages/sv.ts b/packages/plugin-multi-tenant/src/translations/languages/sv.ts new file mode 100644 index 0000000000..fcf4972ff5 --- /dev/null +++ b/packages/plugin-multi-tenant/src/translations/languages/sv.ts @@ -0,0 +1,14 @@ +import type { PluginDefaultTranslationsObject, PluginLanguage } from '../types.js' + +export const svTranslations: PluginDefaultTranslationsObject = { + 'plugin-multi-tenant': { + 'confirm-tenant-switch--body': + 'Du är på väg att ändra ägare från <0>{{fromTenant}} till <0>{{toTenant}}', + 'confirm-tenant-switch--heading': 'Bekräfta ändring av {{tenantLabel}}', + }, +} + +export const sv: PluginLanguage = { + dateFNSKey: 'sv', + translations: svTranslations, +} diff --git a/packages/plugin-multi-tenant/src/translations/languages/th.ts b/packages/plugin-multi-tenant/src/translations/languages/th.ts new file mode 100644 index 0000000000..cdfdc45c9a --- /dev/null +++ b/packages/plugin-multi-tenant/src/translations/languages/th.ts @@ -0,0 +1,14 @@ +import type { PluginDefaultTranslationsObject, PluginLanguage } from '../types.js' + +export const thTranslations: PluginDefaultTranslationsObject = { + 'plugin-multi-tenant': { + 'confirm-tenant-switch--body': + 'คุณกำลังจะเปลี่ยนความเป็นเจ้าของจาก <0>{{fromTenant}} เป็น <0>{{toTenant}}', + 'confirm-tenant-switch--heading': 'ยืนยันการเปลี่ยนแปลง {{tenantLabel}}', + }, +} + +export const th: PluginLanguage = { + dateFNSKey: 'th', + translations: thTranslations, +} diff --git a/packages/plugin-multi-tenant/src/translations/languages/tr.ts b/packages/plugin-multi-tenant/src/translations/languages/tr.ts new file mode 100644 index 0000000000..2f969402e2 --- /dev/null +++ b/packages/plugin-multi-tenant/src/translations/languages/tr.ts @@ -0,0 +1,14 @@ +import type { PluginDefaultTranslationsObject, PluginLanguage } from '../types.js' + +export const trTranslations: PluginDefaultTranslationsObject = { + 'plugin-multi-tenant': { + 'confirm-tenant-switch--body': + "Sahipliği <0>{{fromTenant}}'den <0>{{toTenant}}'e değiştirmek üzeresiniz.", + 'confirm-tenant-switch--heading': '{{tenantLabel}} değişikliğini onayla', + }, +} + +export const tr: PluginLanguage = { + dateFNSKey: 'tr', + translations: trTranslations, +} diff --git a/packages/plugin-multi-tenant/src/translations/languages/uk.ts b/packages/plugin-multi-tenant/src/translations/languages/uk.ts new file mode 100644 index 0000000000..8e0fa89233 --- /dev/null +++ b/packages/plugin-multi-tenant/src/translations/languages/uk.ts @@ -0,0 +1,14 @@ +import type { PluginDefaultTranslationsObject, PluginLanguage } from '../types.js' + +export const ukTranslations: PluginDefaultTranslationsObject = { + 'plugin-multi-tenant': { + 'confirm-tenant-switch--body': + 'Ви збираєтесь змінити власність з <0>{{fromTenant}} на <0>{{toTenant}}', + 'confirm-tenant-switch--heading': 'Підтвердіть зміну {{tenantLabel}}', + }, +} + +export const uk: PluginLanguage = { + dateFNSKey: 'uk', + translations: ukTranslations, +} diff --git a/packages/plugin-multi-tenant/src/translations/languages/vi.ts b/packages/plugin-multi-tenant/src/translations/languages/vi.ts new file mode 100644 index 0000000000..e017d9a05e --- /dev/null +++ b/packages/plugin-multi-tenant/src/translations/languages/vi.ts @@ -0,0 +1,14 @@ +import type { PluginDefaultTranslationsObject, PluginLanguage } from '../types.js' + +export const viTranslations: PluginDefaultTranslationsObject = { + 'plugin-multi-tenant': { + 'confirm-tenant-switch--body': + 'Bạn đang chuẩn bị chuyển quyền sở hữu từ <0>{{fromTenant}} sang <0>{{toTenant}}', + 'confirm-tenant-switch--heading': 'Xác nhận thay đổi {{tenantLabel}}', + }, +} + +export const vi: PluginLanguage = { + dateFNSKey: 'vi', + translations: viTranslations, +} diff --git a/packages/plugin-multi-tenant/src/translations/languages/zh.ts b/packages/plugin-multi-tenant/src/translations/languages/zh.ts new file mode 100644 index 0000000000..047847258c --- /dev/null +++ b/packages/plugin-multi-tenant/src/translations/languages/zh.ts @@ -0,0 +1,13 @@ +import type { PluginDefaultTranslationsObject, PluginLanguage } from '../types.js' + +export const zhTranslations: PluginDefaultTranslationsObject = { + 'plugin-multi-tenant': { + 'confirm-tenant-switch--body': '您即将将所有权从<0>{{fromTenant}}更改为<0>{{toTenant}}', + 'confirm-tenant-switch--heading': '确认更改{{tenantLabel}}', + }, +} + +export const zh: PluginLanguage = { + dateFNSKey: 'zh-CN', + translations: zhTranslations, +} diff --git a/packages/plugin-multi-tenant/src/translations/languages/zhTw.ts b/packages/plugin-multi-tenant/src/translations/languages/zhTw.ts new file mode 100644 index 0000000000..4950b18cb4 --- /dev/null +++ b/packages/plugin-multi-tenant/src/translations/languages/zhTw.ts @@ -0,0 +1,14 @@ +import type { PluginDefaultTranslationsObject, PluginLanguage } from '../types.js' + +export const zhTwTranslations: PluginDefaultTranslationsObject = { + 'plugin-multi-tenant': { + 'confirm-tenant-switch--body': + '您即將將所有權從 <0>{{fromTenant}} 轉移至 <0>{{toTenant}}', + 'confirm-tenant-switch--heading': '確認{{tenantLabel}}更改', + }, +} + +export const zhTw: PluginLanguage = { + dateFNSKey: 'zh-TW', + translations: zhTwTranslations, +} diff --git a/packages/plugin-multi-tenant/src/translations/types.ts b/packages/plugin-multi-tenant/src/translations/types.ts new file mode 100644 index 0000000000..d1750a2c80 --- /dev/null +++ b/packages/plugin-multi-tenant/src/translations/types.ts @@ -0,0 +1,12 @@ +import type { Language } from '@payloadcms/translations' + +import type { enTranslations } from './languages/en.js' + +export type PluginLanguage = Language<{ + 'plugin-multi-tenant': { + 'confirm-tenant-switch--body': string + 'confirm-tenant-switch--heading': string + } +}> + +export type PluginDefaultTranslationsObject = typeof enTranslations diff --git a/packages/richtext-lexical/package.json b/packages/richtext-lexical/package.json index 1766ada144..acd088e2d9 100644 --- a/packages/richtext-lexical/package.json +++ b/packages/richtext-lexical/package.json @@ -344,8 +344,7 @@ "copyfiles": "copyfiles -u 1 \"src/**/*.{html,css,ttf,woff,woff2,eot,svg,jpg,png,json}\" dist/", "lint": "eslint .", "lint:fix": "eslint . --fix", - "prepublishOnly": "pnpm clean && pnpm turbo build", - "translateNewKeys": "node --no-deprecation --import @swc-node/register/esm-register scripts/translateNewKeys.ts" + "prepublishOnly": "pnpm clean && pnpm turbo build" }, "lint-staged": { "**/package.json": "sort-package-json", diff --git a/packages/translations/.env.example b/packages/translations/.env.example deleted file mode 100644 index 22d74139b5..0000000000 --- a/packages/translations/.env.example +++ /dev/null @@ -1 +0,0 @@ -OPENAI_KEY=sk- diff --git a/packages/translations/package.json b/packages/translations/package.json index ae1b93bcad..384e79efb4 100644 --- a/packages/translations/package.json +++ b/packages/translations/package.json @@ -51,8 +51,7 @@ "clean": "rimraf -g {dist,*.tsbuildinfo}", "lint": "eslint .", "lint:fix": "eslint . --fix", - "prepublishOnly": "pnpm clean && pnpm turbo build", - "translateNewKeys": "node --no-deprecation --import @swc-node/register/esm-register scripts/translateNewKeys/run.ts" + "prepublishOnly": "pnpm clean && pnpm turbo build" }, "dependencies": { "date-fns": "4.1.0" diff --git a/packages/translations/scripts/translateNewKeys/run.ts b/packages/translations/scripts/translateNewKeys/run.ts deleted file mode 100644 index e903614f3d..0000000000 --- a/packages/translations/scripts/translateNewKeys/run.ts +++ /dev/null @@ -1,32 +0,0 @@ -import path from 'path' -import { fileURLToPath } from 'url' - -import type { AcceptedLanguages, GenericTranslationsObject } from '../../src/types.js' - -import { translations } from '../../src/exports/all.js' -import { enTranslations } from '../../src/languages/en.js' -import { translateObject } from './index.js' - -const filename = fileURLToPath(import.meta.url) -const dirname = path.dirname(filename) - -const allTranslations: { - [key in AcceptedLanguages]?: { - dateFNSKey: string - translations: GenericTranslationsObject - } -} = {} - -for (const key of Object.keys(translations)) { - allTranslations[key] = { - dateFNSKey: translations[key].dateFNSKey, - translations: translations[key].translations, - } -} - -void translateObject({ - allTranslationsObject: allTranslations, - fromTranslationsObject: enTranslations, - //languages: ['de'], - targetFolder: path.resolve(dirname, '../../src/languages'), -}) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 0cb2a8f4b4..1c111b1db6 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1958,6 +1958,19 @@ importers: open: specifier: ^10.1.0 version: 10.1.0 + payload: + specifier: workspace:* + version: link:../../packages/payload + devDependencies: + '@payloadcms/plugin-multi-tenant': + specifier: workspace:* + version: link:../../packages/plugin-multi-tenant + '@payloadcms/richtext-lexical': + specifier: workspace:* + version: link:../../packages/richtext-lexical + '@payloadcms/translations': + specifier: workspace:* + version: link:../../packages/translations packages: diff --git a/test/plugin-multi-tenant/config.ts b/test/plugin-multi-tenant/config.ts index 999de7acbf..1a4bb8b309 100644 --- a/test/plugin-multi-tenant/config.ts +++ b/test/plugin-multi-tenant/config.ts @@ -41,7 +41,7 @@ export default buildConfigWithDefaults({ isGlobal: true, }, }, - tenantSelectorLabel: 'Sites', + tenantSelectorLabel: 'Site', }), ], typescript: { diff --git a/tools/.env.example b/tools/.env.example new file mode 100644 index 0000000000..ea5cc2a08b --- /dev/null +++ b/tools/.env.example @@ -0,0 +1 @@ +OPENAI_KEY=sk-your-key-here \ No newline at end of file diff --git a/tools/scripts/package.json b/tools/scripts/package.json index 0b944c34a5..2f949551b5 100644 --- a/tools/scripts/package.json +++ b/tools/scripts/package.json @@ -13,9 +13,11 @@ }, "main": "src/index.ts", "scripts": { - "build": "tsc", + "build": "tsc --project tsconfig.build.json", "build-template-with-local-pkgs": "pnpm runts src/build-template-with-local-pkgs.ts", "gen-templates": "pnpm runts src/generate-template-variations.ts", + "generateTranslations:core": "node --no-deprecation --import @swc-node/register/esm-register src/generateTranslations/core.ts", + "generateTranslations:plugin-multi-tenant": "node --no-deprecation --import @swc-node/register/esm-register src/generateTranslations/plugin-multi-tenant.ts", "license-check": "pnpm runts src/license-check.ts", "lint": "eslint .", "lint:fix": "eslint . --fix", @@ -32,6 +34,12 @@ "create-payload-app": "workspace:*", "csv-stringify": "^6.5.2", "license-checker": "25.0.1", - "open": "^10.1.0" + "open": "^10.1.0", + "payload": "workspace:*" + }, + "devDependencies": { + "@payloadcms/plugin-multi-tenant": "workspace:*", + "@payloadcms/richtext-lexical": "workspace:*", + "@payloadcms/translations": "workspace:*" } } diff --git a/tools/scripts/src/generateTranslations/core.ts b/tools/scripts/src/generateTranslations/core.ts new file mode 100644 index 0000000000..b4c31cc108 --- /dev/null +++ b/tools/scripts/src/generateTranslations/core.ts @@ -0,0 +1,31 @@ +import type { AcceptedLanguages, GenericTranslationsObject } from '@payloadcms/translations' + +import { translations } from '@payloadcms/translations/all' +import { enTranslations } from '@payloadcms/translations/languages/en' +import path from 'path' +import { fileURLToPath } from 'url' + +import { translateObject } from './utils/index.js' + +const filename = fileURLToPath(import.meta.url) +const dirname = path.dirname(filename) + +const allTranslations: { + [key in AcceptedLanguages]?: { + dateFNSKey: string + translations: GenericTranslationsObject + } +} = {} + +for (const key of Object.keys(translations) as AcceptedLanguages[]) { + allTranslations[key] = { + dateFNSKey: translations[key]?.dateFNSKey || 'unknown-date-fns-key', + translations: translations[key]?.translations || {}, + } +} + +void translateObject({ + allTranslationsObject: allTranslations, + fromTranslationsObject: enTranslations, + targetFolder: path.resolve(dirname, '../../../../packages/translations/src/languages'), +}) diff --git a/tools/scripts/src/generateTranslations/plugin-multi-tenant.ts b/tools/scripts/src/generateTranslations/plugin-multi-tenant.ts new file mode 100644 index 0000000000..91b94c58b7 --- /dev/null +++ b/tools/scripts/src/generateTranslations/plugin-multi-tenant.ts @@ -0,0 +1,39 @@ +import type { AcceptedLanguages, GenericTranslationsObject } from '@payloadcms/translations' + +import { translations } from '@payloadcms/plugin-multi-tenant/translations/languages/all' +import { enTranslations } from '@payloadcms/plugin-multi-tenant/translations/languages/en' +import path from 'path' +import { fileURLToPath } from 'url' + +import { translateObject } from './utils/index.js' + +const filename = fileURLToPath(import.meta.url) +const dirname = path.dirname(filename) + +const allTranslations: { + [key in AcceptedLanguages]?: { + dateFNSKey: string + translations: GenericTranslationsObject + } +} = {} + +for (const key of Object.keys(translations)) { + allTranslations[key as AcceptedLanguages] = { + dateFNSKey: translations[key as AcceptedLanguages]?.dateFNSKey ?? 'unknown-date-fns-key', + translations: translations[key as AcceptedLanguages]?.translations ?? {}, + } +} + +void translateObject({ + allTranslationsObject: allTranslations, + fromTranslationsObject: enTranslations, + targetFolder: path.resolve( + dirname, + '../../../../packages/plugin-multi-tenant/src/translations/languages', + ), + tsFilePrefix: `import type { PluginDefaultTranslationsObject, PluginLanguage } from '../types.js'\n\nexport const {{locale}}Translations: PluginDefaultTranslationsObject = `, + tsFileSuffix: `\n\nexport const {{locale}}: PluginLanguage = { + dateFNSKey: {{dateFNSKey}}, + translations: {{locale}}Translations, + } `, +}) diff --git a/packages/richtext-lexical/scripts/translateNewKeys.ts b/tools/scripts/src/generateTranslations/richtext-lexical.ts similarity index 56% rename from packages/richtext-lexical/scripts/translateNewKeys.ts rename to tools/scripts/src/generateTranslations/richtext-lexical.ts index 31c27f7803..457ff649a1 100644 --- a/packages/richtext-lexical/scripts/translateNewKeys.ts +++ b/tools/scripts/src/generateTranslations/richtext-lexical.ts @@ -8,13 +8,13 @@ import * as fs from 'node:fs' import path from 'path' import { fileURLToPath } from 'url' -import { translateObject } from '../../translations/scripts/translateNewKeys/index.js' +import { translateObject } from './utils/index.js' const filename = fileURLToPath(import.meta.url) const dirname = path.dirname(filename) // Function to get all files with a specific name recursively in all subdirectories -function findFilesRecursively(startPath, filter) { - let results = [] +function findFilesRecursively(startPath: string, filter: string): string[] { + let results: string[] = [] const entries = fs.readdirSync(startPath, { withFileTypes: true }) @@ -33,7 +33,10 @@ function findFilesRecursively(startPath, filter) { return results } -const i18nFilePaths = findFilesRecursively(path.resolve(dirname, '../src'), 'i18n.ts') +const i18nFilePaths = findFilesRecursively( + path.resolve(dirname, '../../../../packages/richtext-lexical/src'), + 'i18n.ts', +) async function translate() { for (const i18nFilePath of i18nFilePaths) { @@ -46,22 +49,26 @@ async function translate() { } } = {} for (const lang in translationsObject) { - allTranslations[lang] = { + allTranslations[lang as AcceptedLanguages] = { dateFNSKey: 'en', - translations: translationsObject[lang], + translations: translationsObject?.[lang as keyof GenericLanguages] || {}, } } - console.log('Translating', i18nFilePath) - await translateObject({ - allTranslationsObject: allTranslations, - fromTranslationsObject: translationsObject.en, - inlineFile: i18nFilePath, - tsFilePrefix: `import { GenericLanguages } from '@payloadcms/translations' - -export const i18n: Partial = `, - tsFileSuffix: ``, - }) + if (translationsObject.en) { + console.log('Translating', i18nFilePath) + await translateObject({ + allTranslationsObject: allTranslations, + fromTranslationsObject: translationsObject.en, + inlineFile: i18nFilePath, + tsFilePrefix: `import { GenericLanguages } from '@payloadcms/translations' + + export const i18n: Partial = `, + tsFileSuffix: ``, + }) + } else { + console.error(`No English translations found in ${i18nFilePath}`) + } } } diff --git a/packages/translations/scripts/translateNewKeys/applyEslintFixes.ts b/tools/scripts/src/generateTranslations/utils/applyEslintFixes.ts similarity index 100% rename from packages/translations/scripts/translateNewKeys/applyEslintFixes.ts rename to tools/scripts/src/generateTranslations/utils/applyEslintFixes.ts diff --git a/packages/translations/scripts/translateNewKeys/findMissingKeys.ts b/tools/scripts/src/generateTranslations/utils/findMissingKeys.ts similarity index 86% rename from packages/translations/scripts/translateNewKeys/findMissingKeys.ts rename to tools/scripts/src/generateTranslations/utils/findMissingKeys.ts index b37bcab103..4e40650695 100644 --- a/packages/translations/scripts/translateNewKeys/findMissingKeys.ts +++ b/tools/scripts/src/generateTranslations/utils/findMissingKeys.ts @@ -1,4 +1,4 @@ -import type { GenericTranslationsObject } from '../../src/types.js' +import type { GenericTranslationsObject } from '@payloadcms/translations' /** * Returns keys which are present in baseObj but not in targetObj @@ -8,7 +8,7 @@ export function findMissingKeys( targetObj: GenericTranslationsObject, prefix = '', ): string[] { - let missingKeys = [] + let missingKeys: string[] = [] for (const key in baseObj) { const baseValue = baseObj[key] diff --git a/packages/translations/scripts/translateNewKeys/generateTsObjectLiteral.ts b/tools/scripts/src/generateTranslations/utils/generateTsObjectLiteral.ts similarity index 73% rename from packages/translations/scripts/translateNewKeys/generateTsObjectLiteral.ts rename to tools/scripts/src/generateTranslations/utils/generateTsObjectLiteral.ts index 52fe51a714..4bf3b494db 100644 --- a/packages/translations/scripts/translateNewKeys/generateTsObjectLiteral.ts +++ b/tools/scripts/src/generateTranslations/utils/generateTsObjectLiteral.ts @@ -1,5 +1,7 @@ -export function generateTsObjectLiteral(obj: any): string { - const lines = [] +import type { JsonObject } from 'payload' + +export function generateTsObjectLiteral(obj: JsonObject): string { + const lines: string[] = [] const entries = Object.entries(obj) for (const [key, value] of entries) { const safeKey = /^[\w$]+$/.test(key) ? key : JSON.stringify(key) diff --git a/packages/translations/scripts/translateNewKeys/index.ts b/tools/scripts/src/generateTranslations/utils/index.ts similarity index 84% rename from packages/translations/scripts/translateNewKeys/index.ts rename to tools/scripts/src/generateTranslations/utils/index.ts index 1cdc2ae4f2..b3cb8e8177 100644 --- a/packages/translations/scripts/translateNewKeys/index.ts +++ b/tools/scripts/src/generateTranslations/utils/index.ts @@ -1,17 +1,17 @@ /* eslint no-console: 0 */ -import fs from 'fs' -import path from 'path' -import { format } from 'prettier' - import type { AcceptedLanguages, GenericLanguages, GenericTranslationsObject, -} from '../../src/types.js' +} from '@payloadcms/translations' + +import { acceptedLanguages } from '@payloadcms/translations' +import fs from 'fs' +import path from 'path' +import { deepMergeSimple } from 'payload/shared' +import { format } from 'prettier' -import { deepMergeSimple } from '../../src/utilities/deepMergeSimple.js' -import { acceptedLanguages } from '../../src/utilities/languages.js' import { applyEslintFixes } from './applyEslintFixes.js' import { findMissingKeys } from './findMissingKeys.js' import { generateTsObjectLiteral } from './generateTsObjectLiteral.js' @@ -104,16 +104,16 @@ export async function translateObject(props: { */ for (const key of keysWhichDoNotExistInFromlang) { // Delete those keys in the target language object obj[lang] - const keys = key.split('.') + const keys: string[] = key.split('.') let targetObj = allTranslatedTranslationsObject?.[targetLang].translations for (let i = 0; i < keys.length - 1; i += 1) { - const nextObj = targetObj[keys[i]] + const nextObj = targetObj[keys[i] as string] if (typeof nextObj !== 'object') { throw new Error(`Key ${keys[i]} is not an object in ${targetLang} (1)`) } targetObj = nextObj } - delete targetObj[keys[keys.length - 1]] + delete targetObj[keys[keys.length - 1] as string] } if (!allTranslatedTranslationsObject?.[targetLang].translations) { @@ -128,7 +128,10 @@ export async function translateObject(props: { for (const missingKey of missingKeys) { const keys: string[] = missingKey.split('.') - const sourceText = keys.reduce((acc, key) => acc[key], fromTranslationsObject) + const sourceText = keys.reduce( + (acc, key) => acc[key] as GenericTranslationsObject, + fromTranslationsObject, + ) if (!sourceText || typeof sourceText !== 'string') { throw new Error( `Missing key ${missingKey} or key not "leaf" in fromTranslationsObject for lang ${targetLang}. (2)`, @@ -147,20 +150,20 @@ export async function translateObject(props: { } let targetObj = allOnlyNewTranslatedTranslationsObject?.[targetLang] for (let i = 0; i < keys.length - 1; i += 1) { - if (!targetObj[keys[i]]) { - targetObj[keys[i]] = {} + if (!targetObj[keys[i] as string]) { + targetObj[keys[i] as string] = {} } - const nextObj = targetObj[keys[i]] + const nextObj = targetObj[keys[i] as string] if (typeof nextObj !== 'object') { throw new Error(`Key ${keys[i]} is not an object in ${targetLang} (3)`) } targetObj = nextObj } - targetObj[keys[keys.length - 1]] = translated + targetObj[keys[keys.length - 1] as string] = translated - allTranslatedTranslationsObject[targetLang].translations = sortKeys( + allTranslatedTranslationsObject[targetLang]!.translations = sortKeys( deepMergeSimple( - allTranslatedTranslationsObject[targetLang].translations, + allTranslatedTranslationsObject[targetLang]!.translations, allOnlyNewTranslatedTranslationsObject[targetLang], ), ) @@ -180,9 +183,14 @@ export async function translateObject(props: { console.log('New translations:', allOnlyNewTranslatedTranslationsObject) if (inlineFile?.length) { - const simpleTranslationsObject = {} + const simpleTranslationsObject: GenericTranslationsObject = {} for (const lang in allTranslatedTranslationsObject) { - simpleTranslationsObject[lang] = allTranslatedTranslationsObject[lang].translations + if (lang in allTranslatedTranslationsObject) { + simpleTranslationsObject[lang as keyof typeof allTranslatedTranslationsObject] = + allTranslatedTranslationsObject[ + lang as keyof typeof allTranslatedTranslationsObject + ]!.translations + } } // write allTranslatedTranslationsObject @@ -218,10 +226,10 @@ export async function translateObject(props: { const filePath = path.resolve(targetFolder, `${sanitizedKey}.ts`) // prefix & translations - let fileContent: string = `${tsFilePrefix.replace('{{locale}}', sanitizedKey)}${generateTsObjectLiteral(allTranslatedTranslationsObject[key].translations)}\n` + let fileContent: string = `${tsFilePrefix.replace('{{locale}}', sanitizedKey)}${generateTsObjectLiteral(allTranslatedTranslationsObject[key]?.translations || {})}\n` // suffix - fileContent += `${tsFileSuffix.replaceAll('{{locale}}', sanitizedKey).replaceAll('{{dateFNSKey}}', `'${allTranslatedTranslationsObject[key].dateFNSKey}'`)}\n` + fileContent += `${tsFileSuffix.replaceAll('{{locale}}', sanitizedKey).replaceAll('{{dateFNSKey}}', `'${allTranslatedTranslationsObject[key]?.dateFNSKey}'`)}\n` // eslint fileContent = await applyEslintFixes(fileContent, filePath) diff --git a/packages/translations/scripts/translateNewKeys/sortKeys.ts b/tools/scripts/src/generateTranslations/utils/sortKeys.ts similarity index 100% rename from packages/translations/scripts/translateNewKeys/sortKeys.ts rename to tools/scripts/src/generateTranslations/utils/sortKeys.ts diff --git a/packages/translations/scripts/translateNewKeys/translateText.ts b/tools/scripts/src/generateTranslations/utils/translateText.ts similarity index 95% rename from packages/translations/scripts/translateNewKeys/translateText.ts rename to tools/scripts/src/generateTranslations/utils/translateText.ts index e53d3d31d4..d7999e88b4 100644 --- a/packages/translations/scripts/translateNewKeys/translateText.ts +++ b/tools/scripts/src/generateTranslations/utils/translateText.ts @@ -4,7 +4,7 @@ import path from 'path' const filename = fileURLToPath(import.meta.url) const dirname = path.dirname(filename) -dotenv.config({ path: path.resolve(dirname, '../../', '.env') }) +dotenv.config({ path: path.resolve(dirname, '../../../../', '.env') }) export async function translateText(text: string, targetLang: string) { const response = await fetch('https://api.openai.com/v1/chat/completions', { diff --git a/tools/scripts/src/index.ts b/tools/scripts/src/index.ts deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/tools/scripts/tsconfig.build.json b/tools/scripts/tsconfig.build.json new file mode 100644 index 0000000000..bc25916d0a --- /dev/null +++ b/tools/scripts/tsconfig.build.json @@ -0,0 +1,12 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "strict": true + }, + "references": [ + { "path": "../../packages/translations" }, + { "path": "../../packages/richtext-lexical" }, + { "path": "../../packages/plugin-multi-tenant" } + ], + "exclude": ["./src/generateTranslations"] +} diff --git a/tools/scripts/tsconfig.json b/tools/scripts/tsconfig.json index f9f8fe292b..e14725842a 100644 --- a/tools/scripts/tsconfig.json +++ b/tools/scripts/tsconfig.json @@ -2,5 +2,6 @@ "extends": "../../tsconfig.base.json", "compilerOptions": { "strict": true, - } + }, + "references": [{ "path": "../../packages/translations" }, { "path": "../../packages/richtext-lexical"}, { "path": "../../packages/plugin-multi-tenant"}] } diff --git a/tsconfig.base.json b/tsconfig.base.json index 02de03b79e..b2e5e043e1 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -31,7 +31,7 @@ } ], "paths": { - "@payload-config": ["./test/admin/config.ts"], + "@payload-config": ["./test/plugin-multi-tenant/config.ts"], "@payloadcms/admin-bar": ["./packages/admin-bar/src"], "@payloadcms/live-preview": ["./packages/live-preview/src"], "@payloadcms/live-preview-react": ["./packages/live-preview-react/src/index.ts"], @@ -70,6 +70,12 @@ "./packages/plugin-multi-tenant/src/exports/client.ts" ], "@payloadcms/plugin-multi-tenant": ["./packages/plugin-multi-tenant/src/index.ts"], + "@payloadcms/plugin-multi-tenant/translations/languages/all": [ + "./packages/plugin-multi-tenant/src/translations/index.ts" + ], + "@payloadcms/plugin-multi-tenant/translations/languages/*": [ + "./packages/plugin-multi-tenant/src/translations/languages/*.ts" + ], "@payloadcms/next": ["./packages/next/src/exports/*"], "@payloadcms/storage-s3/client": ["./packages/storage-s3/src/exports/client.ts"], "@payloadcms/storage-vercel-blob/client": [