mirror of
https://github.com/facebook/docusaurus.git
synced 2025-05-10 07:37:19 +02:00
feat(v2): editUrl function for advanced use-cases (#4121)
* EditUrl function * normalize blog/docs regarding the editUrl feature + editUrl function * editUrl fn => always inject posix style relative paths, make tests more reliable (see also https://github.com/facebook/docusaurus/issues/4124) * fix editUrl on windows
This commit is contained in:
parent
15c50e2ecb
commit
be7b5dca78
15 changed files with 368 additions and 69 deletions
|
@ -10,14 +10,20 @@ import path from 'path';
|
|||
import pluginContentBlog from '../index';
|
||||
import {DocusaurusConfig, LoadContext, I18n} from '@docusaurus/types';
|
||||
import {PluginOptionSchema} from '../pluginOptionSchema';
|
||||
import {PluginOptions, EditUrlFunction} from '../types';
|
||||
import Joi from 'joi';
|
||||
|
||||
const DefaultI18N: I18n = {
|
||||
currentLocale: 'en',
|
||||
locales: ['en'],
|
||||
defaultLocale: 'en',
|
||||
localeConfigs: {},
|
||||
};
|
||||
|
||||
function validateAndNormalize(schema, options) {
|
||||
function validateAndNormalize(
|
||||
schema: Joi.ObjectSchema,
|
||||
options: Partial<PluginOptions>,
|
||||
) {
|
||||
const {value, error} = schema.validate(options);
|
||||
if (error) {
|
||||
throw error;
|
||||
|
@ -27,8 +33,14 @@ function validateAndNormalize(schema, options) {
|
|||
}
|
||||
|
||||
describe('loadBlog', () => {
|
||||
const pluginPath = 'blog';
|
||||
const getBlogPosts = async (siteDir) => {
|
||||
const PluginPath = 'blog';
|
||||
|
||||
const BaseEditUrl = 'https://baseEditUrl.com/edit';
|
||||
|
||||
const getBlogPosts = async (
|
||||
siteDir: string,
|
||||
pluginOptions: Partial<PluginOptions> = {},
|
||||
) => {
|
||||
const generatedFilesDir: string = path.resolve(siteDir, '.docusaurus');
|
||||
const siteConfig = {
|
||||
title: 'Hello',
|
||||
|
@ -43,12 +55,12 @@ describe('loadBlog', () => {
|
|||
i18n: DefaultI18N,
|
||||
} as LoadContext,
|
||||
validateAndNormalize(PluginOptionSchema, {
|
||||
path: pluginPath,
|
||||
editUrl:
|
||||
'https://github.com/facebook/docusaurus/edit/master/website-1x',
|
||||
path: PluginPath,
|
||||
editUrl: BaseEditUrl,
|
||||
...pluginOptions,
|
||||
}),
|
||||
);
|
||||
const {blogPosts} = await plugin.loadContent();
|
||||
const {blogPosts} = (await plugin.loadContent!())!;
|
||||
|
||||
return blogPosts;
|
||||
};
|
||||
|
@ -58,14 +70,13 @@ describe('loadBlog', () => {
|
|||
const blogPosts = await getBlogPosts(siteDir);
|
||||
|
||||
expect({
|
||||
...blogPosts.find((v) => v.metadata.title === 'date-matter').metadata,
|
||||
...blogPosts.find((v) => v.metadata.title === 'date-matter')!.metadata,
|
||||
...{prevItem: undefined},
|
||||
}).toEqual({
|
||||
editUrl:
|
||||
'https://github.com/facebook/docusaurus/edit/master/website-1x/blog/date-matter.md',
|
||||
editUrl: `${BaseEditUrl}/blog/date-matter.md`,
|
||||
permalink: '/blog/date-matter',
|
||||
readingTime: 0.02,
|
||||
source: path.posix.join('@site', pluginPath, 'date-matter.md'),
|
||||
source: path.posix.join('@site', PluginPath, 'date-matter.md'),
|
||||
title: 'date-matter',
|
||||
description: `date inside front matter`,
|
||||
date: new Date('2019-01-01'),
|
||||
|
@ -81,10 +92,9 @@ describe('loadBlog', () => {
|
|||
expect(
|
||||
blogPosts.find(
|
||||
(v) => v.metadata.title === 'Happy 1st Birthday Slash! (translated)',
|
||||
).metadata,
|
||||
)!.metadata,
|
||||
).toEqual({
|
||||
editUrl:
|
||||
'https://github.com/facebook/docusaurus/edit/master/website-1x/i18n/en/docusaurus-plugin-content-blog/2018-12-14-Happy-First-Birthday-Slash.md',
|
||||
editUrl: `${BaseEditUrl}/blog/2018-12-14-Happy-First-Birthday-Slash.md`,
|
||||
permalink: '/blog/2018/12/14/Happy-First-Birthday-Slash',
|
||||
readingTime: 0.015,
|
||||
source: path.posix.join(
|
||||
|
@ -105,14 +115,13 @@ describe('loadBlog', () => {
|
|||
});
|
||||
|
||||
expect({
|
||||
...blogPosts.find((v) => v.metadata.title === 'Complex Slug').metadata,
|
||||
...blogPosts.find((v) => v.metadata.title === 'Complex Slug')!.metadata,
|
||||
...{prevItem: undefined},
|
||||
}).toEqual({
|
||||
editUrl:
|
||||
'https://github.com/facebook/docusaurus/edit/master/website-1x/blog/complex-slug.md',
|
||||
editUrl: `${BaseEditUrl}/blog/complex-slug.md`,
|
||||
permalink: '/blog/hey/my super path/héllô',
|
||||
readingTime: 0.015,
|
||||
source: path.posix.join('@site', pluginPath, 'complex-slug.md'),
|
||||
source: path.posix.join('@site', PluginPath, 'complex-slug.md'),
|
||||
title: 'Complex Slug',
|
||||
description: `complex url slug`,
|
||||
prevItem: undefined,
|
||||
|
@ -126,14 +135,13 @@ describe('loadBlog', () => {
|
|||
});
|
||||
|
||||
expect({
|
||||
...blogPosts.find((v) => v.metadata.title === 'Simple Slug').metadata,
|
||||
...blogPosts.find((v) => v.metadata.title === 'Simple Slug')!.metadata,
|
||||
...{prevItem: undefined},
|
||||
}).toEqual({
|
||||
editUrl:
|
||||
'https://github.com/facebook/docusaurus/edit/master/website-1x/blog/simple-slug.md',
|
||||
editUrl: `${BaseEditUrl}/blog/simple-slug.md`,
|
||||
permalink: '/blog/simple/slug',
|
||||
readingTime: 0.015,
|
||||
source: path.posix.join('@site', pluginPath, 'simple-slug.md'),
|
||||
source: path.posix.join('@site', PluginPath, 'simple-slug.md'),
|
||||
title: 'Simple Slug',
|
||||
description: `simple url slug`,
|
||||
prevItem: undefined,
|
||||
|
@ -147,6 +155,59 @@ describe('loadBlog', () => {
|
|||
});
|
||||
});
|
||||
|
||||
test('edit url with editLocalizedBlogs true', async () => {
|
||||
const siteDir = path.join(__dirname, '__fixtures__', 'website');
|
||||
const blogPosts = await getBlogPosts(siteDir, {editLocalizedFiles: true});
|
||||
|
||||
const localizedBlogPost = blogPosts.find(
|
||||
(v) => v.metadata.title === 'Happy 1st Birthday Slash! (translated)',
|
||||
)!;
|
||||
|
||||
expect(localizedBlogPost.metadata.editUrl).toEqual(
|
||||
`${BaseEditUrl}/i18n/en/docusaurus-plugin-content-blog/2018-12-14-Happy-First-Birthday-Slash.md`,
|
||||
);
|
||||
});
|
||||
|
||||
test('edit url with editUrl function', async () => {
|
||||
const siteDir = path.join(__dirname, '__fixtures__', 'website');
|
||||
|
||||
const hardcodedEditUrl = 'hardcoded-edit-url';
|
||||
const editUrlFunction: EditUrlFunction = jest.fn(() => hardcodedEditUrl);
|
||||
|
||||
const blogPosts = await getBlogPosts(siteDir, {editUrl: editUrlFunction});
|
||||
|
||||
blogPosts.forEach((blogPost) => {
|
||||
expect(blogPost.metadata.editUrl).toEqual(hardcodedEditUrl);
|
||||
});
|
||||
|
||||
expect(editUrlFunction).toHaveBeenCalledTimes(5);
|
||||
expect(editUrlFunction).toHaveBeenCalledWith({
|
||||
blogDirPath: 'blog',
|
||||
blogPath: 'date-matter.md',
|
||||
locale: 'en',
|
||||
});
|
||||
expect(editUrlFunction).toHaveBeenCalledWith({
|
||||
blogDirPath: 'blog',
|
||||
blogPath: 'draft.md',
|
||||
locale: 'en',
|
||||
});
|
||||
expect(editUrlFunction).toHaveBeenCalledWith({
|
||||
blogDirPath: 'blog',
|
||||
blogPath: 'complex-slug.md',
|
||||
locale: 'en',
|
||||
});
|
||||
expect(editUrlFunction).toHaveBeenCalledWith({
|
||||
blogDirPath: 'blog',
|
||||
blogPath: 'simple-slug.md',
|
||||
locale: 'en',
|
||||
});
|
||||
expect(editUrlFunction).toHaveBeenCalledWith({
|
||||
blogDirPath: 'i18n/en/docusaurus-plugin-content-blog',
|
||||
blogPath: '2018-12-14-Happy-First-Birthday-Slash.md',
|
||||
locale: 'en',
|
||||
});
|
||||
});
|
||||
|
||||
test('draft blog post not exists in production build', async () => {
|
||||
process.env.NODE_ENV = 'production';
|
||||
const siteDir = path.join(__dirname, '__fixtures__', 'website');
|
||||
|
@ -162,17 +223,16 @@ describe('loadBlog', () => {
|
|||
'website-blog-without-date',
|
||||
);
|
||||
const blogPosts = await getBlogPosts(siteDir);
|
||||
const noDateSource = path.posix.join('@site', pluginPath, 'no date.md');
|
||||
const noDateSource = path.posix.join('@site', PluginPath, 'no date.md');
|
||||
const noDateSourceBirthTime = (
|
||||
await fs.stat(noDateSource.replace('@site', siteDir))
|
||||
).birthtime;
|
||||
|
||||
expect({
|
||||
...blogPosts.find((v) => v.metadata.title === 'no date').metadata,
|
||||
...blogPosts.find((v) => v.metadata.title === 'no date')!.metadata,
|
||||
...{prevItem: undefined},
|
||||
}).toEqual({
|
||||
editUrl:
|
||||
'https://github.com/facebook/docusaurus/edit/master/website-1x/blog/no date.md',
|
||||
editUrl: `${BaseEditUrl}/blog/no date.md`,
|
||||
permalink: '/blog/no date',
|
||||
readingTime: 0.01,
|
||||
source: noDateSource,
|
||||
|
|
|
@ -26,6 +26,7 @@ import {
|
|||
aliasedSitePath,
|
||||
getEditUrl,
|
||||
getFolderContainingFile,
|
||||
posixPath,
|
||||
} from '@docusaurus/utils';
|
||||
import {LoadContext} from '@docusaurus/types';
|
||||
import {keyBy} from 'lodash';
|
||||
|
@ -99,7 +100,7 @@ export async function generateBlogFeed(
|
|||
|
||||
export async function generateBlogPosts(
|
||||
contentPaths: BlogContentPaths,
|
||||
{siteConfig, siteDir}: LoadContext,
|
||||
{siteConfig, siteDir, i18n}: LoadContext,
|
||||
options: PluginOptions,
|
||||
): Promise<BlogPost[]> {
|
||||
const {
|
||||
|
@ -107,7 +108,7 @@ export async function generateBlogPosts(
|
|||
routeBasePath,
|
||||
truncateMarker,
|
||||
showReadingTime,
|
||||
editUrl,
|
||||
editUrl: siteEditUrl,
|
||||
} = options;
|
||||
|
||||
if (!fs.existsSync(contentPaths.contentPath)) {
|
||||
|
@ -124,18 +125,47 @@ export async function generateBlogPosts(
|
|||
await Promise.all(
|
||||
blogSourceFiles.map(async (blogSourceFile: string) => {
|
||||
// Lookup in localized folder in priority
|
||||
const contentPath = await getFolderContainingFile(
|
||||
const blogDirPath = await getFolderContainingFile(
|
||||
getContentPathList(contentPaths),
|
||||
blogSourceFile,
|
||||
);
|
||||
|
||||
const source = path.join(contentPath, blogSourceFile);
|
||||
const source = path.join(blogDirPath, blogSourceFile);
|
||||
|
||||
const aliasedSource = aliasedSitePath(source, siteDir);
|
||||
|
||||
const relativePath = path.relative(siteDir, source);
|
||||
const blogFileName = path.basename(blogSourceFile);
|
||||
|
||||
const editBlogUrl = getEditUrl(relativePath, editUrl);
|
||||
function getBlogEditUrl() {
|
||||
const blogPathRelative = path.relative(
|
||||
blogDirPath,
|
||||
path.resolve(source),
|
||||
);
|
||||
|
||||
if (typeof siteEditUrl === 'function') {
|
||||
return siteEditUrl({
|
||||
blogDirPath: posixPath(path.relative(siteDir, blogDirPath)),
|
||||
blogPath: posixPath(blogPathRelative),
|
||||
locale: i18n.currentLocale,
|
||||
});
|
||||
} else if (typeof siteEditUrl === 'string') {
|
||||
const isLocalized = blogDirPath === contentPaths.contentPathLocalized;
|
||||
const fileContentPath =
|
||||
isLocalized && options.editLocalizedFiles
|
||||
? contentPaths.contentPathLocalized
|
||||
: contentPaths.contentPath;
|
||||
|
||||
const contentPathEditUrl = normalizeUrl([
|
||||
siteEditUrl,
|
||||
posixPath(path.relative(siteDir, fileContentPath)),
|
||||
]);
|
||||
|
||||
return getEditUrl(blogPathRelative, contentPathEditUrl);
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
const editBlogUrl = getBlogEditUrl();
|
||||
|
||||
const {frontMatter, content, excerpt} = await parseMarkdownFile(source);
|
||||
|
||||
|
|
|
@ -34,6 +34,7 @@ export const DEFAULT_OPTIONS = {
|
|||
include: ['*.md', '*.mdx'],
|
||||
routeBasePath: 'blog',
|
||||
path: 'blog',
|
||||
editLocalizedFiles: false,
|
||||
};
|
||||
|
||||
export const PluginOptionSchema = Joi.object({
|
||||
|
@ -67,7 +68,8 @@ export const PluginOptionSchema = Joi.object({
|
|||
remarkPlugins: RemarkPluginsSchema.default(DEFAULT_OPTIONS.remarkPlugins),
|
||||
rehypePlugins: RehypePluginsSchema.default(DEFAULT_OPTIONS.rehypePlugins),
|
||||
admonitions: AdmonitionsSchema.default(DEFAULT_OPTIONS.admonitions),
|
||||
editUrl: URISchema,
|
||||
editUrl: Joi.alternatives().try(URISchema, Joi.function()),
|
||||
editLocalizedFiles: Joi.boolean().default(DEFAULT_OPTIONS.editLocalizedFiles),
|
||||
truncateMarker: Joi.object().default(DEFAULT_OPTIONS.truncateMarker),
|
||||
beforeDefaultRemarkPlugins: RemarkPluginsSchema.default(
|
||||
DEFAULT_OPTIONS.beforeDefaultRemarkPlugins,
|
||||
|
|
|
@ -24,6 +24,12 @@ export interface DateLink {
|
|||
|
||||
export type FeedType = 'rss' | 'atom';
|
||||
|
||||
export type EditUrlFunction = (editUrlParams: {
|
||||
blogDirPath: string;
|
||||
blogPath: string;
|
||||
locale: string;
|
||||
}) => string | undefined;
|
||||
|
||||
export interface PluginOptions {
|
||||
id?: string;
|
||||
path: string;
|
||||
|
@ -57,7 +63,8 @@ export interface PluginOptions {
|
|||
copyright: string;
|
||||
language?: string;
|
||||
};
|
||||
editUrl?: string;
|
||||
editUrl?: string | EditUrlFunction;
|
||||
editLocalizedFiles?: boolean;
|
||||
admonitions: Record<string, unknown>;
|
||||
}
|
||||
|
||||
|
|
|
@ -15,6 +15,7 @@ import {
|
|||
MetadataOptions,
|
||||
VersionMetadata,
|
||||
PluginOptions,
|
||||
EditUrlFunction,
|
||||
} from '../types';
|
||||
import {LoadContext} from '@docusaurus/types';
|
||||
import {DEFAULT_PLUGIN_ID} from '@docusaurus/core/lib/constants';
|
||||
|
@ -285,6 +286,45 @@ describe('simple site', () => {
|
|||
});
|
||||
});
|
||||
|
||||
test('docs with function editUrl', async () => {
|
||||
const hardcodedEditUrl = 'hardcoded-edit-url';
|
||||
|
||||
const editUrlFunction: EditUrlFunction = jest.fn(() => hardcodedEditUrl);
|
||||
|
||||
const {siteDir, context, options, currentVersion} = await loadSite({
|
||||
options: {
|
||||
editUrl: editUrlFunction,
|
||||
},
|
||||
});
|
||||
|
||||
const testUtilsLocal = createTestUtils({
|
||||
siteDir,
|
||||
context,
|
||||
options,
|
||||
versionMetadata: currentVersion,
|
||||
});
|
||||
|
||||
await testUtilsLocal.testMeta(path.join('foo', 'baz.md'), {
|
||||
version: 'current',
|
||||
id: 'foo/baz',
|
||||
unversionedId: 'foo/baz',
|
||||
isDocsHomePage: false,
|
||||
permalink: '/docs/foo/bazSlug.html',
|
||||
slug: '/foo/bazSlug.html',
|
||||
title: 'baz',
|
||||
editUrl: hardcodedEditUrl,
|
||||
description: 'Images',
|
||||
});
|
||||
|
||||
expect(editUrlFunction).toHaveBeenCalledTimes(1);
|
||||
expect(editUrlFunction).toHaveBeenCalledWith({
|
||||
version: 'current',
|
||||
versionDocsDirPath: 'docs',
|
||||
docPath: path.posix.join('foo', 'baz.md'),
|
||||
locale: 'en',
|
||||
});
|
||||
});
|
||||
|
||||
test('docs with last update time and author', async () => {
|
||||
const {siteDir, context, options, currentVersion} = await loadSite({
|
||||
options: {
|
||||
|
@ -595,6 +635,47 @@ describe('versioned site', () => {
|
|||
);
|
||||
});
|
||||
|
||||
test('doc with editUrl function', async () => {
|
||||
const hardcodedEditUrl = 'hardcoded-edit-url';
|
||||
|
||||
const editUrlFunction: EditUrlFunction = jest.fn(() => hardcodedEditUrl);
|
||||
|
||||
const {siteDir, context, options, version100} = await loadSite({
|
||||
options: {
|
||||
editUrl: editUrlFunction,
|
||||
},
|
||||
});
|
||||
|
||||
const testUtilsLocal = createTestUtils({
|
||||
siteDir,
|
||||
context,
|
||||
options,
|
||||
versionMetadata: version100,
|
||||
});
|
||||
|
||||
await testUtilsLocal.testMeta(path.join('hello.md'), {
|
||||
id: 'version-1.0.0/hello',
|
||||
unversionedId: 'hello',
|
||||
isDocsHomePage: false,
|
||||
permalink: '/docs/1.0.0/hello',
|
||||
slug: '/hello',
|
||||
title: 'hello',
|
||||
description: 'Hello 1.0.0 ! (translated en)',
|
||||
version: '1.0.0',
|
||||
source:
|
||||
'@site/i18n/en/docusaurus-plugin-content-docs/version-1.0.0/hello.md',
|
||||
editUrl: hardcodedEditUrl,
|
||||
});
|
||||
|
||||
expect(editUrlFunction).toHaveBeenCalledTimes(1);
|
||||
expect(editUrlFunction).toHaveBeenCalledWith({
|
||||
version: '1.0.0',
|
||||
versionDocsDirPath: 'versioned_docs/version-1.0.0',
|
||||
docPath: path.join('hello.md'),
|
||||
locale: 'en',
|
||||
});
|
||||
});
|
||||
|
||||
test('translated doc with editUrl', async () => {
|
||||
const {siteDir, context, options, version100} = await loadSite({
|
||||
options: {
|
||||
|
@ -657,11 +738,11 @@ describe('versioned site', () => {
|
|||
});
|
||||
});
|
||||
|
||||
test('translated fr doc with editUrl and editLocalizedDocs=true', async () => {
|
||||
test('translated fr doc with editUrl and editLocalizedFiles=true', async () => {
|
||||
const {siteDir, context, options, version100} = await loadSite({
|
||||
options: {
|
||||
editUrl: 'https://github.com/facebook/docusaurus/edit/master/website',
|
||||
editLocalizedDocs: true,
|
||||
editLocalizedFiles: true,
|
||||
},
|
||||
locale: 'fr',
|
||||
});
|
||||
|
@ -689,12 +770,12 @@ describe('versioned site', () => {
|
|||
});
|
||||
});
|
||||
|
||||
test('translated fr doc with editUrl and editLocalizedDocs=true + editCurrentVersion=true', async () => {
|
||||
test('translated fr doc with editUrl and editLocalizedFiles=true + editCurrentVersion=true', async () => {
|
||||
const {siteDir, context, options, version100} = await loadSite({
|
||||
options: {
|
||||
editUrl: 'https://github.com/facebook/docusaurus/edit/master/website',
|
||||
editCurrentVersion: true,
|
||||
editLocalizedDocs: true,
|
||||
editLocalizedFiles: true,
|
||||
},
|
||||
locale: 'fr',
|
||||
});
|
||||
|
|
|
@ -39,7 +39,7 @@ describe('normalizeDocsPluginOptions', () => {
|
|||
includeCurrentVersion: false,
|
||||
disableVersioning: true,
|
||||
editCurrentVersion: true,
|
||||
editLocalizedDocs: true,
|
||||
editLocalizedFiles: true,
|
||||
versions: {
|
||||
current: {
|
||||
path: 'next',
|
||||
|
|
|
@ -13,6 +13,7 @@ import {
|
|||
getFolderContainingFile,
|
||||
normalizeUrl,
|
||||
parseMarkdownString,
|
||||
posixPath,
|
||||
} from '@docusaurus/utils';
|
||||
import {LoadContext} from '@docusaurus/types';
|
||||
|
||||
|
@ -120,14 +121,29 @@ export function processDocMetadata({
|
|||
|
||||
const relativeFilePath = path.relative(docsDirPath, filePath);
|
||||
|
||||
function getDocEditUrl() {
|
||||
if (typeof options.editUrl === 'function') {
|
||||
return options.editUrl({
|
||||
version: versionMetadata.versionName,
|
||||
versionDocsDirPath: posixPath(
|
||||
path.relative(siteDir, versionMetadata.docsDirPath),
|
||||
),
|
||||
docPath: posixPath(relativeFilePath),
|
||||
locale: context.i18n.currentLocale,
|
||||
});
|
||||
} else if (typeof options.editUrl === 'string') {
|
||||
const isLocalized = docsDirPath === versionMetadata.docsDirPathLocalized;
|
||||
|
||||
const versionEditUrl =
|
||||
isLocalized && options.editLocalizedDocs
|
||||
const baseVersionEditUrl =
|
||||
isLocalized && options.editLocalizedFiles
|
||||
? versionMetadata.versionEditUrlLocalized
|
||||
: versionMetadata.versionEditUrl;
|
||||
return getEditUrl(relativeFilePath, baseVersionEditUrl);
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
const docsEditUrl = getEditUrl(relativeFilePath, versionEditUrl);
|
||||
const docsEditUrl = getDocEditUrl();
|
||||
|
||||
const {frontMatter = {}, excerpt} = parseMarkdownString(content);
|
||||
const {sidebar_label, custom_edit_url} = frontMatter;
|
||||
|
|
|
@ -38,7 +38,7 @@ export const DEFAULT_OPTIONS: Omit<PluginOptions, 'id'> = {
|
|||
lastVersion: undefined,
|
||||
versions: {},
|
||||
editCurrentVersion: false,
|
||||
editLocalizedDocs: false,
|
||||
editLocalizedFiles: false,
|
||||
};
|
||||
|
||||
const VersionOptionsSchema = Joi.object({
|
||||
|
@ -52,9 +52,9 @@ const VersionsOptionsSchema = Joi.object()
|
|||
|
||||
export const OptionsSchema = Joi.object({
|
||||
path: Joi.string().default(DEFAULT_OPTIONS.path),
|
||||
editUrl: URISchema,
|
||||
editUrl: Joi.alternatives().try(URISchema, Joi.function()),
|
||||
editCurrentVersion: Joi.boolean().default(DEFAULT_OPTIONS.editCurrentVersion),
|
||||
editLocalizedDocs: Joi.boolean().default(DEFAULT_OPTIONS.editLocalizedDocs),
|
||||
editLocalizedFiles: Joi.boolean().default(DEFAULT_OPTIONS.editLocalizedFiles),
|
||||
routeBasePath: Joi.string()
|
||||
// '' not allowed, see https://github.com/facebook/docusaurus/issues/3374
|
||||
// .allow('') ""
|
||||
|
|
|
@ -31,12 +31,19 @@ export type VersionMetadata = {
|
|||
routePriority: number | undefined; // -1 for the latest docs
|
||||
};
|
||||
|
||||
export type EditUrlFunction = (editUrlParams: {
|
||||
version: string;
|
||||
versionDocsDirPath: string;
|
||||
docPath: string;
|
||||
locale: string;
|
||||
}) => string | undefined;
|
||||
|
||||
export type MetadataOptions = {
|
||||
routeBasePath: string;
|
||||
homePageId?: string;
|
||||
editUrl?: string;
|
||||
editUrl?: string | EditUrlFunction;
|
||||
editCurrentVersion: boolean;
|
||||
editLocalizedDocs: boolean;
|
||||
editLocalizedFiles: boolean;
|
||||
showLastUpdateTime?: boolean;
|
||||
showLastUpdateAuthor?: boolean;
|
||||
};
|
||||
|
|
|
@ -211,6 +211,12 @@ function getVersionEditUrls({
|
|||
return undefined;
|
||||
}
|
||||
|
||||
// if the user is using the functional form of editUrl,
|
||||
// he has total freedom and we can't compute a "version edit url"
|
||||
if (typeof editUrl === 'function') {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const editDirPath = editCurrentVersion ? currentVersionPath : docsDirPath;
|
||||
const editDirPathLocalized = editCurrentVersion
|
||||
? getDocsDirPathLocalized({
|
||||
|
|
|
@ -31,11 +31,23 @@ module.exports = {
|
|||
*/
|
||||
path: 'blog',
|
||||
/**
|
||||
* URL for editing a blog post.
|
||||
* Example: 'https://github.com/facebook/docusaurus/edit/master/website/blog/'
|
||||
* Base url to edit your site.
|
||||
* Docusaurus will compute the final editUrl with "editUrl + relativeDocPath"
|
||||
*/
|
||||
editUrl:
|
||||
'https://github.com/facebook/docusaurus/edit/master/website/blog/',
|
||||
editUrl: 'https://github.com/facebook/docusaurus/edit/master/website/',
|
||||
/**
|
||||
* For advanced cases, compute the edit url for each markdown file yourself.
|
||||
*/
|
||||
editUrl: ({locale, blogDirPath, blogPath}) => {
|
||||
return `https://github.com/facebook/docusaurus/edit/master/website/${blogDirPath}/${blogPath}`;
|
||||
},
|
||||
/**
|
||||
* Useful if you commit localized files to git.
|
||||
* When markdown files are localized, the edit url will target the localized file,
|
||||
* instead of the original unlocalized file.
|
||||
* Note: this option is ignored when editUrl is a function
|
||||
*/
|
||||
editLocalizedFiles: false,
|
||||
/**
|
||||
* Blog page title for better SEO
|
||||
*/
|
||||
|
|
|
@ -31,22 +31,30 @@ module.exports = {
|
|||
*/
|
||||
path: 'docs',
|
||||
/**
|
||||
* URL for editing a doc in the website repo.
|
||||
* Example: 'https://github.com/facebook/docusaurus/edit/master/website/'
|
||||
* Base url to edit your site.
|
||||
* Docusaurus will compute the final editUrl with "editUrl + relativeDocPath"
|
||||
*/
|
||||
editUrl: 'https://github.com/facebook/docusaurus/edit/master/website/',
|
||||
/**
|
||||
* For advanced cases, compute the edit url for each markdown file yourself.
|
||||
*/
|
||||
editUrl: function ({locale, version, versionDocsDirPath, docPath}) {
|
||||
return `https://github.com/facebook/docusaurus/edit/master/website/${versionDocsDirPath}/${docPath}`;
|
||||
},
|
||||
/**
|
||||
* Useful if you commit localized files to git.
|
||||
* When markdown files are localized, the edit url will target the localized file,
|
||||
* instead of the original unlocalized file.
|
||||
* Note: this option is ignored when editUrl is a function
|
||||
*/
|
||||
editLocalizedFiles: false,
|
||||
/**
|
||||
* Useful if you don't want users to submit doc pull-requests to older versions.
|
||||
* When docs are versioned, the edit url will link to the doc
|
||||
* in current version, instead of the versioned doc.
|
||||
* Useful if you don't want users to submit doc pull-requests to older versions.
|
||||
* Note: this option is ignored when editUrl is a function
|
||||
*/
|
||||
editCurrentVersion: false,
|
||||
/**
|
||||
* When docs are localized, the edit url will target the localized doc,
|
||||
* instead of the original unlocalized doc.
|
||||
* Useful if you commit localized docs to git, instead of using a translation service.
|
||||
*/
|
||||
editLocalizedDocs: false,
|
||||
/**
|
||||
* URL route for the docs section of your site.
|
||||
* *DO NOT* include a trailing slash.
|
||||
|
|
|
@ -409,6 +409,54 @@ Crowdin replaces markdown strings with technical ids such as `crowdin:id12345`,
|
|||
|
||||
:::
|
||||
|
||||
### Localize edit urls
|
||||
|
||||
When the user is browsing a page at `/fr/doc1`, the edit button will link by default to the unlocalized doc at `website/docs/doc1.md`.
|
||||
|
||||
You may prefer the edit button to link to the Crowdin interface instead, and can use the `editUrl` function to customize the edit urls on a per-locale basis.
|
||||
|
||||
```js title="docusaurus.config.js"
|
||||
const DefaultLocale = 'en';
|
||||
|
||||
module.exports = {
|
||||
presets: [
|
||||
[
|
||||
'@docusaurus/preset-classic',
|
||||
{
|
||||
docs: {
|
||||
// highlight-start
|
||||
editUrl: ({locale, versionDocsDirPath, docPath}) => {
|
||||
// Link to Crowdin for French docs
|
||||
if (locale !== DefaultLocale) {
|
||||
return `https://crowdin.com/project/docusaurus-v2/${locale}`;
|
||||
}
|
||||
// Link to Github for English docs
|
||||
return `https://github.com/facebook/docusaurus/edit/master/website/${versionDocsDirPath}/${docPath}`;
|
||||
},
|
||||
// highlight-end
|
||||
},
|
||||
blog: {
|
||||
// highlight-start
|
||||
editUrl: ({locale, blogDirPath, blogPath}) => {
|
||||
if (locale !== DefaultLocale) {
|
||||
return `https://crowdin.com/project/docusaurus-v2/${locale}`;
|
||||
}
|
||||
return `https://github.com/facebook/docusaurus/edit/master/website/${blogDirPath}/${blogPath}`;
|
||||
},
|
||||
// highlight-start
|
||||
},
|
||||
},
|
||||
],
|
||||
],
|
||||
};
|
||||
```
|
||||
|
||||
:::note
|
||||
|
||||
It is currently **not possible to link to a specific file** in Crowdin.
|
||||
|
||||
:::
|
||||
|
||||
### Example configuration
|
||||
|
||||
The **Docusaurus v2 configuration file** is a good example of using versioning and multi-instance:
|
||||
|
|
|
@ -171,3 +171,11 @@ New translation will be appended, and existing ones will not be overridden.
|
|||
Reset your translations with the `--override` option.
|
||||
|
||||
:::
|
||||
|
||||
### Localize edit urls
|
||||
|
||||
When the user is browsing a page at `/fr/doc1`, the edit button will link by default to the unlocalized doc at `website/docs/doc1.md`.
|
||||
|
||||
Your translations are on Git, and you can use the `editLocalizedFiles: true` option of the docs and blog plugins.
|
||||
|
||||
The edit button will link to the localized doc at `i18n/fr/docusaurus-plugin-content-docs/current/doc1.md`.
|
||||
|
|
|
@ -41,6 +41,7 @@ const isBootstrapPreset = process.env.DOCUSAURUS_PRESET === 'bootstrap';
|
|||
|
||||
const isVersioningDisabled = !!process.env.DISABLE_VERSIONING;
|
||||
|
||||
/** @type {import('@docusaurus/types').DocusaurusConfig} */
|
||||
module.exports = {
|
||||
title: 'Docusaurus',
|
||||
tagline: 'Build optimized websites quickly, focus on your content',
|
||||
|
@ -76,7 +77,12 @@ module.exports = {
|
|||
{
|
||||
id: 'community',
|
||||
path: 'community',
|
||||
editUrl: 'https://github.com/facebook/docusaurus/edit/master/website/',
|
||||
editUrl: ({locale, versionDocsDirPath, docPath}) => {
|
||||
if (locale !== 'en') {
|
||||
return `https://crowdin.com/project/docusaurus-v2/${locale}`;
|
||||
}
|
||||
return `https://github.com/facebook/docusaurus/edit/master/website/${versionDocsDirPath}/${docPath}`;
|
||||
},
|
||||
editCurrentVersion: true,
|
||||
routeBasePath: 'community',
|
||||
sidebarPath: require.resolve('./sidebarsCommunity.js'),
|
||||
|
@ -204,8 +210,12 @@ module.exports = {
|
|||
// routeBasePath: '/',
|
||||
path: 'docs',
|
||||
sidebarPath: require.resolve('./sidebars.js'),
|
||||
editUrl:
|
||||
'https://github.com/facebook/docusaurus/edit/master/website/',
|
||||
editUrl: ({locale, versionDocsDirPath, docPath}) => {
|
||||
if (locale !== 'en') {
|
||||
return `https://crowdin.com/project/docusaurus-v2/${locale}`;
|
||||
}
|
||||
return `https://github.com/facebook/docusaurus/edit/master/website/${versionDocsDirPath}/${docPath}`;
|
||||
},
|
||||
editCurrentVersion: true,
|
||||
showLastUpdateAuthor: true,
|
||||
showLastUpdateTime: true,
|
||||
|
@ -227,8 +237,12 @@ module.exports = {
|
|||
blog: {
|
||||
// routeBasePath: '/',
|
||||
path: '../website-1.x/blog',
|
||||
editUrl:
|
||||
'https://github.com/facebook/docusaurus/edit/master/website-1.x/',
|
||||
editUrl: ({locale, blogDirPath, blogPath}) => {
|
||||
if (locale !== 'en') {
|
||||
return `https://crowdin.com/project/docusaurus-v2/${locale}`;
|
||||
}
|
||||
return `https://github.com/facebook/docusaurus/edit/master/website/${blogDirPath}/${blogPath}`;
|
||||
},
|
||||
postsPerPage: 3,
|
||||
feedOptions: {
|
||||
type: 'all',
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue