mirror of
https://github.com/facebook/docusaurus.git
synced 2025-06-07 05:12:31 +02:00
feat(v2): Extract/translate hardcoded labels from classic theme (#4168)
* Translate theme hardcoded strings * improve test
This commit is contained in:
parent
823d0fe3c2
commit
ab7951571e
17 changed files with 217 additions and 60 deletions
|
@ -7,6 +7,7 @@
|
|||
|
||||
import React from 'react';
|
||||
import Link from '@docusaurus/Link';
|
||||
import Translate from '@docusaurus/Translate';
|
||||
import type {Metadata} from '@theme/BlogListPage';
|
||||
|
||||
function BlogListPaginator(props: {readonly metadata: Metadata}): JSX.Element {
|
||||
|
@ -18,14 +19,28 @@ function BlogListPaginator(props: {readonly metadata: Metadata}): JSX.Element {
|
|||
<div className="pagination-nav__item">
|
||||
{previousPage && (
|
||||
<Link className="pagination-nav__link" to={previousPage}>
|
||||
<div className="pagination-nav__label">« Newer Entries</div>
|
||||
<div className="pagination-nav__label">
|
||||
«{' '}
|
||||
<Translate
|
||||
id="theme.BlogListPaginator.newerEntries"
|
||||
description="The label used to navigate to the newer blog posts page (previous page)">
|
||||
Newer Entries
|
||||
</Translate>
|
||||
</div>
|
||||
</Link>
|
||||
)}
|
||||
</div>
|
||||
<div className="pagination-nav__item pagination-nav__item--next">
|
||||
{nextPage && (
|
||||
<Link className="pagination-nav__link" to={nextPage}>
|
||||
<div className="pagination-nav__label">Older Entries »</div>
|
||||
<div className="pagination-nav__label">
|
||||
<Translate
|
||||
id="theme.BlogListPaginator.olderEntries"
|
||||
description="The label used to navigate to the older blog posts page (next page)">
|
||||
Older Entries
|
||||
</Translate>{' '}
|
||||
»
|
||||
</div>
|
||||
</Link>
|
||||
)}
|
||||
</div>
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
import React from 'react';
|
||||
import clsx from 'clsx';
|
||||
import {MDXProvider} from '@mdx-js/react';
|
||||
|
||||
import Translate from '@docusaurus/Translate';
|
||||
import Head from '@docusaurus/Head';
|
||||
import Link from '@docusaurus/Link';
|
||||
import MDXComponents from '@theme/MDXComponents';
|
||||
|
@ -133,7 +133,13 @@ function BlogPostItem(props: Props): JSX.Element {
|
|||
<Link
|
||||
to={metadata.permalink}
|
||||
aria-label={`Read more about ${title}`}>
|
||||
<strong>Read More</strong>
|
||||
<strong>
|
||||
<Translate
|
||||
id="theme.BlogPostItem.readMore"
|
||||
description="The label used in blog post item excerps to link to full blog posts">
|
||||
Read More
|
||||
</Translate>
|
||||
</strong>
|
||||
</Link>
|
||||
</div>
|
||||
)}
|
||||
|
|
|
@ -6,14 +6,13 @@
|
|||
*/
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import Layout from '@theme/Layout';
|
||||
import BlogPostItem from '@theme/BlogPostItem';
|
||||
import BlogPostPaginator from '@theme/BlogPostPaginator';
|
||||
import type {Props} from '@theme/BlogPostPage';
|
||||
import BlogSidebar from '@theme/BlogSidebar';
|
||||
import TOC from '@theme/TOC';
|
||||
import IconEdit from '@theme/IconEdit';
|
||||
import EditThisPage from '@theme/EditThisPage';
|
||||
|
||||
function BlogPostPage(props: Props): JSX.Element {
|
||||
const {content: BlogPostContents, sidebar} = props;
|
||||
|
@ -39,14 +38,7 @@ function BlogPostPage(props: Props): JSX.Element {
|
|||
isBlogPostPage>
|
||||
<BlogPostContents />
|
||||
</BlogPostItem>
|
||||
<div>
|
||||
{editUrl && (
|
||||
<a href={editUrl} target="_blank" rel="noreferrer noopener">
|
||||
<IconEdit />
|
||||
Edit this page
|
||||
</a>
|
||||
)}
|
||||
</div>
|
||||
<div>{editUrl && <EditThisPage editUrl={editUrl} />}</div>
|
||||
{(nextItem || prevItem) && (
|
||||
<div className="margin-vert--xl">
|
||||
<BlogPostPaginator nextItem={nextItem} prevItem={prevItem} />
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
*/
|
||||
|
||||
import React from 'react';
|
||||
import Translate from '@docusaurus/Translate';
|
||||
import Link from '@docusaurus/Link';
|
||||
import type {Props} from '@theme/BlogPostPaginator';
|
||||
|
||||
|
@ -17,7 +18,13 @@ function BlogPostPaginator(props: Props): JSX.Element {
|
|||
<div className="pagination-nav__item">
|
||||
{prevItem && (
|
||||
<Link className="pagination-nav__link" to={prevItem.permalink}>
|
||||
<div className="pagination-nav__sublabel">Newer Post</div>
|
||||
<div className="pagination-nav__sublabel">
|
||||
<Translate
|
||||
id="theme.BlogPostPaginator.newerPost"
|
||||
description="The blog post button label to navigate to the newer/previous post">
|
||||
Newer Post
|
||||
</Translate>
|
||||
</div>
|
||||
<div className="pagination-nav__label">
|
||||
« {prevItem.title}
|
||||
</div>
|
||||
|
@ -27,7 +34,13 @@ function BlogPostPaginator(props: Props): JSX.Element {
|
|||
<div className="pagination-nav__item pagination-nav__item--next">
|
||||
{nextItem && (
|
||||
<Link className="pagination-nav__link" to={nextItem.permalink}>
|
||||
<div className="pagination-nav__sublabel">Older Post</div>
|
||||
<div className="pagination-nav__sublabel">
|
||||
<Translate
|
||||
id="theme.BlogPostPaginator.olderPost"
|
||||
description="The blog post button label to navigate to the older/next post">
|
||||
Older Post
|
||||
</Translate>
|
||||
</div>
|
||||
<div className="pagination-nav__label">
|
||||
{nextItem.title} »
|
||||
</div>
|
||||
|
|
|
@ -49,6 +49,7 @@ function BlogTagsListPage(props: Props): JSX.Element {
|
|||
))
|
||||
.filter((item) => item != null);
|
||||
|
||||
// TODO soon: translate hardcoded labels, but factorize them (blog + docs will both have tags)
|
||||
return (
|
||||
<Layout
|
||||
title="Tags"
|
||||
|
|
|
@ -21,6 +21,7 @@ function BlogTagsPostPage(props: Props): JSX.Element {
|
|||
const {metadata, items, sidebar} = props;
|
||||
const {allTagsPath, name: tagName, count} = metadata;
|
||||
|
||||
// TODO soon: translate hardcoded labels, but factorize them (blog + docs will both have tags)
|
||||
return (
|
||||
<Layout
|
||||
title={`Posts tagged "${tagName}"`}
|
||||
|
|
|
@ -12,6 +12,7 @@ import copy from 'copy-text-to-clipboard';
|
|||
import rangeParser from 'parse-numeric-range';
|
||||
import usePrismTheme from '@theme/hooks/usePrismTheme';
|
||||
import type {Props} from '@theme/CodeBlock';
|
||||
import Translate from '@docusaurus/Translate';
|
||||
|
||||
import styles from './styles.module.css';
|
||||
import {useThemeConfig} from '@docusaurus/theme-common';
|
||||
|
@ -86,11 +87,11 @@ const highlightDirectiveRegex = (lang) => {
|
|||
};
|
||||
const codeBlockTitleRegex = /(?:title=")(.*)(?:")/;
|
||||
|
||||
export default ({
|
||||
export default function CodeBlock({
|
||||
children,
|
||||
className: languageClassName,
|
||||
metastring,
|
||||
}: Props): JSX.Element => {
|
||||
}: Props): JSX.Element {
|
||||
const {prism} = useThemeConfig();
|
||||
|
||||
const [showCopied, setShowCopied] = useState(false);
|
||||
|
@ -242,11 +243,23 @@ export default ({
|
|||
aria-label="Copy code to clipboard"
|
||||
className={clsx(styles.copyButton)}
|
||||
onClick={handleCopyCode}>
|
||||
{showCopied ? 'Copied' : 'Copy'}
|
||||
{showCopied ? (
|
||||
<Translate
|
||||
id="theme.CodeBlock.copied"
|
||||
description="The copied button label on code blocks">
|
||||
Copied
|
||||
</Translate>
|
||||
) : (
|
||||
<Translate
|
||||
id="theme.CodeBlock.copy"
|
||||
description="The copy button label on code blocks">
|
||||
Copy
|
||||
</Translate>
|
||||
)}
|
||||
</button>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</Highlight>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
*/
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import Head from '@docusaurus/Head';
|
||||
import {useTitleFormatter} from '@docusaurus/theme-common';
|
||||
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
|
||||
|
@ -15,7 +14,7 @@ import DocPaginator from '@theme/DocPaginator';
|
|||
import DocVersionSuggestions from '@theme/DocVersionSuggestions';
|
||||
import type {Props} from '@theme/DocItem';
|
||||
import TOC from '@theme/TOC';
|
||||
import IconEdit from '@theme/IconEdit';
|
||||
import EditThisPage from '@theme/EditThisPage';
|
||||
|
||||
import clsx from 'clsx';
|
||||
import styles from './styles.module.css';
|
||||
|
@ -107,15 +106,7 @@ function DocItem(props: Props): JSX.Element {
|
|||
<div className="margin-vert--xl">
|
||||
<div className="row">
|
||||
<div className="col">
|
||||
{editUrl && (
|
||||
<a
|
||||
href={editUrl}
|
||||
target="_blank"
|
||||
rel="noreferrer noopener">
|
||||
<IconEdit />
|
||||
Edit this page
|
||||
</a>
|
||||
)}
|
||||
{editUrl && <EditThisPage editUrl={editUrl} />}
|
||||
</div>
|
||||
{(lastUpdatedAt || lastUpdatedBy) && (
|
||||
<div className="col text--right">
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
import React from 'react';
|
||||
import Link from '@docusaurus/Link';
|
||||
import Translate from '@docusaurus/Translate';
|
||||
import type {Props} from '@theme/DocPaginator';
|
||||
|
||||
function DocPaginator(props: Props): JSX.Element {
|
||||
|
@ -19,7 +20,13 @@ function DocPaginator(props: Props): JSX.Element {
|
|||
<Link
|
||||
className="pagination-nav__link"
|
||||
to={metadata.previous.permalink}>
|
||||
<div className="pagination-nav__sublabel">Previous</div>
|
||||
<div className="pagination-nav__sublabel">
|
||||
<Translate
|
||||
id="theme.DocPaginator.previous"
|
||||
description="The label used to navigate to the previous doc">
|
||||
Previous
|
||||
</Translate>
|
||||
</div>
|
||||
<div className="pagination-nav__label">
|
||||
« {metadata.previous.title}
|
||||
</div>
|
||||
|
@ -29,7 +36,13 @@ function DocPaginator(props: Props): JSX.Element {
|
|||
<div className="pagination-nav__item pagination-nav__item--next">
|
||||
{metadata.next && (
|
||||
<Link className="pagination-nav__link" to={metadata.next.permalink}>
|
||||
<div className="pagination-nav__sublabel">Next</div>
|
||||
<div className="pagination-nav__sublabel">
|
||||
<Translate
|
||||
id="theme.DocPaginator.next"
|
||||
description="The label used to navigate to the next doc">
|
||||
Next
|
||||
</Translate>
|
||||
</div>
|
||||
<div className="pagination-nav__label">
|
||||
{metadata.next.title} »
|
||||
</div>
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import Translate from '@docusaurus/Translate';
|
||||
|
||||
import type {Props} from '@theme/EditThisPage';
|
||||
import IconEdit from '@theme/IconEdit';
|
||||
|
||||
export default function EditThisPage({editUrl}: Props): JSX.Element {
|
||||
return (
|
||||
<a href={editUrl} target="_blank" rel="noreferrer noopener">
|
||||
<IconEdit />
|
||||
<Translate
|
||||
id="theme.EditThisPage.editThisPage"
|
||||
description="The link label to edit the current page">
|
||||
Edit this page
|
||||
</Translate>
|
||||
</a>
|
||||
);
|
||||
}
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
import React from 'react';
|
||||
import Layout from '@theme/Layout';
|
||||
import Translate from '@docusaurus/Translate';
|
||||
|
||||
function NotFound(): JSX.Element {
|
||||
return (
|
||||
|
@ -14,11 +15,27 @@ function NotFound(): JSX.Element {
|
|||
<main className="container margin-vert--xl">
|
||||
<div className="row">
|
||||
<div className="col col--6 col--offset-3">
|
||||
<h1 className="hero__title">Page Not Found</h1>
|
||||
<p>We could not find what you were looking for.</p>
|
||||
<h1 className="hero__title">
|
||||
<Translate
|
||||
id="theme.NotFound.title"
|
||||
description="The title of the 404 page">
|
||||
Page Not Found
|
||||
</Translate>
|
||||
</h1>
|
||||
<p>
|
||||
Please contact the owner of the site that linked you to the
|
||||
original URL and let them know their link is broken.
|
||||
<Translate
|
||||
id="theme.NotFound.p1"
|
||||
description="The first paragraph of the 404 page">
|
||||
We could not find what you were looking for.
|
||||
</Translate>
|
||||
</p>
|
||||
<p>
|
||||
<Translate
|
||||
id="theme.NotFound.p2"
|
||||
description="The 2nd paragraph of the 404 page">
|
||||
Please contact the owner of the site that linked you to the
|
||||
original URL and let them know their link is broken.
|
||||
</Translate>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -6,8 +6,8 @@
|
|||
*/
|
||||
|
||||
import React, {useRef, useEffect} from 'react';
|
||||
import Translate from '@docusaurus/Translate';
|
||||
import {useLocation} from '@docusaurus/router';
|
||||
|
||||
import styles from './styles.module.css';
|
||||
|
||||
function programmaticFocus(el) {
|
||||
|
@ -39,7 +39,11 @@ function SkipToContent(): JSX.Element {
|
|||
return (
|
||||
<div ref={containerRef}>
|
||||
<a href="#main" className={styles.skipToContent} onClick={handleSkip}>
|
||||
Skip to main content
|
||||
<Translate
|
||||
id="theme.SkipToContent.skipToMainContent"
|
||||
description="The skip to content label used for accessibility, allowing to rapidly navigate to main content with keyboard tab/enter navigation">
|
||||
Skip to main content
|
||||
</Translate>
|
||||
</a>
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -92,6 +92,14 @@ declare module '@theme/DocVersionSuggestions' {
|
|||
export default DocVersionSuggestions;
|
||||
}
|
||||
|
||||
declare module '@theme/EditThisPage' {
|
||||
export type Props = {
|
||||
readonly editUrl: string;
|
||||
};
|
||||
const EditThisPage: (props: Props) => JSX.Element;
|
||||
export default EditThisPage;
|
||||
}
|
||||
|
||||
declare module '@theme/Footer' {
|
||||
const Footer: () => JSX.Element | null;
|
||||
export default Footer;
|
||||
|
|
|
@ -8,10 +8,11 @@
|
|||
import * as React from 'react';
|
||||
import {LiveProvider, LiveEditor, LiveError, LivePreview} from 'react-live';
|
||||
import clsx from 'clsx';
|
||||
import Translate from '@docusaurus/Translate';
|
||||
|
||||
import styles from './styles.module.css';
|
||||
|
||||
function Playground({children, theme, transformCode, ...props}) {
|
||||
export default function Playground({children, theme, transformCode, ...props}) {
|
||||
return (
|
||||
<LiveProvider
|
||||
code={children.replace(/\n$/, '')}
|
||||
|
@ -23,7 +24,11 @@ function Playground({children, theme, transformCode, ...props}) {
|
|||
styles.playgroundHeader,
|
||||
styles.playgroundEditorHeader,
|
||||
)}>
|
||||
Live Editor
|
||||
<Translate
|
||||
id="theme.Playground.liveEditor"
|
||||
description="The live editor label of the live codeblocks">
|
||||
Live Editor
|
||||
</Translate>
|
||||
</div>
|
||||
<LiveEditor className={styles.playgroundEditor} />
|
||||
<div
|
||||
|
@ -31,7 +36,11 @@ function Playground({children, theme, transformCode, ...props}) {
|
|||
styles.playgroundHeader,
|
||||
styles.playgroundPreviewHeader,
|
||||
)}>
|
||||
Result
|
||||
<Translate
|
||||
id="theme.Playground.result"
|
||||
description="The result label of the live codeblocks">
|
||||
Result
|
||||
</Translate>
|
||||
</div>
|
||||
<div className={styles.playgroundPreview}>
|
||||
<LivePreview />
|
||||
|
@ -40,5 +49,3 @@ function Playground({children, theme, transformCode, ...props}) {
|
|||
</LiveProvider>
|
||||
);
|
||||
}
|
||||
|
||||
export default Playground;
|
||||
|
|
|
@ -238,21 +238,54 @@ describe('extractPluginsSourceCodeTranslations', () => {
|
|||
return {
|
||||
name: 'abc',
|
||||
getPathsToWatch() {
|
||||
return [path.join(pluginDir, '**/*.{js,jsx,ts,tsx}')];
|
||||
return [path.join(pluginDir, 'subpath', '**/*.{js,jsx,ts,tsx}')];
|
||||
},
|
||||
getThemePath() {
|
||||
return path.join(pluginDir, 'src', 'theme');
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
const plugin1Dir = await createTmpDir();
|
||||
const plugin1File = path.join(plugin1Dir, 'file.jsx');
|
||||
await fs.ensureDir(path.dirname(plugin1File));
|
||||
const plugin1File1 = path.join(plugin1Dir, 'subpath', 'file1.jsx');
|
||||
await fs.ensureDir(path.dirname(plugin1File1));
|
||||
await fs.writeFile(
|
||||
plugin1File,
|
||||
plugin1File1,
|
||||
`
|
||||
export default function MyComponent() {
|
||||
return (
|
||||
<div>
|
||||
<input text={translate({id: 'plugin1Id',message: 'plugin1 message',description: 'plugin1 description'})}/>
|
||||
<input text={translate({id: 'plugin1Id1',message: 'plugin1 message 1',description: 'plugin1 description 1'})}/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
`,
|
||||
);
|
||||
const plugin1File2 = path.join(plugin1Dir, 'src', 'theme', 'file2.jsx');
|
||||
await fs.ensureDir(path.dirname(plugin1File2));
|
||||
await fs.writeFile(
|
||||
plugin1File2,
|
||||
`
|
||||
export default function MyComponent() {
|
||||
return (
|
||||
<div>
|
||||
<input text={translate({id: 'plugin1Id2',message: 'plugin1 message 2',description: 'plugin1 description 2'})}/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
`,
|
||||
);
|
||||
|
||||
// This one should not be found! On purpose!
|
||||
const plugin1File3 = path.join(plugin1Dir, 'unscannedFolder', 'file3.jsx');
|
||||
await fs.ensureDir(path.dirname(plugin1File3));
|
||||
await fs.writeFile(
|
||||
plugin1File3,
|
||||
`
|
||||
export default function MyComponent() {
|
||||
return (
|
||||
<div>
|
||||
<input text={translate({id: 'plugin1Id3',message: 'plugin1 message 3',description: 'plugin1 description 3'})}/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -261,7 +294,7 @@ export default function MyComponent() {
|
|||
const plugin1 = createTestPlugin(plugin1Dir);
|
||||
|
||||
const plugin2Dir = await createTmpDir();
|
||||
const plugin2File = path.join(plugin1Dir, 'sub', 'path', 'file.tsx');
|
||||
const plugin2File = path.join(plugin1Dir, 'subpath', 'file.tsx');
|
||||
await fs.ensureDir(path.dirname(plugin2File));
|
||||
await fs.writeFile(
|
||||
plugin2File,
|
||||
|
@ -271,7 +304,7 @@ type Props = {hey: string};
|
|||
export default function MyComponent(props: Props) {
|
||||
return (
|
||||
<div>
|
||||
<input text={translate({id: 'plugin2Id',message: 'plugin2 message',description: 'plugin2 description'})}/>
|
||||
<input text={translate({id: 'plugin2Id1',message: 'plugin2 message 1',description: 'plugin2 description 1'})}/>
|
||||
<Translate
|
||||
id="plugin2Id2"
|
||||
description="plugin2 description 2"
|
||||
|
@ -291,13 +324,17 @@ export default function MyComponent(props: Props) {
|
|||
TestBabelOptions,
|
||||
);
|
||||
expect(translations).toEqual({
|
||||
plugin1Id: {
|
||||
description: 'plugin1 description',
|
||||
message: 'plugin1 message',
|
||||
plugin1Id1: {
|
||||
description: 'plugin1 description 1',
|
||||
message: 'plugin1 message 1',
|
||||
},
|
||||
plugin2Id: {
|
||||
description: 'plugin2 description',
|
||||
message: 'plugin2 message',
|
||||
plugin1Id2: {
|
||||
description: 'plugin1 description 2',
|
||||
message: 'plugin1 message 2',
|
||||
},
|
||||
plugin2Id1: {
|
||||
description: 'plugin2 description 1',
|
||||
message: 'plugin2 message 1',
|
||||
},
|
||||
plugin2Id2: {
|
||||
description: 'plugin2 description 2',
|
||||
|
|
|
@ -31,15 +31,28 @@ function isTranslatableSourceCodePath(filePath: string): boolean {
|
|||
return TranslatableSourceCodeExtension.has(nodePath.extname(filePath));
|
||||
}
|
||||
|
||||
function getPluginSourceCodeFilePaths(plugin: InitPlugin): string[] {
|
||||
// The getPathsToWatch() generally returns the js/jsx/ts/tsx/md/mdx file paths
|
||||
// We can use this method as well to know which folders we should try to extract translations from
|
||||
// Hacky/implicit, but do we want to introduce a new lifecycle method just for that???
|
||||
const codePaths: string[] = plugin.getPathsToWatch?.() ?? [];
|
||||
|
||||
// We also include theme code
|
||||
const themePath = plugin.getThemePath?.();
|
||||
if (themePath) {
|
||||
codePaths.push(themePath);
|
||||
}
|
||||
|
||||
return codePaths;
|
||||
}
|
||||
|
||||
async function getSourceCodeFilePaths(
|
||||
plugins: InitPlugin[],
|
||||
): Promise<string[]> {
|
||||
// The getPathsToWatch() generally returns the js/jsx/ts/tsx/md/mdx file paths
|
||||
// We can use this method as well to know which folders we should try to extract translations from
|
||||
// Hacky/implicit, but do we want to introduce a new lifecycle method for that???
|
||||
const allPathsToWatch = flatten(
|
||||
plugins.map((plugin) => plugin.getPathsToWatch?.() ?? []),
|
||||
);
|
||||
const allPathsToWatch = flatten(plugins.map(getPluginSourceCodeFilePaths));
|
||||
|
||||
// Required for Windows support, as paths using \ should not be used by globby
|
||||
// (also using the windows hard drive prefix like c: is not a good idea)
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
"deploy": "docusaurus deploy",
|
||||
"clear": "docusaurus clear",
|
||||
"serve": "docusaurus serve",
|
||||
"write-translations": "docusaurus write-translations",
|
||||
"start:baseUrl": "cross-env BASE_URL='/build/' yarn start",
|
||||
"build:baseUrl": "cross-env BASE_URL='/build/' yarn build",
|
||||
"start:bootstrap": "cross-env DOCUSAURUS_PRESET=bootstrap yarn start",
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue