47 行
1.6 KiB
TypeScript
47 行
1.6 KiB
TypeScript
import { Helmet } from 'react-helmet-async'
|
|
import { useLocation } from 'react-router-dom'
|
|
|
|
import { useLocale } from '@/lib/useLocale'
|
|
import { useUITranslation } from '@/lib/useUITranslation'
|
|
import { currentRenderContext } from '@/lib/renderContext'
|
|
|
|
import type { ReactNode } from 'react'
|
|
|
|
type LocalisedTitle = { text: string; language: string }
|
|
type Props = {
|
|
title?: string | LocalisedTitle
|
|
includeSiteName?: boolean
|
|
description?: LocalisedTitle
|
|
canonical?: string
|
|
children?: ReactNode }
|
|
|
|
|
|
const PageHead = (
|
|
{ title, includeSiteName = true, description: pageDescription, canonical, children }: Props,
|
|
) => {
|
|
const locale = useLocale ()
|
|
const location = useLocation ()
|
|
const origin = currentRenderContext ()?.origin
|
|
const pageCanonical = canonical ?? (origin == null
|
|
? undefined : new URL (location.pathname + location.search, origin).href)
|
|
const { message, siteTitle } = useUITranslation ('shared')
|
|
const pageTitle = typeof title === 'string' ? { text: title, language: locale } : title
|
|
const fullTitle =
|
|
pageTitle == null
|
|
? siteTitle.text
|
|
: (includeSiteName ? `${pageTitle.text} | ${siteTitle.text}` : pageTitle.text)
|
|
const description = pageDescription ?? pageTitle
|
|
?? message ('head.description', { brand: siteTitle.text })
|
|
|
|
return (
|
|
<Helmet>
|
|
<title lang={pageTitle?.language ?? siteTitle.language}>{fullTitle}</title>
|
|
<meta name="description" content={description.text} lang={description.language}/>
|
|
{pageCanonical != null && <link rel="canonical" href={pageCanonical}/>}
|
|
{children}
|
|
</Helmet>)
|
|
}
|
|
|
|
|
|
export default PageHead
|