adds Translation component and removes more react-i18next
This commit is contained in:
@@ -16,6 +16,7 @@ import { Button } from '../Button'
|
||||
import * as PopupList from '../Popup/PopupButtonList'
|
||||
import './index.scss'
|
||||
import { useRouter } from 'next/navigation'
|
||||
import { Translation } from '../Translation'
|
||||
|
||||
const baseClass = 'delete-document'
|
||||
|
||||
@@ -112,18 +113,17 @@ const DeleteDocument: React.FC<Props> = (props) => {
|
||||
<MinimalTemplate className={`${baseClass}__template`}>
|
||||
<h1>{t('general:confirmDeletion')}</h1>
|
||||
<p>
|
||||
{t('general:aboutToDelete', {
|
||||
label: getTranslation(singularLabel, i18n),
|
||||
title: titleToRender,
|
||||
})}
|
||||
{/* <Trans
|
||||
i18nKey="aboutToDelete"
|
||||
<Translation
|
||||
t={t}
|
||||
values={{ label: getTranslation(singularLabel, i18n), title: titleToRender }}
|
||||
>
|
||||
aboutToDelete
|
||||
<strong>{titleToRender}</strong>
|
||||
</Trans> */}
|
||||
i18nKey="general:aboutToDelete"
|
||||
variables={{
|
||||
label: getTranslation(singularLabel, i18n),
|
||||
title: titleToRender,
|
||||
}}
|
||||
elements={{
|
||||
'1': ({ children }) => <strong children={children} />,
|
||||
}}
|
||||
/>
|
||||
</p>
|
||||
<div className={`${baseClass}__actions`}>
|
||||
<Button
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { useTranslation } from '../../providers/Translation'
|
||||
import { Button } from '../Button'
|
||||
|
||||
import './index.scss'
|
||||
@@ -22,7 +22,7 @@ export const Dropzone: React.FC<Props> = ({ onChange, className, mimeTypes }) =>
|
||||
const [dragging, setDragging] = React.useState(false)
|
||||
const inputRef = React.useRef(null)
|
||||
|
||||
const { t } = useTranslation(['upload', 'general'])
|
||||
const { t } = useTranslation()
|
||||
|
||||
const handlePaste = React.useCallback(
|
||||
(e: ClipboardEvent) => {
|
||||
@@ -107,7 +107,7 @@ export const Dropzone: React.FC<Props> = ({ onChange, className, mimeTypes }) =>
|
||||
}}
|
||||
className={`${baseClass}__file-button`}
|
||||
>
|
||||
{t('selectFile')}
|
||||
{t('upload:selectFile')}
|
||||
</Button>
|
||||
|
||||
<input
|
||||
@@ -119,7 +119,7 @@ export const Dropzone: React.FC<Props> = ({ onChange, className, mimeTypes }) =>
|
||||
/>
|
||||
|
||||
<p className={`${baseClass}__label`}>
|
||||
{t('general:or')} {t('dragAndDrop')}
|
||||
{t('general:or')} {t('upload:dragAndDrop')}
|
||||
</p>
|
||||
</div>
|
||||
)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { useModal } from '@faceless-ui/modal'
|
||||
import React, { useRef, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { useTranslation } from '../../providers/Translation'
|
||||
import ReactCrop, { type Crop as CropType } from 'react-image-crop'
|
||||
import 'react-image-crop/dist/ReactCrop.css'
|
||||
|
||||
@@ -34,7 +34,7 @@ export const EditUpload: React.FC<{
|
||||
showFocalPoint?: boolean
|
||||
}> = ({ fileName, fileSrc, imageCacheTag, showCrop, showFocalPoint }) => {
|
||||
const { closeModal } = useModal()
|
||||
const { t } = useTranslation(['general', 'upload'])
|
||||
const { t } = useTranslation()
|
||||
const { formQueryParams, setFormQueryParams } = useFormQueryParams()
|
||||
const { uploadEdits } = formQueryParams || {}
|
||||
const [crop, setCrop] = useState<CropType>({
|
||||
@@ -117,7 +117,7 @@ export const EditUpload: React.FC<{
|
||||
</h2>
|
||||
<div className={`${baseClass}__actions`}>
|
||||
<Button
|
||||
aria-label={t('cancel')}
|
||||
aria-label={t('general:cancel')}
|
||||
buttonStyle="secondary"
|
||||
className={`${baseClass}__cancel`}
|
||||
onClick={() => closeModal(editDrawerSlug)}
|
||||
|
||||
@@ -9,6 +9,7 @@ import { MinimalTemplate } from '../../templates/Minimal'
|
||||
import { useDocumentInfo } from '../../providers/DocumentInfo'
|
||||
import { Button } from '../Button'
|
||||
import './index.scss'
|
||||
import { Translation } from '../Translation'
|
||||
|
||||
const baseClass = 'generate-confirmation'
|
||||
|
||||
@@ -43,11 +44,13 @@ const GenerateConfirmation: React.FC<Props> = (props) => {
|
||||
<MinimalTemplate className={`${baseClass}__template`}>
|
||||
<h1>{t('authentication:confirmGeneration')}</h1>
|
||||
<p>
|
||||
<strong>{t('authentication:generatingNewAPIKeyWillInvalidate')}</strong>
|
||||
{/* <Trans i18nKey="generatingNewAPIKeyWillInvalidate" t={t}>
|
||||
generatingNewAPIKeyWillInvalidate
|
||||
<strong>invalidate</strong>
|
||||
</Trans> */}
|
||||
<Translation
|
||||
t={t}
|
||||
i18nKey="authentication:generatingNewAPIKeyWillInvalidate"
|
||||
elements={{
|
||||
1: ({ children }) => <strong children={children} />,
|
||||
}}
|
||||
/>
|
||||
</p>
|
||||
|
||||
<Button
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Modal, useModal } from '@faceless-ui/modal'
|
||||
import React from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { useTranslation } from '../../providers/Translation'
|
||||
import { useHistory } from 'react-router-dom'
|
||||
|
||||
import type { Props } from './types'
|
||||
@@ -22,14 +22,14 @@ const StayLoggedInModal: React.FC<Props> = (props) => {
|
||||
routes: { admin },
|
||||
} = config
|
||||
const { toggleModal } = useModal()
|
||||
const { t } = useTranslation('authentication')
|
||||
const { t } = useTranslation()
|
||||
|
||||
return (
|
||||
<Modal className={baseClass} slug="stay-logged-in">
|
||||
<div className={`${baseClass}__wrapper`}>
|
||||
<div className={`${baseClass}__content`}>
|
||||
<h1>{t('stayLoggedIn')}</h1>
|
||||
<p>{t('youAreInactive')}</p>
|
||||
<h1>{t('authentication:stayLoggedIn')}</h1>
|
||||
<p>{t('authentication:youAreInactive')}</p>
|
||||
</div>
|
||||
<div className={`${baseClass}__controls`}>
|
||||
<Button
|
||||
@@ -39,7 +39,7 @@ const StayLoggedInModal: React.FC<Props> = (props) => {
|
||||
history.push(`${admin}${logoutRoute}`)
|
||||
}}
|
||||
>
|
||||
{t('logOut')}
|
||||
{t('authentication:logOut')}
|
||||
</Button>
|
||||
<Button
|
||||
onClick={() => {
|
||||
@@ -47,7 +47,7 @@ const StayLoggedInModal: React.FC<Props> = (props) => {
|
||||
toggleModal(modalSlug)
|
||||
}}
|
||||
>
|
||||
{t('stayLoggedIn')}
|
||||
{t('authentication:stayLoggedIn')}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
44
packages/ui/src/elements/Translation/index.tsx
Normal file
44
packages/ui/src/elements/Translation/index.tsx
Normal file
@@ -0,0 +1,44 @@
|
||||
import * as React from 'react'
|
||||
import { TFunction } from '@payloadcms/translations'
|
||||
|
||||
const RecursiveTranslation: React.FC<{
|
||||
translationString: string
|
||||
elements?: Record<string, React.FC<{ children: React.ReactNode }>>
|
||||
}> = ({ translationString, elements }) => {
|
||||
const regex = /(<[^>]+>.*?<\/[^>]+>)/g
|
||||
const sections = translationString.split(regex)
|
||||
|
||||
return (
|
||||
<span>
|
||||
{sections.map((section, index) => {
|
||||
const Element = elements?.[index.toString()]
|
||||
if (Element) {
|
||||
const regex = new RegExp(`<${index}>(.*?)<\/${index}>`, 'g')
|
||||
const children = section.replace(regex, (_, group) => group)
|
||||
return (
|
||||
<Element>
|
||||
<RecursiveTranslation translationString={children} />
|
||||
</Element>
|
||||
)
|
||||
}
|
||||
return section
|
||||
})}
|
||||
</span>
|
||||
)
|
||||
}
|
||||
|
||||
type TranslationProps = {
|
||||
i18nKey: string
|
||||
variables?: Record<string, unknown>
|
||||
elements?: Record<string, React.FC<{ children: React.ReactNode }>>
|
||||
t: TFunction
|
||||
}
|
||||
export const Translation: React.FC<TranslationProps> = ({ elements, variables, i18nKey, t }) => {
|
||||
let stringWithVariables = t(i18nKey, variables || {})
|
||||
|
||||
if (!elements) {
|
||||
return stringWithVariables
|
||||
}
|
||||
|
||||
return <RecursiveTranslation translationString={stringWithVariables} elements={elements} />
|
||||
}
|
||||
@@ -32,4 +32,6 @@ export { useListDrawer } from '../elements/ListDrawer'
|
||||
export { useDocumentDrawer } from '../elements/DocumentDrawer'
|
||||
export { ShimmerEffect } from '../elements/ShimmerEffect'
|
||||
export { useDrawerSlug } from '../elements/Drawer/useDrawerSlug'
|
||||
export { default as Popup } from '../elements/Popup'
|
||||
// export { useThumbnail } from '../elements/Upload'
|
||||
export { Translation } from '../elements/Translation'
|
||||
|
||||
@@ -3,7 +3,7 @@ import type { SanitizedCollectionConfig, SanitizedGlobalConfig } from 'payload/t
|
||||
|
||||
import { useFormFields } from '../forms/Form/context'
|
||||
import { formatDocTitle } from '../utilities/formatDocTitle'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { useTranslation } from '../providers/Translation'
|
||||
import { getTranslation } from '@payloadcms/translations'
|
||||
|
||||
const useTitle = (args: {
|
||||
|
||||
@@ -11,15 +11,15 @@ export type LanguageOptions = {
|
||||
}[]
|
||||
|
||||
const Context = createContext<{
|
||||
t: (key: string, vars?: Record<string, string | number>) => string
|
||||
t: (key: string, vars?: Record<string, any>) => string
|
||||
i18n: I18n
|
||||
languageOptions: LanguageOptions
|
||||
}>({
|
||||
t: () => '',
|
||||
t: (key) => key,
|
||||
i18n: {
|
||||
language: 'en',
|
||||
fallbackLanguage: 'en',
|
||||
t: () => '',
|
||||
t: (key) => key,
|
||||
},
|
||||
languageOptions: undefined,
|
||||
})
|
||||
@@ -36,7 +36,7 @@ export const TranslationProvider: React.FC<{
|
||||
fallbackLang: ClientConfig['i18n']['fallbackLanguage']
|
||||
languageOptions: LanguageOptions
|
||||
}> = ({ children, translations, lang, fallbackLang, languageOptions }) => {
|
||||
const nextT = (key: string, vars?: Record<string, string | number>): string =>
|
||||
const nextT = (key: string, vars?: Record<string, any>): string =>
|
||||
t({
|
||||
key,
|
||||
vars,
|
||||
|
||||
@@ -13,7 +13,7 @@ jest.mock('../../../../utilities/Config', () => ({
|
||||
useConfig: () => ({ admin: { dateFormat: 'MMMM do yyyy, h:mm a' } }),
|
||||
}))
|
||||
|
||||
jest.mock('react-i18next', () => ({
|
||||
jest.mock('../../../../providers/Translation', () => ({
|
||||
useTranslation: () => ({ t: (string) => string }),
|
||||
}))
|
||||
|
||||
|
||||
Reference in New Issue
Block a user