feat(plugin-multi-tenant): prompt the user to confirm the change of tenant before actually updating (#12382)
This commit is contained in:
@@ -74,6 +74,7 @@ export const rootEslintConfig = [
|
|||||||
'no-console': 'off',
|
'no-console': 'off',
|
||||||
'perfectionist/sort-object-types': 'off',
|
'perfectionist/sort-object-types': 'off',
|
||||||
'perfectionist/sort-objects': 'off',
|
'perfectionist/sort-objects': 'off',
|
||||||
|
'payload/no-relative-monorepo-imports': 'off',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -56,6 +56,16 @@
|
|||||||
"import": "./src/exports/utilities.ts",
|
"import": "./src/exports/utilities.ts",
|
||||||
"types": "./src/exports/utilities.ts",
|
"types": "./src/exports/utilities.ts",
|
||||||
"default": "./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",
|
"main": "./src/index.ts",
|
||||||
@@ -118,6 +128,16 @@
|
|||||||
"import": "./dist/exports/utilities.js",
|
"import": "./dist/exports/utilities.js",
|
||||||
"types": "./dist/exports/utilities.d.ts",
|
"types": "./dist/exports/utilities.d.ts",
|
||||||
"default": "./dist/exports/utilities.js"
|
"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",
|
"main": "./dist/index.js",
|
||||||
|
|||||||
@@ -3,18 +3,52 @@ import type { ReactSelectOption } from '@payloadcms/ui'
|
|||||||
import type { ViewTypes } from 'payload'
|
import type { ViewTypes } from 'payload'
|
||||||
|
|
||||||
import { getTranslation } from '@payloadcms/translations'
|
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 React from 'react'
|
||||||
|
|
||||||
|
import type {
|
||||||
|
PluginMultiTenantTranslationKeys,
|
||||||
|
PluginMultiTenantTranslations,
|
||||||
|
} from '../../translations/index.js'
|
||||||
|
|
||||||
import { useTenantSelection } from '../../providers/TenantSelectionProvider/index.client.js'
|
import { useTenantSelection } from '../../providers/TenantSelectionProvider/index.client.js'
|
||||||
import './index.scss'
|
import './index.scss'
|
||||||
|
|
||||||
export const TenantSelector = ({ label, viewType }: { label: string; viewType?: ViewTypes }) => {
|
const confirmSwitchTenantSlug = 'confirmSwitchTenant'
|
||||||
const { options, selectedTenantID, setTenant } = useTenantSelection()
|
|
||||||
const { i18n } = useTranslation()
|
|
||||||
|
|
||||||
const handleChange = React.useCallback(
|
export const TenantSelector = ({ label, viewType }: { label: string; viewType?: ViewTypes }) => {
|
||||||
(option: ReactSelectOption | ReactSelectOption[]) => {
|
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) {
|
if (option && 'value' in option) {
|
||||||
setTenant({ id: option.value as string, refresh: true })
|
setTenant({ id: option.value as string, refresh: true })
|
||||||
} else {
|
} else {
|
||||||
@@ -24,6 +58,19 @@ export const TenantSelector = ({ label, viewType }: { label: string; viewType?:
|
|||||||
[setTenant],
|
[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) {
|
if (options.length <= 1) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
@@ -34,11 +81,46 @@ export const TenantSelector = ({ label, viewType }: { label: string; viewType?:
|
|||||||
isClearable={viewType === 'list'}
|
isClearable={viewType === 'list'}
|
||||||
label={getTranslation(label, i18n)}
|
label={getTranslation(label, i18n)}
|
||||||
name="setTenant"
|
name="setTenant"
|
||||||
onChange={handleChange}
|
onChange={onChange}
|
||||||
options={options}
|
options={options}
|
||||||
path="setTenant"
|
path="setTenant"
|
||||||
value={selectedTenantID as string | undefined}
|
value={selectedTenantID as string | undefined}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<ConfirmationModal
|
||||||
|
body={
|
||||||
|
<Translation
|
||||||
|
elements={{
|
||||||
|
0: ({ children }) => {
|
||||||
|
return <b>{children}</b>
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
// 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={
|
||||||
|
<Translation
|
||||||
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||||
|
// @ts-expect-error
|
||||||
|
i18nKey="plugin-multi-tenant:confirm-tenant-switch--heading"
|
||||||
|
t={t}
|
||||||
|
variables={{
|
||||||
|
tenantLabel: label.toLowerCase(),
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
modalSlug={confirmSwitchTenantSlug}
|
||||||
|
onConfirm={() => {
|
||||||
|
switchTenant(tenantSelection)
|
||||||
|
}}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
}
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
export { TenantField } from '../components/TenantField/index.client.js'
|
export { TenantField } from '../components/TenantField/index.client.js'
|
||||||
export { TenantSelector } from '../components/TenantSelector/index.js'
|
export { TenantSelector } from '../components/TenantSelector/index.js'
|
||||||
|
export { WatchTenantCollection } from '../components/WatchTenantCollection/index.js'
|
||||||
export { useTenantSelection } from '../providers/TenantSelectionProvider/index.client.js'
|
export { useTenantSelection } from '../providers/TenantSelectionProvider/index.client.js'
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
import type { AcceptedLanguages } from '@payloadcms/translations'
|
import type { AcceptedLanguages } from '@payloadcms/translations'
|
||||||
import type { CollectionConfig, Config } from 'payload'
|
import type { CollectionConfig, Config } from 'payload'
|
||||||
|
|
||||||
|
import { deepMergeSimple } from 'payload'
|
||||||
|
|
||||||
|
import type { PluginDefaultTranslationsObject } from './translations/types.js'
|
||||||
import type { MultiTenantPluginConfig } from './types.js'
|
import type { MultiTenantPluginConfig } from './types.js'
|
||||||
|
|
||||||
import { defaults } from './defaults.js'
|
import { defaults } from './defaults.js'
|
||||||
@@ -10,6 +13,7 @@ import { addTenantCleanup } from './hooks/afterTenantDelete.js'
|
|||||||
import { filterDocumentsBySelectedTenant } from './list-filters/filterDocumentsBySelectedTenant.js'
|
import { filterDocumentsBySelectedTenant } from './list-filters/filterDocumentsBySelectedTenant.js'
|
||||||
import { filterTenantsBySelectedTenant } from './list-filters/filterTenantsBySelectedTenant.js'
|
import { filterTenantsBySelectedTenant } from './list-filters/filterTenantsBySelectedTenant.js'
|
||||||
import { filterUsersBySelectedTenant } from './list-filters/filterUsersBySelectedTenant.js'
|
import { filterUsersBySelectedTenant } from './list-filters/filterUsersBySelectedTenant.js'
|
||||||
|
import { translations } from './translations/index.js'
|
||||||
import { addCollectionAccess } from './utilities/addCollectionAccess.js'
|
import { addCollectionAccess } from './utilities/addCollectionAccess.js'
|
||||||
import { addFilterOptionsToFields } from './utilities/addFilterOptionsToFields.js'
|
import { addFilterOptionsToFields } from './utilities/addFilterOptionsToFields.js'
|
||||||
import { combineListFilters } from './utilities/combineListFilters.js'
|
import { combineListFilters } from './utilities/combineListFilters.js'
|
||||||
@@ -229,6 +233,21 @@ export const multiTenantPlugin =
|
|||||||
usersTenantsArrayTenantFieldName: tenantsArrayTenantFieldName,
|
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]) {
|
} else if (pluginConfig.collections?.[collection.slug]) {
|
||||||
const isGlobal = Boolean(pluginConfig.collections[collection.slug]?.isGlobal)
|
const isGlobal = Boolean(pluginConfig.collections[collection.slug]?.isGlobal)
|
||||||
|
|
||||||
@@ -340,5 +359,25 @@ export const multiTenantPlugin =
|
|||||||
path: '@payloadcms/plugin-multi-tenant/client#TenantSelector',
|
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<string, PluginDefaultTranslationsObject>,
|
||||||
|
)
|
||||||
|
|
||||||
|
incomingConfig.i18n = {
|
||||||
|
...incomingConfig.i18n,
|
||||||
|
translations: deepMergeSimple(
|
||||||
|
simplifiedTranslations,
|
||||||
|
incomingConfig.i18n?.translations ?? {},
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
||||||
return incomingConfig
|
return incomingConfig
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ type ContextType = {
|
|||||||
* Array of options to select from
|
* Array of options to select from
|
||||||
*/
|
*/
|
||||||
options: OptionObject[]
|
options: OptionObject[]
|
||||||
|
preventRefreshOnChange: boolean
|
||||||
/**
|
/**
|
||||||
* The currently selected tenant ID
|
* The currently selected tenant ID
|
||||||
*/
|
*/
|
||||||
@@ -28,20 +29,26 @@ type ContextType = {
|
|||||||
* @param args.refresh - Whether to refresh the page after changing the tenant
|
* @param args.refresh - Whether to refresh the page after changing the tenant
|
||||||
*/
|
*/
|
||||||
setTenant: (args: { id: number | string | undefined; refresh?: boolean }) => void
|
setTenant: (args: { id: number | string | undefined; refresh?: boolean }) => void
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
updateTenants: (args: { id: number | string; label: string }) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
const Context = createContext<ContextType>({
|
const Context = createContext<ContextType>({
|
||||||
options: [],
|
options: [],
|
||||||
|
preventRefreshOnChange: false,
|
||||||
selectedTenantID: undefined,
|
selectedTenantID: undefined,
|
||||||
setPreventRefreshOnChange: () => null,
|
setPreventRefreshOnChange: () => null,
|
||||||
setTenant: () => null,
|
setTenant: () => null,
|
||||||
|
updateTenants: () => null,
|
||||||
})
|
})
|
||||||
|
|
||||||
export const TenantSelectionProviderClient = ({
|
export const TenantSelectionProviderClient = ({
|
||||||
children,
|
children,
|
||||||
initialValue,
|
initialValue,
|
||||||
tenantCookie,
|
tenantCookie,
|
||||||
tenantOptions,
|
tenantOptions: tenantOptionsFromProps,
|
||||||
}: {
|
}: {
|
||||||
children: React.ReactNode
|
children: React.ReactNode
|
||||||
initialValue?: number | string
|
initialValue?: number | string
|
||||||
@@ -54,6 +61,9 @@ export const TenantSelectionProviderClient = ({
|
|||||||
const [preventRefreshOnChange, setPreventRefreshOnChange] = React.useState(false)
|
const [preventRefreshOnChange, setPreventRefreshOnChange] = React.useState(false)
|
||||||
const { user } = useAuth()
|
const { user } = useAuth()
|
||||||
const userID = React.useMemo(() => user?.id, [user?.id])
|
const userID = React.useMemo(() => user?.id, [user?.id])
|
||||||
|
const [tenantOptions, setTenantOptions] = React.useState<OptionObject[]>(
|
||||||
|
() => tenantOptionsFromProps,
|
||||||
|
)
|
||||||
const selectedTenantLabel = React.useMemo(
|
const selectedTenantLabel = React.useMemo(
|
||||||
() => tenantOptions.find((option) => option.value === selectedTenantID)?.label,
|
() => tenantOptions.find((option) => option.value === selectedTenantID)?.label,
|
||||||
[selectedTenantID, tenantOptions],
|
[selectedTenantID, tenantOptions],
|
||||||
@@ -91,6 +101,20 @@ export const TenantSelectionProviderClient = ({
|
|||||||
[deleteCookie, preventRefreshOnChange, router, setCookie, setSelectedTenantID, tenantOptions],
|
[deleteCookie, preventRefreshOnChange, router, setCookie, setSelectedTenantID, tenantOptions],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const updateTenants = React.useCallback<ContextType['updateTenants']>(({ id, label }) => {
|
||||||
|
setTenantOptions((prev) => {
|
||||||
|
return prev.map((currentTenant) => {
|
||||||
|
if (id === currentTenant.value) {
|
||||||
|
return {
|
||||||
|
label,
|
||||||
|
value: id,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return currentTenant
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}, [])
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
if (selectedTenantID && !tenantOptions.find((option) => option.value === selectedTenantID)) {
|
if (selectedTenantID && !tenantOptions.find((option) => option.value === selectedTenantID)) {
|
||||||
if (tenantOptions?.[0]?.value) {
|
if (tenantOptions?.[0]?.value) {
|
||||||
@@ -105,13 +129,14 @@ export const TenantSelectionProviderClient = ({
|
|||||||
if (userID && !tenantCookie) {
|
if (userID && !tenantCookie) {
|
||||||
// User is logged in, but does not have a tenant cookie, set it
|
// User is logged in, but does not have a tenant cookie, set it
|
||||||
setSelectedTenantID(initialValue)
|
setSelectedTenantID(initialValue)
|
||||||
|
setTenantOptions(tenantOptionsFromProps)
|
||||||
if (initialValue) {
|
if (initialValue) {
|
||||||
setCookie(String(initialValue))
|
setCookie(String(initialValue))
|
||||||
} else {
|
} else {
|
||||||
deleteCookie()
|
deleteCookie()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [userID, tenantCookie, initialValue, setCookie, deleteCookie, router])
|
}, [userID, tenantCookie, initialValue, setCookie, deleteCookie, router, tenantOptionsFromProps])
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
if (!userID && tenantCookie) {
|
if (!userID && tenantCookie) {
|
||||||
@@ -132,9 +157,11 @@ export const TenantSelectionProviderClient = ({
|
|||||||
<Context
|
<Context
|
||||||
value={{
|
value={{
|
||||||
options: tenantOptions,
|
options: tenantOptions,
|
||||||
|
preventRefreshOnChange,
|
||||||
selectedTenantID,
|
selectedTenantID,
|
||||||
setPreventRefreshOnChange,
|
setPreventRefreshOnChange,
|
||||||
setTenant,
|
setTenant,
|
||||||
|
updateTenants,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
|
|||||||
91
packages/plugin-multi-tenant/src/translations/index.ts
Normal file
91
packages/plugin-multi-tenant/src/translations/index.ts
Normal file
@@ -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<PluginDefaultTranslationsObject>
|
||||||
|
|
||||||
|
export type PluginMultiTenantTranslations = GenericTranslationsObject
|
||||||
|
|
||||||
|
export type PluginMultiTenantTranslationKeys = NestedKeysStripped<PluginMultiTenantTranslations>
|
||||||
@@ -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> إلى <0>{{toTenant}}</0>',
|
||||||
|
'confirm-tenant-switch--heading': 'تأكيد تغيير {{tenantLabel}}',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export const ar: PluginLanguage = {
|
||||||
|
dateFNSKey: 'ar',
|
||||||
|
translations: arTranslations,
|
||||||
|
}
|
||||||
@@ -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}}</0> mülkiyyətini <0>{{toTenant}}</0> 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,
|
||||||
|
}
|
||||||
@@ -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> на <0>{{toTenant}}</0>',
|
||||||
|
'confirm-tenant-switch--heading': 'Потвърдете промяната на {{tenantLabel}}',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export const bg: PluginLanguage = {
|
||||||
|
dateFNSKey: 'bg',
|
||||||
|
translations: bgTranslations,
|
||||||
|
}
|
||||||
@@ -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}}</0> a <0>{{toTenant}}</0>',
|
||||||
|
'confirm-tenant-switch--heading': 'Confirmeu el canvi de {{tenantLabel}}',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export const ca: PluginLanguage = {
|
||||||
|
dateFNSKey: 'ca',
|
||||||
|
translations: caTranslations,
|
||||||
|
}
|
||||||
@@ -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}}</0> na <0>{{toTenant}}</0>',
|
||||||
|
'confirm-tenant-switch--heading': 'Potvrďte změnu {{tenantLabel}}',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export const cs: PluginLanguage = {
|
||||||
|
dateFNSKey: 'cs',
|
||||||
|
translations: csTranslations,
|
||||||
|
}
|
||||||
@@ -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}}</0> til <0>{{toTenant}}</0>',
|
||||||
|
'confirm-tenant-switch--heading': 'Bekræft {{tenantLabel}} ændring',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export const da: PluginLanguage = {
|
||||||
|
dateFNSKey: 'da',
|
||||||
|
translations: daTranslations,
|
||||||
|
}
|
||||||
@@ -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}}</0> auf <0>{{toTenant}}</0> zu übertragen.',
|
||||||
|
'confirm-tenant-switch--heading': 'Bestätigen Sie die Änderung von {{tenantLabel}}.',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export const de: PluginLanguage = {
|
||||||
|
dateFNSKey: 'de',
|
||||||
|
translations: deTranslations,
|
||||||
|
}
|
||||||
@@ -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}}</0> to <0>{{toTenant}}</0>',
|
||||||
|
'confirm-tenant-switch--heading': 'Confirm {{tenantLabel}} change',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export const en: PluginLanguage = {
|
||||||
|
dateFNSKey: 'en-US',
|
||||||
|
translations: enTranslations,
|
||||||
|
}
|
||||||
@@ -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}}</0> a <0>{{toTenant}}</0>',
|
||||||
|
'confirm-tenant-switch--heading': 'Confirme el cambio de {{tenantLabel}}',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export const es: PluginLanguage = {
|
||||||
|
dateFNSKey: 'es',
|
||||||
|
translations: esTranslations,
|
||||||
|
}
|
||||||
@@ -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}}</0>lt <0>{{toTenant}}</0>le.',
|
||||||
|
'confirm-tenant-switch--heading': 'Kinnita {{tenantLabel}} muutus',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export const et: PluginLanguage = {
|
||||||
|
dateFNSKey: 'et',
|
||||||
|
translations: etTranslations,
|
||||||
|
}
|
||||||
@@ -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> به <0>{{toTenant}}</0> هستید',
|
||||||
|
'confirm-tenant-switch--heading': 'تایید تغییر {{tenantLabel}}',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export const fa: PluginLanguage = {
|
||||||
|
dateFNSKey: 'fa-IR',
|
||||||
|
translations: faTranslations,
|
||||||
|
}
|
||||||
@@ -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> à <0>{{toTenant}}</0>',
|
||||||
|
'confirm-tenant-switch--heading': 'Confirmer le changement de {{tenantLabel}}',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export const fr: PluginLanguage = {
|
||||||
|
dateFNSKey: 'fr',
|
||||||
|
translations: frTranslations,
|
||||||
|
}
|
||||||
@@ -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> ל- <0>{{toTenant}}</0>',
|
||||||
|
'confirm-tenant-switch--heading': 'אשר שינוי {{tenantLabel}}',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export const he: PluginLanguage = {
|
||||||
|
dateFNSKey: 'he',
|
||||||
|
translations: heTranslations,
|
||||||
|
}
|
||||||
@@ -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}}</0> na <0>{{toTenant}}</0>',
|
||||||
|
'confirm-tenant-switch--heading': 'Potvrdi promjenu {{tenantLabel}}',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export const hr: PluginLanguage = {
|
||||||
|
dateFNSKey: 'hr',
|
||||||
|
translations: hrTranslations,
|
||||||
|
}
|
||||||
@@ -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}}</0>-ről <0>{{toTenant}}</0>-re.',
|
||||||
|
'confirm-tenant-switch--heading': 'Erősítse meg a(z) {{tenantLabel}} változtatást',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export const hu: PluginLanguage = {
|
||||||
|
dateFNSKey: 'hu',
|
||||||
|
translations: huTranslations,
|
||||||
|
}
|
||||||
@@ -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>-ից <0>{{toTenant}}</0>-ին',
|
||||||
|
'confirm-tenant-switch--heading': 'Հաստատեք {{tenantLabel}} փոփոխությունը',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export const hy: PluginLanguage = {
|
||||||
|
dateFNSKey: 'hy-AM',
|
||||||
|
translations: hyTranslations,
|
||||||
|
}
|
||||||
@@ -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}}</0> a <0>{{toTenant}}</0>',
|
||||||
|
'confirm-tenant-switch--heading': 'Conferma il cambiamento di {{tenantLabel}}',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export const it: PluginLanguage = {
|
||||||
|
dateFNSKey: 'it',
|
||||||
|
translations: itTranslations,
|
||||||
|
}
|
||||||
@@ -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>から<0>{{toTenant}}</0>へ変更しようとしています',
|
||||||
|
'confirm-tenant-switch--heading': '{{tenantLabel}}の変更を確認してください',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export const ja: PluginLanguage = {
|
||||||
|
dateFNSKey: 'ja',
|
||||||
|
translations: jaTranslations,
|
||||||
|
}
|
||||||
@@ -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>에서 <0>{{toTenant}}</0>으로 소유권을 변경하려고 합니다.',
|
||||||
|
'confirm-tenant-switch--heading': '{{tenantLabel}} 변경을 확인하세요',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export const ko: PluginLanguage = {
|
||||||
|
dateFNSKey: 'ko',
|
||||||
|
translations: koTranslations,
|
||||||
|
}
|
||||||
@@ -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> į <0>{{toTenant}}</0>',
|
||||||
|
'confirm-tenant-switch--heading': 'Patvirtinkite {{tenantLabel}} pakeitimą',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export const lt: PluginLanguage = {
|
||||||
|
dateFNSKey: 'lt',
|
||||||
|
translations: ltTranslations,
|
||||||
|
}
|
||||||
@@ -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}}</0> ke <0>{{toTenant}}</0>',
|
||||||
|
'confirm-tenant-switch--heading': 'Sahkan perubahan {{tenantLabel}}',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export const my: PluginLanguage = {
|
||||||
|
dateFNSKey: 'en-US',
|
||||||
|
translations: myTranslations,
|
||||||
|
}
|
||||||
@@ -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}}</0> til <0>{{toTenant}}</0>',
|
||||||
|
'confirm-tenant-switch--heading': 'Bekreft {{tenantLabel}} endring',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export const nb: PluginLanguage = {
|
||||||
|
dateFNSKey: 'nb',
|
||||||
|
translations: nbTranslations,
|
||||||
|
}
|
||||||
@@ -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}}</0> naar <0>{{toTenant}}</0>',
|
||||||
|
'confirm-tenant-switch--heading': 'Bevestig wijziging van {{tenantLabel}}',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export const nl: PluginLanguage = {
|
||||||
|
dateFNSKey: 'nl',
|
||||||
|
translations: nlTranslations,
|
||||||
|
}
|
||||||
@@ -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}}</0> na <0>{{toTenant}}</0>',
|
||||||
|
'confirm-tenant-switch--heading': 'Potwierdź zmianę {{tenantLabel}}',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export const pl: PluginLanguage = {
|
||||||
|
dateFNSKey: 'pl',
|
||||||
|
translations: plTranslations,
|
||||||
|
}
|
||||||
@@ -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}}</0> para <0>{{toTenant}}</0>',
|
||||||
|
'confirm-tenant-switch--heading': 'Confirme a alteração de {{tenantLabel}}',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export const pt: PluginLanguage = {
|
||||||
|
dateFNSKey: 'pt',
|
||||||
|
translations: ptTranslations,
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
for file in *.js; do
|
||||||
|
mv -- "$file" "${file%.js}.ts"
|
||||||
|
done
|
||||||
@@ -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}}</0> la <0>{{toTenant}}</0>',
|
||||||
|
'confirm-tenant-switch--heading': 'Confirmați schimbarea {{tenantLabel}}',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export const ro: PluginLanguage = {
|
||||||
|
dateFNSKey: 'ro',
|
||||||
|
translations: roTranslations,
|
||||||
|
}
|
||||||
@@ -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}}</0> na <0>{{toTenant}}</0>',
|
||||||
|
'confirm-tenant-switch--heading': 'Potvrdi promena {{tenantLabel}}',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export const rs: PluginLanguage = {
|
||||||
|
dateFNSKey: 'rs',
|
||||||
|
translations: rsTranslations,
|
||||||
|
}
|
||||||
@@ -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}}</0> na <0>{{toTenant}}</0>',
|
||||||
|
'confirm-tenant-switch--heading': 'Potvrdite promenu {{tenantLabel}}',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export const rsLatin: PluginLanguage = {
|
||||||
|
dateFNSKey: 'rs-Latin',
|
||||||
|
translations: rsLatinTranslations,
|
||||||
|
}
|
||||||
@@ -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> на <0>{{toTenant}}</0>',
|
||||||
|
'confirm-tenant-switch--heading': 'Подтвердите изменение {{tenantLabel}}',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export const ru: PluginLanguage = {
|
||||||
|
dateFNSKey: 'ru',
|
||||||
|
translations: ruTranslations,
|
||||||
|
}
|
||||||
@@ -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}}</0> na <0>{{toTenant}}</0>',
|
||||||
|
'confirm-tenant-switch--heading': 'Potvrďte zmenu {{tenantLabel}}',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export const sk: PluginLanguage = {
|
||||||
|
dateFNSKey: 'sk',
|
||||||
|
translations: skTranslations,
|
||||||
|
}
|
||||||
@@ -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}}</0> na <0>{{toTenant}}</0>',
|
||||||
|
'confirm-tenant-switch--heading': 'Potrdi spremembo {{tenantLabel}}',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export const sl: PluginLanguage = {
|
||||||
|
dateFNSKey: 'sl-SI',
|
||||||
|
translations: slTranslations,
|
||||||
|
}
|
||||||
@@ -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}}</0> till <0>{{toTenant}}</0>',
|
||||||
|
'confirm-tenant-switch--heading': 'Bekräfta ändring av {{tenantLabel}}',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export const sv: PluginLanguage = {
|
||||||
|
dateFNSKey: 'sv',
|
||||||
|
translations: svTranslations,
|
||||||
|
}
|
||||||
@@ -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> เป็น <0>{{toTenant}}</0>',
|
||||||
|
'confirm-tenant-switch--heading': 'ยืนยันการเปลี่ยนแปลง {{tenantLabel}}',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export const th: PluginLanguage = {
|
||||||
|
dateFNSKey: 'th',
|
||||||
|
translations: thTranslations,
|
||||||
|
}
|
||||||
@@ -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}}</0>'den <0>{{toTenant}}</0>'e değiştirmek üzeresiniz.",
|
||||||
|
'confirm-tenant-switch--heading': '{{tenantLabel}} değişikliğini onayla',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export const tr: PluginLanguage = {
|
||||||
|
dateFNSKey: 'tr',
|
||||||
|
translations: trTranslations,
|
||||||
|
}
|
||||||
@@ -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> на <0>{{toTenant}}</0>',
|
||||||
|
'confirm-tenant-switch--heading': 'Підтвердіть зміну {{tenantLabel}}',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export const uk: PluginLanguage = {
|
||||||
|
dateFNSKey: 'uk',
|
||||||
|
translations: ukTranslations,
|
||||||
|
}
|
||||||
@@ -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}}</0> sang <0>{{toTenant}}</0>',
|
||||||
|
'confirm-tenant-switch--heading': 'Xác nhận thay đổi {{tenantLabel}}',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export const vi: PluginLanguage = {
|
||||||
|
dateFNSKey: 'vi',
|
||||||
|
translations: viTranslations,
|
||||||
|
}
|
||||||
@@ -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>更改为<0>{{toTenant}}</0>',
|
||||||
|
'confirm-tenant-switch--heading': '确认更改{{tenantLabel}}',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export const zh: PluginLanguage = {
|
||||||
|
dateFNSKey: 'zh-CN',
|
||||||
|
translations: zhTranslations,
|
||||||
|
}
|
||||||
@@ -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> 轉移至 <0>{{toTenant}}</0>',
|
||||||
|
'confirm-tenant-switch--heading': '確認{{tenantLabel}}更改',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export const zhTw: PluginLanguage = {
|
||||||
|
dateFNSKey: 'zh-TW',
|
||||||
|
translations: zhTwTranslations,
|
||||||
|
}
|
||||||
12
packages/plugin-multi-tenant/src/translations/types.ts
Normal file
12
packages/plugin-multi-tenant/src/translations/types.ts
Normal file
@@ -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
|
||||||
@@ -344,8 +344,7 @@
|
|||||||
"copyfiles": "copyfiles -u 1 \"src/**/*.{html,css,ttf,woff,woff2,eot,svg,jpg,png,json}\" dist/",
|
"copyfiles": "copyfiles -u 1 \"src/**/*.{html,css,ttf,woff,woff2,eot,svg,jpg,png,json}\" dist/",
|
||||||
"lint": "eslint .",
|
"lint": "eslint .",
|
||||||
"lint:fix": "eslint . --fix",
|
"lint:fix": "eslint . --fix",
|
||||||
"prepublishOnly": "pnpm clean && pnpm turbo build",
|
"prepublishOnly": "pnpm clean && pnpm turbo build"
|
||||||
"translateNewKeys": "node --no-deprecation --import @swc-node/register/esm-register scripts/translateNewKeys.ts"
|
|
||||||
},
|
},
|
||||||
"lint-staged": {
|
"lint-staged": {
|
||||||
"**/package.json": "sort-package-json",
|
"**/package.json": "sort-package-json",
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
OPENAI_KEY=sk-
|
|
||||||
@@ -51,8 +51,7 @@
|
|||||||
"clean": "rimraf -g {dist,*.tsbuildinfo}",
|
"clean": "rimraf -g {dist,*.tsbuildinfo}",
|
||||||
"lint": "eslint .",
|
"lint": "eslint .",
|
||||||
"lint:fix": "eslint . --fix",
|
"lint:fix": "eslint . --fix",
|
||||||
"prepublishOnly": "pnpm clean && pnpm turbo build",
|
"prepublishOnly": "pnpm clean && pnpm turbo build"
|
||||||
"translateNewKeys": "node --no-deprecation --import @swc-node/register/esm-register scripts/translateNewKeys/run.ts"
|
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"date-fns": "4.1.0"
|
"date-fns": "4.1.0"
|
||||||
|
|||||||
@@ -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'),
|
|
||||||
})
|
|
||||||
13
pnpm-lock.yaml
generated
13
pnpm-lock.yaml
generated
@@ -1958,6 +1958,19 @@ importers:
|
|||||||
open:
|
open:
|
||||||
specifier: ^10.1.0
|
specifier: ^10.1.0
|
||||||
version: 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:
|
packages:
|
||||||
|
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ export default buildConfigWithDefaults({
|
|||||||
isGlobal: true,
|
isGlobal: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
tenantSelectorLabel: 'Sites',
|
tenantSelectorLabel: 'Site',
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
typescript: {
|
typescript: {
|
||||||
|
|||||||
1
tools/.env.example
Normal file
1
tools/.env.example
Normal file
@@ -0,0 +1 @@
|
|||||||
|
OPENAI_KEY=sk-your-key-here
|
||||||
@@ -13,9 +13,11 @@
|
|||||||
},
|
},
|
||||||
"main": "src/index.ts",
|
"main": "src/index.ts",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "tsc",
|
"build": "tsc --project tsconfig.build.json",
|
||||||
"build-template-with-local-pkgs": "pnpm runts src/build-template-with-local-pkgs.ts",
|
"build-template-with-local-pkgs": "pnpm runts src/build-template-with-local-pkgs.ts",
|
||||||
"gen-templates": "pnpm runts src/generate-template-variations.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",
|
"license-check": "pnpm runts src/license-check.ts",
|
||||||
"lint": "eslint .",
|
"lint": "eslint .",
|
||||||
"lint:fix": "eslint . --fix",
|
"lint:fix": "eslint . --fix",
|
||||||
@@ -32,6 +34,12 @@
|
|||||||
"create-payload-app": "workspace:*",
|
"create-payload-app": "workspace:*",
|
||||||
"csv-stringify": "^6.5.2",
|
"csv-stringify": "^6.5.2",
|
||||||
"license-checker": "25.0.1",
|
"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:*"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
31
tools/scripts/src/generateTranslations/core.ts
Normal file
31
tools/scripts/src/generateTranslations/core.ts
Normal file
@@ -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'),
|
||||||
|
})
|
||||||
@@ -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,
|
||||||
|
} `,
|
||||||
|
})
|
||||||
@@ -8,13 +8,13 @@ import * as fs from 'node:fs'
|
|||||||
import path from 'path'
|
import path from 'path'
|
||||||
import { fileURLToPath } from 'url'
|
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 filename = fileURLToPath(import.meta.url)
|
||||||
const dirname = path.dirname(filename)
|
const dirname = path.dirname(filename)
|
||||||
|
|
||||||
// Function to get all files with a specific name recursively in all subdirectories
|
// Function to get all files with a specific name recursively in all subdirectories
|
||||||
function findFilesRecursively(startPath, filter) {
|
function findFilesRecursively(startPath: string, filter: string): string[] {
|
||||||
let results = []
|
let results: string[] = []
|
||||||
|
|
||||||
const entries = fs.readdirSync(startPath, { withFileTypes: true })
|
const entries = fs.readdirSync(startPath, { withFileTypes: true })
|
||||||
|
|
||||||
@@ -33,7 +33,10 @@ function findFilesRecursively(startPath, filter) {
|
|||||||
return results
|
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() {
|
async function translate() {
|
||||||
for (const i18nFilePath of i18nFilePaths) {
|
for (const i18nFilePath of i18nFilePaths) {
|
||||||
@@ -46,22 +49,26 @@ async function translate() {
|
|||||||
}
|
}
|
||||||
} = {}
|
} = {}
|
||||||
for (const lang in translationsObject) {
|
for (const lang in translationsObject) {
|
||||||
allTranslations[lang] = {
|
allTranslations[lang as AcceptedLanguages] = {
|
||||||
dateFNSKey: 'en',
|
dateFNSKey: 'en',
|
||||||
translations: translationsObject[lang],
|
translations: translationsObject?.[lang as keyof GenericLanguages] || {},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log('Translating', i18nFilePath)
|
if (translationsObject.en) {
|
||||||
await translateObject({
|
console.log('Translating', i18nFilePath)
|
||||||
allTranslationsObject: allTranslations,
|
await translateObject({
|
||||||
fromTranslationsObject: translationsObject.en,
|
allTranslationsObject: allTranslations,
|
||||||
inlineFile: i18nFilePath,
|
fromTranslationsObject: translationsObject.en,
|
||||||
tsFilePrefix: `import { GenericLanguages } from '@payloadcms/translations'
|
inlineFile: i18nFilePath,
|
||||||
|
tsFilePrefix: `import { GenericLanguages } from '@payloadcms/translations'
|
||||||
export const i18n: Partial<GenericLanguages> = `,
|
|
||||||
tsFileSuffix: ``,
|
export const i18n: Partial<GenericLanguages> = `,
|
||||||
})
|
tsFileSuffix: ``,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
console.error(`No English translations found in ${i18nFilePath}`)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -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
|
* Returns keys which are present in baseObj but not in targetObj
|
||||||
@@ -8,7 +8,7 @@ export function findMissingKeys(
|
|||||||
targetObj: GenericTranslationsObject,
|
targetObj: GenericTranslationsObject,
|
||||||
prefix = '',
|
prefix = '',
|
||||||
): string[] {
|
): string[] {
|
||||||
let missingKeys = []
|
let missingKeys: string[] = []
|
||||||
|
|
||||||
for (const key in baseObj) {
|
for (const key in baseObj) {
|
||||||
const baseValue = baseObj[key]
|
const baseValue = baseObj[key]
|
||||||
@@ -1,5 +1,7 @@
|
|||||||
export function generateTsObjectLiteral(obj: any): string {
|
import type { JsonObject } from 'payload'
|
||||||
const lines = []
|
|
||||||
|
export function generateTsObjectLiteral(obj: JsonObject): string {
|
||||||
|
const lines: string[] = []
|
||||||
const entries = Object.entries(obj)
|
const entries = Object.entries(obj)
|
||||||
for (const [key, value] of entries) {
|
for (const [key, value] of entries) {
|
||||||
const safeKey = /^[\w$]+$/.test(key) ? key : JSON.stringify(key)
|
const safeKey = /^[\w$]+$/.test(key) ? key : JSON.stringify(key)
|
||||||
@@ -1,17 +1,17 @@
|
|||||||
/* eslint no-console: 0 */
|
/* eslint no-console: 0 */
|
||||||
|
|
||||||
import fs from 'fs'
|
|
||||||
import path from 'path'
|
|
||||||
import { format } from 'prettier'
|
|
||||||
|
|
||||||
import type {
|
import type {
|
||||||
AcceptedLanguages,
|
AcceptedLanguages,
|
||||||
GenericLanguages,
|
GenericLanguages,
|
||||||
GenericTranslationsObject,
|
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 { applyEslintFixes } from './applyEslintFixes.js'
|
||||||
import { findMissingKeys } from './findMissingKeys.js'
|
import { findMissingKeys } from './findMissingKeys.js'
|
||||||
import { generateTsObjectLiteral } from './generateTsObjectLiteral.js'
|
import { generateTsObjectLiteral } from './generateTsObjectLiteral.js'
|
||||||
@@ -104,16 +104,16 @@ export async function translateObject(props: {
|
|||||||
*/
|
*/
|
||||||
for (const key of keysWhichDoNotExistInFromlang) {
|
for (const key of keysWhichDoNotExistInFromlang) {
|
||||||
// Delete those keys in the target language object obj[lang]
|
// Delete those keys in the target language object obj[lang]
|
||||||
const keys = key.split('.')
|
const keys: string[] = key.split('.')
|
||||||
let targetObj = allTranslatedTranslationsObject?.[targetLang].translations
|
let targetObj = allTranslatedTranslationsObject?.[targetLang].translations
|
||||||
for (let i = 0; i < keys.length - 1; i += 1) {
|
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') {
|
if (typeof nextObj !== 'object') {
|
||||||
throw new Error(`Key ${keys[i]} is not an object in ${targetLang} (1)`)
|
throw new Error(`Key ${keys[i]} is not an object in ${targetLang} (1)`)
|
||||||
}
|
}
|
||||||
targetObj = nextObj
|
targetObj = nextObj
|
||||||
}
|
}
|
||||||
delete targetObj[keys[keys.length - 1]]
|
delete targetObj[keys[keys.length - 1] as string]
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!allTranslatedTranslationsObject?.[targetLang].translations) {
|
if (!allTranslatedTranslationsObject?.[targetLang].translations) {
|
||||||
@@ -128,7 +128,10 @@ export async function translateObject(props: {
|
|||||||
|
|
||||||
for (const missingKey of missingKeys) {
|
for (const missingKey of missingKeys) {
|
||||||
const keys: string[] = missingKey.split('.')
|
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') {
|
if (!sourceText || typeof sourceText !== 'string') {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Missing key ${missingKey} or key not "leaf" in fromTranslationsObject for lang ${targetLang}. (2)`,
|
`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]
|
let targetObj = allOnlyNewTranslatedTranslationsObject?.[targetLang]
|
||||||
for (let i = 0; i < keys.length - 1; i += 1) {
|
for (let i = 0; i < keys.length - 1; i += 1) {
|
||||||
if (!targetObj[keys[i]]) {
|
if (!targetObj[keys[i] as string]) {
|
||||||
targetObj[keys[i]] = {}
|
targetObj[keys[i] as string] = {}
|
||||||
}
|
}
|
||||||
const nextObj = targetObj[keys[i]]
|
const nextObj = targetObj[keys[i] as string]
|
||||||
if (typeof nextObj !== 'object') {
|
if (typeof nextObj !== 'object') {
|
||||||
throw new Error(`Key ${keys[i]} is not an object in ${targetLang} (3)`)
|
throw new Error(`Key ${keys[i]} is not an object in ${targetLang} (3)`)
|
||||||
}
|
}
|
||||||
targetObj = nextObj
|
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(
|
deepMergeSimple(
|
||||||
allTranslatedTranslationsObject[targetLang].translations,
|
allTranslatedTranslationsObject[targetLang]!.translations,
|
||||||
allOnlyNewTranslatedTranslationsObject[targetLang],
|
allOnlyNewTranslatedTranslationsObject[targetLang],
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
@@ -180,9 +183,14 @@ export async function translateObject(props: {
|
|||||||
console.log('New translations:', allOnlyNewTranslatedTranslationsObject)
|
console.log('New translations:', allOnlyNewTranslatedTranslationsObject)
|
||||||
|
|
||||||
if (inlineFile?.length) {
|
if (inlineFile?.length) {
|
||||||
const simpleTranslationsObject = {}
|
const simpleTranslationsObject: GenericTranslationsObject = {}
|
||||||
for (const lang in allTranslatedTranslationsObject) {
|
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
|
// write allTranslatedTranslationsObject
|
||||||
@@ -218,10 +226,10 @@ export async function translateObject(props: {
|
|||||||
const filePath = path.resolve(targetFolder, `${sanitizedKey}.ts`)
|
const filePath = path.resolve(targetFolder, `${sanitizedKey}.ts`)
|
||||||
|
|
||||||
// prefix & translations
|
// 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
|
// suffix
|
||||||
fileContent += `${tsFileSuffix.replaceAll('{{locale}}', sanitizedKey).replaceAll('{{dateFNSKey}}', `'${allTranslatedTranslationsObject[key].dateFNSKey}'`)}\n`
|
fileContent += `${tsFileSuffix.replaceAll('{{locale}}', sanitizedKey).replaceAll('{{dateFNSKey}}', `'${allTranslatedTranslationsObject[key]?.dateFNSKey}'`)}\n`
|
||||||
|
|
||||||
// eslint
|
// eslint
|
||||||
fileContent = await applyEslintFixes(fileContent, filePath)
|
fileContent = await applyEslintFixes(fileContent, filePath)
|
||||||
@@ -4,7 +4,7 @@ import path from 'path'
|
|||||||
const filename = fileURLToPath(import.meta.url)
|
const filename = fileURLToPath(import.meta.url)
|
||||||
const dirname = path.dirname(filename)
|
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) {
|
export async function translateText(text: string, targetLang: string) {
|
||||||
const response = await fetch('https://api.openai.com/v1/chat/completions', {
|
const response = await fetch('https://api.openai.com/v1/chat/completions', {
|
||||||
12
tools/scripts/tsconfig.build.json
Normal file
12
tools/scripts/tsconfig.build.json
Normal file
@@ -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"]
|
||||||
|
}
|
||||||
@@ -2,5 +2,6 @@
|
|||||||
"extends": "../../tsconfig.base.json",
|
"extends": "../../tsconfig.base.json",
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"strict": true,
|
"strict": true,
|
||||||
}
|
},
|
||||||
|
"references": [{ "path": "../../packages/translations" }, { "path": "../../packages/richtext-lexical"}, { "path": "../../packages/plugin-multi-tenant"}]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,7 +31,7 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"paths": {
|
"paths": {
|
||||||
"@payload-config": ["./test/admin/config.ts"],
|
"@payload-config": ["./test/plugin-multi-tenant/config.ts"],
|
||||||
"@payloadcms/admin-bar": ["./packages/admin-bar/src"],
|
"@payloadcms/admin-bar": ["./packages/admin-bar/src"],
|
||||||
"@payloadcms/live-preview": ["./packages/live-preview/src"],
|
"@payloadcms/live-preview": ["./packages/live-preview/src"],
|
||||||
"@payloadcms/live-preview-react": ["./packages/live-preview-react/src/index.ts"],
|
"@payloadcms/live-preview-react": ["./packages/live-preview-react/src/index.ts"],
|
||||||
@@ -70,6 +70,12 @@
|
|||||||
"./packages/plugin-multi-tenant/src/exports/client.ts"
|
"./packages/plugin-multi-tenant/src/exports/client.ts"
|
||||||
],
|
],
|
||||||
"@payloadcms/plugin-multi-tenant": ["./packages/plugin-multi-tenant/src/index.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/next": ["./packages/next/src/exports/*"],
|
||||||
"@payloadcms/storage-s3/client": ["./packages/storage-s3/src/exports/client.ts"],
|
"@payloadcms/storage-s3/client": ["./packages/storage-s3/src/exports/client.ts"],
|
||||||
"@payloadcms/storage-vercel-blob/client": [
|
"@payloadcms/storage-vercel-blob/client": [
|
||||||
|
|||||||
Reference in New Issue
Block a user