Skip to content

Commit 0c4615f

Browse files
committed
feat: add trailing slashes to sidebar, breadcrumbs, top level links and hreflang tag
1 parent b4f121a commit 0c4615f

File tree

3 files changed

+33
-26
lines changed

3 files changed

+33
-26
lines changed

gatsby-node.js

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ const {
1818
getDocSection,
1919
buildBreadcrumbs,
2020
dedupePath,
21-
noTrailingSlash,
21+
addTrailingSlash,
2222
removeEnPrefix,
2323
translatePath,
2424
getSlug,
@@ -179,7 +179,7 @@ function getSupplementaryPagesProps({
179179
return {
180180
path: compose(
181181
removeEnPrefix,
182-
noTrailingSlash,
182+
addTrailingSlash,
183183
dedupePath,
184184
slugify,
185185
)(path),
@@ -222,15 +222,16 @@ function getSupplementaryPagesProps({
222222
return {
223223
path: compose(
224224
removeEnPrefix,
225-
noTrailingSlash,
225+
addTrailingSlash,
226226
dedupePath,
227227
slugify,
228228
)(path),
229229
component: Path.resolve('./src/templates/docs/breadcrumb-stub.js'),
230230
context: {
231231
sidebarTree: getGuidesSidebar(locale),
232232
breadcrumbs: breadcrumbs.filter(
233-
(item) => !SUPPORTED_LOCALES.includes(item.path.replace('/', '')),
233+
(item) =>
234+
!SUPPORTED_LOCALES.includes(item.path.replace(/\//g, '')),
234235
),
235236
title: meta.title,
236237
navLinks: generateTopLevelLinks(topLevelLinks),
@@ -273,7 +274,7 @@ function getTopLevelPagesProps({
273274
}
274275

275276
return {
276-
path: slug === 'guides' ? `/` : `/${slug}`,
277+
path: slug === 'guides' ? `/` : `/${slug}/`,
277278
component: Path.resolve(`./src/templates/docs/${slug}.js`),
278279
context: {
279280
sidebarTree: getSidebar(name),
@@ -283,7 +284,7 @@ function getTopLevelPagesProps({
283284
})
284285
.concat(
285286
SUPPORTED_LOCALES.map((locale) => ({
286-
path: locale === 'en' ? '/' : `/${locale}`,
287+
path: locale === 'en' ? '/' : `/${locale}/`,
287288
component: Path.resolve(`./src/templates/docs/guides.js`),
288289
context: {
289290
sidebarTree: getGuidesSidebar(locale),
@@ -332,7 +333,7 @@ function getDocPagesProps({
332333
const strippedDirectory = stripDirectoryPath(relativeDirectory, 'docs');
333334
const path = `${strippedDirectory}/${title.replace(/\//g, '-')}`;
334335

335-
const slug = customSlug || getSlug(path);
336+
const slug = customSlug ? addTrailingSlash(customSlug) : getSlug(path);
336337
// path collision check
337338
if (!pathCollisionDetectorInstance.add({ path: slug, name }).isUnique()) {
338339
// skip the page creation if there is already a page with identical url
@@ -425,7 +426,7 @@ function getGuidesPagesProps({
425426
? getSlug(path)
426427
: getTranslatedSlug(relativeDirectory, title, pageLocale, 'guides');
427428

428-
const pageSlug = customSlug || slug;
429+
const pageSlug = customSlug ? addTrailingSlash(customSlug) : slug;
429430

430431
// path collision check
431432
if (!pathCollisionDetectorInstance.add({ path: slug, name }).isUnique()) {
@@ -480,7 +481,7 @@ function getGuidesPagesProps({
480481
remarkNode: extendedRemarkNode,
481482
sidebarTree,
482483
breadcrumbs: breadcrumbs.filter(
483-
(item) => !SUPPORTED_LOCALES.includes(item.path.replace('/', '')),
484+
(item) => !SUPPORTED_LOCALES.includes(item.path.replace(/\//g, '')),
484485
),
485486
navLinks: generateTopLevelLinks(topLevelLinks),
486487
locale: pageLocale,
@@ -594,7 +595,7 @@ async function createDocPages({
594595
.filter((name) => name !== 'Cloud REST API')
595596
.map((name) => ({
596597
label: name === 'cloud' ? 'Cloud Docs' : name.toUpperCase(),
597-
to: name === 'guides' ? `/` : `/${slugify(name)}`,
598+
to: name === 'guides' ? `/` : `/${slugify(name)}/`,
598599
}));
599600

600601
getDocPagesProps({
@@ -634,14 +635,14 @@ const createRedirects = ({ actions }) => {
634635
const { createRedirect } = actions;
635636

636637
createRedirect({
637-
fromPath: '/getting-started/welcome',
638+
fromPath: '/getting-started/welcome/',
638639
toPath: '/',
639640
redirectInBrowser: true,
640641
isPermanent: true,
641642
});
642643
createRedirect({
643-
fromPath: '/es/empezando/bienvenido',
644-
toPath: '/es',
644+
fromPath: '/es/empezando/bienvenido/',
645+
toPath: '/es/',
645646
redirectInBrowser: true,
646647
isPermanent: true,
647648
});

src/components/shared/seo/seo.view.js

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -49,13 +49,13 @@ export const SEO = ({
4949
let esPathname = pageTranslations.es.path;
5050
let enPathname = pageTranslations.en.path;
5151

52-
if (esPathname.endsWith('/')) {
53-
// gatsby-plugin-react-helmet-canonical-urls.noTrailingSlash
54-
esPathname = esPathname.substring(0, esPathname.length - 1);
52+
if (!esPathname.endsWith('/')) {
53+
// make sure each link has trailing slash
54+
esPathname = `${esPathname}/`;
5555
}
56-
if (enPathname.endsWith('/')) {
57-
// gatsby-plugin-react-helmet-canonical-urls.noTrailingSlash
58-
enPathname = enPathname.substring(0, enPathname.length - 1);
56+
if (!enPathname.endsWith('/')) {
57+
// make sure each link has trailing slash
58+
enPathname = `${enPathname}/`;
5959
}
6060
hrefLangAttributes.es.href += esPathname;
6161
hrefLangAttributes.en.href += enPathname;

src/utils/utils.node.js

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,13 @@ const DEFAULT_LOCALE = 'en';
99
// create a container;
1010
const utils = {};
1111

12+
// ensures that no trailing slash is left
13+
const noTrailingSlash = (path) =>
14+
path === '/' ? '/' : path.replace(/(.+)\/$/, '$1');
15+
16+
// ensures that path has a trailing slash
17+
const addTrailingSlash = (path) => path.replace(/\/$|$/, `/`);
18+
1219
const translatePathPart = (item, locale) => {
1320
if (
1421
typeof pathTranslations[item] !== 'undefined' &&
@@ -44,7 +51,7 @@ const buildBreadcrumbs = (path) => {
4451
}
4552
return {
4653
name,
47-
path: slug,
54+
path: addTrailingSlash(slug),
4855
};
4956
});
5057
};
@@ -205,14 +212,10 @@ const redirectWelcome = (path) =>
205212
.replace(/en\/getting-started\/welcome/i, '')
206213
.replace(/empezando\/bienvenido/i, '');
207214

208-
// ensures that no trailing slash is left
209-
const noTrailingSlash = (path) =>
210-
path === '/' ? '/' : path.replace(/(.+)\/$/, '$1');
211-
212215
const getSlug = (path) => {
213216
const slug = compose(
214217
removeEnPrefix,
215-
noTrailingSlash,
218+
addTrailingSlash,
216219
redirectWelcome,
217220
dedupePath,
218221
unorderify,
@@ -234,7 +237,7 @@ const getTranslatedSlug = (
234237
const translatedPath = translatePath(path, locale);
235238

236239
const slug = compose(
237-
noTrailingSlash,
240+
addTrailingSlash,
238241
redirectWelcome,
239242
dedupePath,
240243
slugify,
@@ -244,6 +247,9 @@ const getTranslatedSlug = (
244247
};
245248

246249
Object.defineProperties(utils, {
250+
addTrailingSlash: {
251+
value: addTrailingSlash,
252+
},
247253
noTrailingSlash: {
248254
value: noTrailingSlash,
249255
},

0 commit comments

Comments
 (0)