Skip to content

Commit

Permalink
feat(core): Added og:locale and og:locale:alternate to static site ge…
Browse files Browse the repository at this point in the history
…neration
  • Loading branch information
NotHr committed Apr 17, 2023
1 parent d1614e5 commit 66c89bd
Showing 1 changed file with 97 additions and 96 deletions.
193 changes: 97 additions & 96 deletions packages/docusaurus-theme-classic/src/theme/SiteMetadata/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,127 +5,128 @@
* LICENSE file in the root directory of this source tree.
*/

import React from "react";
import Head from "@docusaurus/Head";
import useDocusaurusContext from "@docusaurus/useDocusaurusContext";
import useBaseUrl from "@docusaurus/useBaseUrl";
import { PageMetadata, useThemeConfig } from "@docusaurus/theme-common";
import React from 'react';
import Head from '@docusaurus/Head';
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
import useBaseUrl from '@docusaurus/useBaseUrl';
import {PageMetadata, useThemeConfig} from '@docusaurus/theme-common';
import {
DEFAULT_SEARCH_TAG,
useAlternatePageUtils,
keyboardFocusedClassName,
} from "@docusaurus/theme-common/internal";
import { useLocation } from "@docusaurus/router";
import SearchMetadata from "@theme/SearchMetadata";
DEFAULT_SEARCH_TAG,
useAlternatePageUtils,
keyboardFocusedClassName,
} from '@docusaurus/theme-common/internal';
import {useLocation} from '@docusaurus/router';
import SearchMetadata from '@theme/SearchMetadata';

// TODO move to SiteMetadataDefaults or theme-common ?
// Useful for i18n/SEO
// See https://developers.google.com/search/docs/advanced/crawling/localized-versions
// See https://github.com/facebook/docusaurus/issues/3317
function AlternateLangHeaders(): JSX.Element {
const {
i18n: { defaultLocale, localeConfigs },
} = useDocusaurusContext();
const alternatePageUtils = useAlternatePageUtils();

// Note: it is fine to use both "x-default" and "en" to target the same url
// See https://www.searchviu.com/en/multiple-hreflang-tags-one-url/
return (
<Head>
{Object.entries(localeConfigs).map(([locale, { htmlLang }]) => (
<link
key={locale}
rel="alternate"
href={alternatePageUtils.createUrl({
locale,
fullyQualified: true,
})}
hrefLang={htmlLang}
/>
))}
{Object.entries(localeConfigs).map(([locale]) => (
<meta property="og:locale:alternate" content={locale} />
))}

<meta property="og:locale" content={defaultLocale} />

<link
rel="alternate"
href={alternatePageUtils.createUrl({
locale: defaultLocale,
fullyQualified: true,
})}
hrefLang="x-default"
/>
</Head>
);
const {
i18n: {defaultLocale, localeConfigs},
} = useDocusaurusContext();
const alternatePageUtils = useAlternatePageUtils();

// Note: it is fine to use both "x-default" and "en" to target the same url
// See https://www.searchviu.com/en/multiple-hreflang-tags-one-url/
return (
<Head>
{Object.entries(localeConfigs).map(([locale, {htmlLang}]) => (
<>
<link
key={locale}
rel="alternate"
href={alternatePageUtils.createUrl({
locale,
fullyQualified: true,
})}
hrefLang={htmlLang}
/>

<meta property="og:locale:alternate" content={locale} />
</>
))}

<meta property="og:locale" content={defaultLocale} />

<link
rel="alternate"
href={alternatePageUtils.createUrl({
locale: defaultLocale,
fullyQualified: true,
})}
hrefLang="x-default"
/>
</Head>
);
}

// Default canonical url inferred from current page location pathname
function useDefaultCanonicalUrl() {
const {
siteConfig: { url: siteUrl },
} = useDocusaurusContext();
const { pathname } = useLocation();
return siteUrl + useBaseUrl(pathname);
const {
siteConfig: {url: siteUrl},
} = useDocusaurusContext();
const {pathname} = useLocation();
return siteUrl + useBaseUrl(pathname);
}

// TODO move to SiteMetadataDefaults or theme-common ?
function CanonicalUrlHeaders({ permalink }: { permalink?: string }) {
const {
siteConfig: { url: siteUrl },
} = useDocusaurusContext();
const defaultCanonicalUrl = useDefaultCanonicalUrl();

const canonicalUrl = permalink
? `${siteUrl}${permalink}`
: defaultCanonicalUrl;
return (
<Head>
<meta property="og:url" content={canonicalUrl} />
<link rel="canonical" href={canonicalUrl} />
</Head>
);
function CanonicalUrlHeaders({permalink}: {permalink?: string}) {
const {
siteConfig: {url: siteUrl},
} = useDocusaurusContext();
const defaultCanonicalUrl = useDefaultCanonicalUrl();

const canonicalUrl = permalink
? `${siteUrl}${permalink}`
: defaultCanonicalUrl;
return (
<Head>
<meta property="og:url" content={canonicalUrl} />
<link rel="canonical" href={canonicalUrl} />
</Head>
);
}

export default function SiteMetadata(): JSX.Element {
const {
i18n: { currentLocale },
} = useDocusaurusContext();

// TODO maybe move these 2 themeConfig to siteConfig?
// These seems useful for other themes as well
const { metadata, image: defaultImage } = useThemeConfig();

return (
<>
<Head>
<meta name="twitter:card" content="summary_large_image" />
{/* The keyboard focus class name need to be applied when SSR so links
const {
i18n: {currentLocale},
} = useDocusaurusContext();

// TODO maybe move these 2 themeConfig to siteConfig?
// These seems useful for other themes as well
const {metadata, image: defaultImage} = useThemeConfig();

return (
<>
<Head>
<meta name="twitter:card" content="summary_large_image" />
{/* The keyboard focus class name need to be applied when SSR so links
are outlined when JS is disabled */}
<body className={keyboardFocusedClassName} />
</Head>
<body className={keyboardFocusedClassName} />
</Head>

{defaultImage && <PageMetadata image={defaultImage} />}
{defaultImage && <PageMetadata image={defaultImage} />}

<CanonicalUrlHeaders />
<CanonicalUrlHeaders />

<AlternateLangHeaders />
<AlternateLangHeaders />

<SearchMetadata tag={DEFAULT_SEARCH_TAG} locale={currentLocale} />
<SearchMetadata tag={DEFAULT_SEARCH_TAG} locale={currentLocale} />

{/*
{/*
It's important to have an additional <Head> element here, as it allows
react-helmet to override default metadata values set in previous <Head>
like "twitter:card". In same Head, the same meta would appear twice
instead of overriding.
*/}
<Head>
{/* Yes, "metadatum" is the grammatically correct term */}
{metadata.map((metadatum, i) => (
<meta key={i} {...metadatum} />
))}
</Head>
</>
);
}
<Head>
{/* Yes, "metadatum" is the grammatically correct term */}
{metadata.map((metadatum, i) => (
<meta key={i} {...metadatum} />
))}
</Head>
</>
);
}

0 comments on commit 66c89bd

Please sign in to comment.