@docusaurus/plugin-content-docs 3.8.1 → 3.9.0-canary-6403

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/index.ts CHANGED
@@ -7,7 +7,6 @@
7
7
 
8
8
  import path from 'path';
9
9
  import fs from 'fs-extra';
10
- import logger from '@docusaurus/logger';
11
10
  import {
12
11
  normalizeUrl,
13
12
  docuHash,
@@ -63,6 +62,12 @@ async function createMdxLoaderDependencyFile({
63
62
  options: PluginOptions;
64
63
  versionsMetadata: VersionMetadata[];
65
64
  }): Promise<string | undefined> {
65
+ // Disabled for unit tests, the side effect produces infinite watch loops
66
+ // TODO find a better way :/
67
+ if (process.env.NODE_ENV === 'test') {
68
+ return undefined;
69
+ }
70
+
66
71
  const filePath = path.join(dataDir, '__mdx-loader-dependency.json');
67
72
  // the cache is invalidated whenever this file content changes
68
73
  const fileContent = {
@@ -158,18 +163,12 @@ export default async function pluginContentDocs(
158
163
  sourceFilePath,
159
164
  versionsMetadata,
160
165
  );
161
- const permalink = resolveMarkdownLinkPathname(linkPathname, {
166
+ return resolveMarkdownLinkPathname(linkPathname, {
162
167
  sourceFilePath,
163
168
  sourceToPermalink: contentHelpers.sourceToPermalink,
164
169
  siteDir,
165
170
  contentPaths: version,
166
171
  });
167
- if (permalink === null) {
168
- logger.report(
169
- siteConfig.onBrokenMarkdownLinks,
170
- )`Docs markdown link couldn't be resolved: (url=${linkPathname}) in source file path=${sourceFilePath} for version number=${version.versionName}`;
171
- }
172
- return permalink;
173
172
  },
174
173
  },
175
174
  });
package/src/props.ts CHANGED
@@ -38,28 +38,23 @@ export function toSidebarDocItemLinkProp({
38
38
  'id' | 'title' | 'permalink' | 'unlisted' | 'frontMatter'
39
39
  >;
40
40
  }): PropSidebarItemLink {
41
- const {
42
- id,
43
- title,
44
- permalink,
45
- frontMatter: {
46
- sidebar_label: sidebarLabel,
47
- sidebar_custom_props: customProps,
48
- },
49
- unlisted,
50
- } = doc;
41
+ const {id, title, permalink, frontMatter, unlisted} = doc;
51
42
  return {
52
43
  type: 'link',
53
- label: sidebarLabel ?? item.label ?? title,
44
+ ...(item.key && {key: item.key}),
54
45
  href: permalink,
55
- className: item.className,
56
- customProps: item.customProps ?? customProps,
46
+ // Front Matter data takes precedence over sidebars.json
47
+ label: frontMatter.sidebar_label ?? item.label ?? title,
48
+ className: frontMatter.sidebar_class_name ?? item.className,
49
+ customProps: frontMatter.sidebar_custom_props ?? item.customProps,
57
50
  docId: id,
58
51
  unlisted,
59
52
  };
60
53
  }
61
54
 
62
- export function toSidebarsProp(loadedVersion: LoadedVersion): PropSidebars {
55
+ export function toSidebarsProp(
56
+ loadedVersion: Pick<LoadedVersion, 'docs' | 'sidebars'>,
57
+ ): PropSidebars {
63
58
  const docsById = createDocsByIdIndex(loadedVersion.docs);
64
59
 
65
60
  function getDocById(docId: string): DocMetadata {
@@ -252,6 +252,7 @@ Available doc IDs:
252
252
  ...(categoryMetadata?.description && {
253
253
  description: categoryMetadata?.description,
254
254
  }),
255
+ ...(categoryMetadata?.key && {key: categoryMetadata?.key}),
255
256
  ...(link && {link}),
256
257
  };
257
258
  }
@@ -77,10 +77,13 @@ function postProcessSidebarItem(
77
77
  ) {
78
78
  return null;
79
79
  }
80
+ const {label, className, customProps} = category;
80
81
  return {
81
82
  type: 'doc',
82
- label: category.label,
83
83
  id: category.link.id,
84
+ label,
85
+ ...(className && {className}),
86
+ ...(customProps && {customProps}),
84
87
  };
85
88
  }
86
89
  // A non-collapsible category can't be collapsed!
@@ -19,6 +19,7 @@ import type {Slugger} from '@docusaurus/utils';
19
19
  type Expand<T extends {[x: string]: unknown}> = {[P in keyof T]: T[P]};
20
20
 
21
21
  export type SidebarItemBase = {
22
+ key?: string;
22
23
  className?: string;
23
24
  customProps?: {[key: string]: unknown};
24
25
  };
@@ -28,8 +29,9 @@ export type SidebarItemDoc = SidebarItemBase & {
28
29
  label?: string;
29
30
  id: string;
30
31
  /**
31
- * This is an internal marker. Items with labels defined in the config needs
32
- * to be translated with JSON
32
+ * This is an internal marker set during the sidebar normalization process.
33
+ * Docs with labels defined in the config need to be translated with JSON.
34
+ * Otherwise, it's preferable to translate the MDX doc title or front matter.
33
35
  */
34
36
  translatable?: true;
35
37
  };
@@ -215,6 +217,7 @@ export type PropSidebarBreadcrumbsItem =
215
217
  | PropSidebarItemCategory;
216
218
 
217
219
  export type CategoryMetadataFile = {
220
+ key?: string;
218
221
  label?: string;
219
222
  position?: number;
220
223
  description?: string;
@@ -28,6 +28,7 @@ import type {
28
28
  // in normalization
29
29
 
30
30
  const sidebarItemBaseSchema = Joi.object<SidebarItemBase>({
31
+ key: Joi.string(),
31
32
  className: Joi.string(),
32
33
  customProps: Joi.object().unknown(),
33
34
  });
@@ -166,6 +167,7 @@ export function validateSidebars(sidebars: {
166
167
  }
167
168
 
168
169
  const categoryMetadataFileSchema = Joi.object<CategoryMetadataFile>({
170
+ key: Joi.string(),
169
171
  label: Joi.string(),
170
172
  description: Joi.string(),
171
173
  position: Joi.number(),
@@ -7,6 +7,7 @@
7
7
 
8
8
  import _ from 'lodash';
9
9
  import {mergeTranslations} from '@docusaurus/utils';
10
+ import logger from '@docusaurus/logger';
10
11
  import {CURRENT_VERSION_NAME} from './constants';
11
12
  import {
12
13
  collectSidebarCategories,
@@ -40,20 +41,53 @@ function getVersionFileName(versionName: string): string {
40
41
  return `version-${versionName}`;
41
42
  }
42
43
 
44
+ type TranslationMessageEntry = [string, TranslationMessage];
45
+
46
+ function ensureNoSidebarDuplicateEntries(
47
+ translationEntries: TranslationMessageEntry[],
48
+ ): void {
49
+ const grouped = _.groupBy(translationEntries, (entry) => entry[0]);
50
+ const duplicates = Object.entries(grouped).filter(
51
+ (entry) => entry[1].length > 1,
52
+ );
53
+
54
+ if (duplicates.length > 0) {
55
+ throw new Error(`Multiple docs sidebar items produce the same translation key.
56
+ - ${duplicates
57
+ .map(([translationKey, entries]) => {
58
+ return `${logger.code(translationKey)}: ${logger.num(
59
+ entries.length,
60
+ )} duplicates found:\n - ${entries
61
+ .map((duplicate) => {
62
+ const desc = duplicate[1].description;
63
+ return `${logger.name(duplicate[1].message)} ${
64
+ desc ? `(${logger.subdue(desc)})` : ''
65
+ }`;
66
+ })
67
+ .join('\n - ')}`;
68
+ })
69
+ .join('\n\n- ')}
70
+
71
+ To avoid translation key conflicts, use the ${logger.code(
72
+ 'key',
73
+ )} attribute on the sidebar items above to uniquely identify them.
74
+ `);
75
+ }
76
+ }
77
+
43
78
  function getSidebarTranslationFileContent(
44
79
  sidebar: Sidebar,
45
80
  sidebarName: string,
46
81
  ): TranslationFileContent {
47
- type TranslationMessageEntry = [string, TranslationMessage];
48
-
49
82
  const categories = collectSidebarCategories(sidebar);
50
83
 
51
- const categoryContent: TranslationFileContent = Object.fromEntries(
52
- categories.flatMap((category) => {
84
+ const categoryEntries: TranslationMessageEntry[] = categories.flatMap(
85
+ (category) => {
53
86
  const entries: TranslationMessageEntry[] = [];
87
+ const categoryKey = category.key ?? category.label;
54
88
 
55
89
  entries.push([
56
- `sidebar.${sidebarName}.category.${category.label}`,
90
+ `sidebar.${sidebarName}.category.${categoryKey}`,
57
91
  {
58
92
  message: category.label,
59
93
  description: `The label for category ${category.label} in sidebar ${sidebarName}`,
@@ -63,7 +97,7 @@ function getSidebarTranslationFileContent(
63
97
  if (category.link?.type === 'generated-index') {
64
98
  if (category.link.title) {
65
99
  entries.push([
66
- `sidebar.${sidebarName}.category.${category.label}.link.generated-index.title`,
100
+ `sidebar.${sidebarName}.category.${categoryKey}.link.generated-index.title`,
67
101
  {
68
102
  message: category.link.title,
69
103
  description: `The generated-index page title for category ${category.label} in sidebar ${sidebarName}`,
@@ -72,7 +106,7 @@ function getSidebarTranslationFileContent(
72
106
  }
73
107
  if (category.link.description) {
74
108
  entries.push([
75
- `sidebar.${sidebarName}.category.${category.label}.link.generated-index.description`,
109
+ `sidebar.${sidebarName}.category.${categoryKey}.link.generated-index.description`,
76
110
  {
77
111
  message: category.link.description,
78
112
  description: `The generated-index page description for category ${category.label} in sidebar ${sidebarName}`,
@@ -82,36 +116,40 @@ function getSidebarTranslationFileContent(
82
116
  }
83
117
 
84
118
  return entries;
85
- }),
119
+ },
86
120
  );
87
121
 
88
122
  const links = collectSidebarLinks(sidebar);
89
- const linksContent: TranslationFileContent = Object.fromEntries(
90
- links.map((link) => [
91
- `sidebar.${sidebarName}.link.${link.label}`,
123
+ const linksEntries: TranslationMessageEntry[] = links.map((link) => {
124
+ const linkKey = link.key ?? link.label;
125
+ return [
126
+ `sidebar.${sidebarName}.link.${linkKey}`,
92
127
  {
93
128
  message: link.label,
94
129
  description: `The label for link ${link.label} in sidebar ${sidebarName}, linking to ${link.href}`,
95
130
  },
96
- ]),
97
- );
131
+ ];
132
+ });
98
133
 
99
134
  const docs = collectSidebarDocItems(sidebar)
100
135
  .concat(collectSidebarRefs(sidebar))
101
136
  .filter((item) => item.translatable);
102
- const docLinksContent: TranslationFileContent = Object.fromEntries(
103
- docs.map((doc) => [
104
- `sidebar.${sidebarName}.doc.${doc.label!}`,
137
+ const docLinksEntries: TranslationMessageEntry[] = docs.map((doc) => {
138
+ const docKey = doc.key ?? doc.label!;
139
+ return [
140
+ `sidebar.${sidebarName}.doc.${docKey}`,
105
141
  {
106
142
  message: doc.label!,
107
143
  description: `The label for the doc item ${doc.label!} in sidebar ${sidebarName}, linking to the doc ${
108
144
  doc.id
109
145
  }`,
110
146
  },
111
- ]),
112
- );
147
+ ];
148
+ });
113
149
 
114
- return mergeTranslations([categoryContent, linksContent, docLinksContent]);
150
+ const allEntries = [...categoryEntries, ...linksEntries, ...docLinksEntries];
151
+ ensureNoSidebarDuplicateEntries(allEntries);
152
+ return Object.fromEntries(allEntries);
115
153
  }
116
154
 
117
155
  function translateSidebar({
@@ -150,27 +188,30 @@ function translateSidebar({
150
188
  return transformSidebarItems(sidebar, (item) => {
151
189
  if (item.type === 'category') {
152
190
  const link = transformSidebarCategoryLink(item);
191
+ const categoryKey = item.key ?? item.label;
153
192
  return {
154
193
  ...item,
155
194
  label:
156
- sidebarsTranslations[`sidebar.${sidebarName}.category.${item.label}`]
195
+ sidebarsTranslations[`sidebar.${sidebarName}.category.${categoryKey}`]
157
196
  ?.message ?? item.label,
158
197
  ...(link && {link}),
159
198
  };
160
199
  }
161
200
  if (item.type === 'link') {
201
+ const linkKey = item.key ?? item.label;
162
202
  return {
163
203
  ...item,
164
204
  label:
165
- sidebarsTranslations[`sidebar.${sidebarName}.link.${item.label}`]
205
+ sidebarsTranslations[`sidebar.${sidebarName}.link.${linkKey}`]
166
206
  ?.message ?? item.label,
167
207
  };
168
208
  }
169
209
  if ((item.type === 'doc' || item.type === 'ref') && item.translatable) {
210
+ const docKey = item.key ?? item.label!;
170
211
  return {
171
212
  ...item,
172
213
  label:
173
- sidebarsTranslations[`sidebar.${sidebarName}.doc.${item.label!}`]
214
+ sidebarsTranslations[`sidebar.${sidebarName}.doc.${docKey}`]
174
215
  ?.message ?? item.label,
175
216
  };
176
217
  }
@@ -7,7 +7,11 @@
7
7
 
8
8
  import path from 'path';
9
9
  import fs from 'fs-extra';
10
- import {getPluginI18nPath, DEFAULT_PLUGIN_ID} from '@docusaurus/utils';
10
+ import {
11
+ getPluginI18nPath,
12
+ getLocaleConfig,
13
+ DEFAULT_PLUGIN_ID,
14
+ } from '@docusaurus/utils';
11
15
  import {
12
16
  VERSIONS_JSON_FILE,
13
17
  VERSIONED_DOCS_DIR,
@@ -186,11 +190,16 @@ export async function getVersionMetadataPaths({
186
190
  >
187
191
  > {
188
192
  const isCurrent = versionName === CURRENT_VERSION_NAME;
189
- const contentPathLocalized = getDocsDirPathLocalized({
190
- localizationDir: context.localizationDir,
191
- pluginId: options.id,
192
- versionName,
193
- });
193
+
194
+ const shouldTranslate = getLocaleConfig(context.i18n).translate;
195
+ const contentPathLocalized = shouldTranslate
196
+ ? getDocsDirPathLocalized({
197
+ localizationDir: context.localizationDir,
198
+ pluginId: options.id,
199
+ versionName,
200
+ })
201
+ : undefined;
202
+
194
203
  const contentPath = isCurrent
195
204
  ? path.resolve(context.siteDir, options.path)
196
205
  : getVersionDocsDirPath(context.siteDir, options.id, versionName);
@@ -7,7 +7,7 @@
7
7
 
8
8
  import path from 'path';
9
9
  import _ from 'lodash';
10
- import {createSlugger} from '@docusaurus/utils';
10
+ import {aliasedSitePathToRelativePath, createSlugger} from '@docusaurus/utils';
11
11
  import {getTagsFile} from '@docusaurus/utils-validation';
12
12
  import logger from '@docusaurus/logger';
13
13
  import {
@@ -29,102 +29,157 @@ import type {
29
29
  import type {DocFile} from '../types';
30
30
  import type {LoadContext} from '@docusaurus/types';
31
31
 
32
- export async function loadVersion({
33
- context,
34
- options,
35
- versionMetadata,
36
- env,
37
- }: {
32
+ type LoadVersionParams = {
38
33
  context: LoadContext;
39
34
  options: PluginOptions;
40
35
  versionMetadata: VersionMetadata;
41
36
  env: DocEnv;
42
- }): Promise<LoadedVersion> {
43
- const {siteDir} = context;
44
-
45
- async function loadVersionDocsBase(
46
- tagsFile: TagsFile | null,
47
- ): Promise<DocMetadataBase[]> {
48
- const docFiles = await readVersionDocs(versionMetadata, options);
49
- if (docFiles.length === 0) {
50
- throw new Error(
51
- `Docs version "${
52
- versionMetadata.versionName
53
- }" has no docs! At least one doc should exist at "${path.relative(
54
- siteDir,
55
- versionMetadata.contentPath,
56
- )}".`,
57
- );
58
- }
59
- function processVersionDoc(docFile: DocFile) {
60
- return processDocMetadata({
61
- docFile,
62
- versionMetadata,
63
- context,
64
- options,
65
- env,
66
- tagsFile,
67
- });
68
- }
69
- return Promise.all(docFiles.map(processVersionDoc));
37
+ };
38
+
39
+ function ensureNoDuplicateDocId(docs: DocMetadataBase[]): void {
40
+ const duplicatesById = _.chain(docs)
41
+ .sort((d1, d2) => {
42
+ // Need to sort because Globby order is non-deterministic
43
+ // TODO maybe we should create a deterministic glob utils?
44
+ // see https://github.com/sindresorhus/globby/issues/131
45
+ return d1.source.localeCompare(d2.source);
46
+ })
47
+ .groupBy((d) => d.id)
48
+ .pickBy((group) => group.length > 1)
49
+ .value();
50
+
51
+ const duplicateIdEntries = Object.entries(duplicatesById);
52
+
53
+ if (duplicateIdEntries.length) {
54
+ const idMessages = duplicateIdEntries
55
+ .map(([id, duplicateDocs]) => {
56
+ return logger.interpolate`- code=${id} found in number=${
57
+ duplicateDocs.length
58
+ } docs:
59
+ - ${duplicateDocs
60
+ .map((d) => aliasedSitePathToRelativePath(d.source))
61
+ .join('\n - ')}`;
62
+ })
63
+ .join('\n\n');
64
+
65
+ const message = `The docs plugin found docs sharing the same id:
66
+ \n${idMessages}\n
67
+ Docs should have distinct ids.
68
+ In case of conflict, you can rename the docs file, or use the ${logger.code(
69
+ 'id',
70
+ )} front matter to assign an explicit distinct id to each doc.
71
+ `;
72
+
73
+ throw new Error(message);
70
74
  }
75
+ }
71
76
 
72
- async function doLoadVersion(): Promise<LoadedVersion> {
73
- const tagsFile = await getTagsFile({
74
- contentPaths: versionMetadata,
75
- tags: options.tags,
77
+ async function loadVersionDocsBase({
78
+ tagsFile,
79
+ context,
80
+ options,
81
+ versionMetadata,
82
+ env,
83
+ }: LoadVersionParams & {
84
+ tagsFile: TagsFile | null;
85
+ }): Promise<DocMetadataBase[]> {
86
+ const docFiles = await readVersionDocs(versionMetadata, options);
87
+ if (docFiles.length === 0) {
88
+ throw new Error(
89
+ `Docs version "${
90
+ versionMetadata.versionName
91
+ }" has no docs! At least one doc should exist at "${path.relative(
92
+ context.siteDir,
93
+ versionMetadata.contentPath,
94
+ )}".`,
95
+ );
96
+ }
97
+ function processVersionDoc(docFile: DocFile) {
98
+ return processDocMetadata({
99
+ docFile,
100
+ versionMetadata,
101
+ context,
102
+ options,
103
+ env,
104
+ tagsFile,
76
105
  });
106
+ }
107
+ const docs = await Promise.all(docFiles.map(processVersionDoc));
108
+ ensureNoDuplicateDocId(docs);
109
+ return docs;
110
+ }
77
111
 
78
- const docsBase: DocMetadataBase[] = await loadVersionDocsBase(tagsFile);
112
+ async function doLoadVersion({
113
+ context,
114
+ options,
115
+ versionMetadata,
116
+ env,
117
+ }: LoadVersionParams): Promise<LoadedVersion> {
118
+ const tagsFile = await getTagsFile({
119
+ contentPaths: versionMetadata,
120
+ tags: options.tags,
121
+ });
79
122
 
80
- // TODO we only ever need draftIds in further code, not full draft items
81
- // To simplify and prevent mistakes, avoid exposing draft
82
- // replace draft=>draftIds in content loaded
83
- const [drafts, docs] = _.partition(docsBase, (doc) => doc.draft);
123
+ const docsBase: DocMetadataBase[] = await loadVersionDocsBase({
124
+ tagsFile,
125
+ context,
126
+ options,
127
+ versionMetadata,
128
+ env,
129
+ });
84
130
 
85
- const sidebars = await loadSidebars(versionMetadata.sidebarFilePath, {
86
- sidebarItemsGenerator: options.sidebarItemsGenerator,
87
- numberPrefixParser: options.numberPrefixParser,
88
- docs,
89
- drafts,
90
- version: versionMetadata,
91
- sidebarOptions: {
92
- sidebarCollapsed: options.sidebarCollapsed,
93
- sidebarCollapsible: options.sidebarCollapsible,
94
- },
95
- categoryLabelSlugger: createSlugger(),
96
- });
131
+ // TODO we only ever need draftIds in further code, not full draft items
132
+ // To simplify and prevent mistakes, avoid exposing draft
133
+ // replace draft=>draftIds in content loaded
134
+ const [drafts, docs] = _.partition(docsBase, (doc) => doc.draft);
97
135
 
98
- const sidebarsUtils = createSidebarsUtils(sidebars);
136
+ const sidebars = await loadSidebars(versionMetadata.sidebarFilePath, {
137
+ sidebarItemsGenerator: options.sidebarItemsGenerator,
138
+ numberPrefixParser: options.numberPrefixParser,
139
+ docs,
140
+ drafts,
141
+ version: versionMetadata,
142
+ sidebarOptions: {
143
+ sidebarCollapsed: options.sidebarCollapsed,
144
+ sidebarCollapsible: options.sidebarCollapsible,
145
+ },
146
+ categoryLabelSlugger: createSlugger(),
147
+ });
99
148
 
100
- const docsById = createDocsByIdIndex(docs);
101
- const allDocIds = Object.keys(docsById);
149
+ const sidebarsUtils = createSidebarsUtils(sidebars);
102
150
 
103
- sidebarsUtils.checkLegacyVersionedSidebarNames({
104
- sidebarFilePath: versionMetadata.sidebarFilePath as string,
105
- versionMetadata,
106
- });
107
- sidebarsUtils.checkSidebarsDocIds({
108
- allDocIds,
109
- sidebarFilePath: versionMetadata.sidebarFilePath as string,
110
- versionMetadata,
111
- });
151
+ const docsById = createDocsByIdIndex(docs);
152
+ const allDocIds = Object.keys(docsById);
112
153
 
113
- return {
114
- ...versionMetadata,
115
- docs: addDocNavigation({
116
- docs,
117
- sidebarsUtils,
118
- }),
119
- drafts,
120
- sidebars,
121
- };
122
- }
154
+ sidebarsUtils.checkLegacyVersionedSidebarNames({
155
+ sidebarFilePath: versionMetadata.sidebarFilePath as string,
156
+ versionMetadata,
157
+ });
158
+ sidebarsUtils.checkSidebarsDocIds({
159
+ allDocIds,
160
+ sidebarFilePath: versionMetadata.sidebarFilePath as string,
161
+ versionMetadata,
162
+ });
163
+
164
+ return {
165
+ ...versionMetadata,
166
+ docs: addDocNavigation({
167
+ docs,
168
+ sidebarsUtils,
169
+ }),
170
+ drafts,
171
+ sidebars,
172
+ };
173
+ }
123
174
 
175
+ export async function loadVersion(
176
+ params: LoadVersionParams,
177
+ ): Promise<LoadedVersion> {
124
178
  try {
125
- return await doLoadVersion();
179
+ return await doLoadVersion(params);
126
180
  } catch (err) {
127
- logger.error`Loading of version failed for version name=${versionMetadata.versionName}`;
181
+ // TODO use error cause (but need to refactor many tests)
182
+ logger.error`Loading of version failed for version name=${params.versionMetadata.versionName}`;
128
183
  throw err;
129
184
  }
130
185
  }
@@ -50,33 +50,47 @@ function getVersionEditUrls({
50
50
  return {editUrl: undefined, editUrlLocalized: undefined};
51
51
  }
52
52
 
53
- const editDirPath = options.editCurrentVersion ? options.path : contentPath;
54
- const editDirPathLocalized = options.editCurrentVersion
55
- ? getDocsDirPathLocalized({
56
- localizationDir: context.localizationDir,
57
- versionName: CURRENT_VERSION_NAME,
58
- pluginId: options.id,
59
- })
60
- : contentPathLocalized;
53
+ // Intermediate var just to please TS not narrowing to "string"
54
+ const editUrlOption = options.editUrl;
61
55
 
62
- const versionPathSegment = posixPath(
63
- path.relative(context.siteDir, path.resolve(context.siteDir, editDirPath)),
64
- );
65
- const versionPathSegmentLocalized = posixPath(
66
- path.relative(
67
- context.siteDir,
68
- path.resolve(context.siteDir, editDirPathLocalized),
69
- ),
70
- );
56
+ const getEditUrl = () => {
57
+ const editDirPath = options.editCurrentVersion ? options.path : contentPath;
58
+
59
+ return normalizeUrl([
60
+ editUrlOption,
61
+ posixPath(
62
+ path.relative(
63
+ context.siteDir,
64
+ path.resolve(context.siteDir, editDirPath),
65
+ ),
66
+ ),
67
+ ]);
68
+ };
71
69
 
72
- const editUrl = normalizeUrl([options.editUrl, versionPathSegment]);
70
+ const getEditUrlLocalized = () => {
71
+ if (!contentPathLocalized) {
72
+ return undefined;
73
+ }
74
+ const editDirPathLocalized = options.editCurrentVersion
75
+ ? getDocsDirPathLocalized({
76
+ localizationDir: context.localizationDir,
77
+ versionName: CURRENT_VERSION_NAME,
78
+ pluginId: options.id,
79
+ })
80
+ : contentPathLocalized;
73
81
 
74
- const editUrlLocalized = normalizeUrl([
75
- options.editUrl,
76
- versionPathSegmentLocalized,
77
- ]);
82
+ return normalizeUrl([
83
+ editUrlOption,
84
+ posixPath(
85
+ path.relative(
86
+ context.siteDir,
87
+ path.resolve(context.siteDir, editDirPathLocalized),
88
+ ),
89
+ ),
90
+ ]);
91
+ };
78
92
 
79
- return {editUrl, editUrlLocalized};
93
+ return {editUrl: getEditUrl(), editUrlLocalized: getEditUrlLocalized()};
80
94
  }
81
95
 
82
96
  /**