Skip to content

Commit a12de33

Browse files
committed
feat: add urlBlacklist to gatsby-plugin-intl
1 parent 8075089 commit a12de33

File tree

2 files changed

+125
-16
lines changed

2 files changed

+125
-16
lines changed

gatsby-config.ts

Lines changed: 10 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -62,37 +62,33 @@ const config: GatsbyConfig = {
6262
locale: 'en-US',
6363
prefix: 'en',
6464
messages: messagesByLocale['en-US'], // <-- plain object from TS
65-
slugs: {},
66-
pageBlacklist: ['/cms/', '/cms/pages/', '/cms/media/', '/cms/media/', '/cms/settings/'],
65+
slugs: {}
6766
},
6867
{
6968
locale: 'de-AT',
7069
prefix: 'de',
7170
messages: messagesByLocale['de-AT'],
72-
slugs: {},
73-
pageBlacklist: ['/cms/', '/cms/pages/', '/cms/media/', '/cms/media/', '/cms/settings/'],
71+
slugs: {}
7472
},
7573
{
7674
locale: 'tr-TR',
7775
prefix: 'tr',
7876
messages: messagesByLocale['tr-TR'],
79-
slugs: {},
80-
pageBlacklist: ['/cms/', '/cms/pages/', '/cms/media/', '/cms/media/', '/cms/settings/'],
77+
slugs: {}
8178
},
8279
{
8380
locale: 'ar-EG',
8481
prefix: 'ar',
8582
messages: messagesByLocale['ar-EG'],
86-
slugs: {},
87-
pageBlacklist: ['/cms/', '/cms/pages/', '/cms/media/', '/cms/media/', '/cms/settings/'],
83+
slugs: {}
8884
}
8985
],
90-
// omit certain path segments (relative directories)
91-
pathBlacklist: [
92-
'/pages/cms', // /pages/products/gummibears/ becomes /products/gummibears/
93-
'/pages/login',
94-
'/pages/mailpress',
95-
],
86+
// omit certain path and subpaths segments from translation (urls not relative directories)
87+
// urlBlacklist: [
88+
// '/cms',
89+
// '/login',
90+
// '/mailpress',
91+
// ],
9692
trailingSlash: 'always'
9793
}
9894
}

gatsby-node.ts

Lines changed: 115 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,65 @@ import path from 'path';
44
import fs from 'fs';
55
import { buildSearchIndex } from './src/utils/search/build-search-index';
66

7+
/** ----- i18n translation-removal + Jaen recreation config ----- */
8+
const DEFAULT_LOCALE = 'en-US';
9+
/** These are the locale URL prefixes you configured in gatsby-plugin-i18n-l10n */
10+
const LOCALE_PREFIXES = ['en', 'de', 'tr', 'ar'];
11+
/** Remove *translations* for these URL roots (and all their children) */
12+
const URL_BLACKLIST = ['/cms/', '/login/', '/mailpress/', '/settings/', '/logout/'];
13+
14+
/** Normalize path to have leading slash, no duplicate slashes */
15+
const normalizePath = (p: string) => {
16+
if (!p) return '/';
17+
let s = p.trim();
18+
if (!s.startsWith('/')) s = '/' + s;
19+
// collapse multiple slashes
20+
s = s.replace(/\/{2,}/g, '/');
21+
return s;
22+
};
23+
24+
/** Strip any known locale prefix like /de or /tr from the start of the path */
25+
const stripLocalePrefix = (p: string) => {
26+
const norm = normalizePath(p);
27+
// build regex like ^/(en|de|tr|ar)(/|$)
28+
const re = new RegExp(`^/(?:${LOCALE_PREFIXES.join('|')})(?=/|$)`, 'i');
29+
const stripped = norm.replace(re, '');
30+
return stripped || '/';
31+
};
32+
33+
/** True if path is under any blacklisted URL root (exact or child) */
34+
const isUnderBlacklistedRoot = (p: string) => {
35+
const norm = normalizePath(p);
36+
// drop trailing slash for compare
37+
const trimmed = norm.replace(/\/+$/, '');
38+
return URL_BLACKLIST.some(root => {
39+
const r = normalizePath(root).replace(/\/+$/, '');
40+
return trimmed === r || trimmed.startsWith(r + '/');
41+
});
42+
};
43+
44+
const detectLocaleFromPath = (p: string): string | undefined => {
45+
const norm = normalizePath(p);
46+
const seg = norm.split('/')[1]; // first segment after leading slash
47+
return LOCALE_PREFIXES.includes(seg) ? seg : undefined;
48+
};
49+
50+
/** Try to detect locale from page.context or from URL */
51+
const getPageLocale = (page: any): string | undefined => {
52+
const ctx = page?.context ?? {};
53+
return (
54+
ctx.locale ??
55+
ctx.language ??
56+
ctx.lang ??
57+
ctx?.i18n?.locale ??
58+
ctx?.intl?.locale ??
59+
ctx?.intl?.language ??
60+
detectLocaleFromPath(page.path)
61+
);
62+
};
63+
64+
/** ----------------------------------------------------- */
65+
766
export const onCreateWebpackConfig: GatsbyNode['onCreateWebpackConfig'] = ({
867
actions
968
}) => {
@@ -16,6 +75,62 @@ export const onCreateWebpackConfig: GatsbyNode['onCreateWebpackConfig'] = ({
1675
});
1776
};
1877

78+
/**
79+
* Goal:
80+
* - Recreate every *non-blacklisted* page (default + translated) as a Jaen page so metadata is editable per locale.
81+
* - For blacklisted URL roots, keep default locale and remove translations.
82+
* - Use a per-locale stable Jaen id: `path:<path-without-locale>::<locale>`
83+
* - Avoid infinite loops with `__jaenRecreated`.
84+
*/
85+
export const onCreatePage: GatsbyNode['onCreatePage'] = async ({ page, actions }) => {
86+
const { deletePage, createPage } = actions;
87+
88+
// Prevent infinite reprocessing
89+
if ((page.context as any)?.__jaenRecreated) {
90+
return;
91+
}
92+
93+
const locale = getPageLocale(page) || DEFAULT_LOCALE;
94+
const isTranslated = locale !== DEFAULT_LOCALE;
95+
96+
// figure out the effective "base" path without locale prefix
97+
const pathNoLocale = stripLocalePrefix(page.path);
98+
const matchNoLocale = page.matchPath ? stripLocalePrefix(page.matchPath) : undefined;
99+
100+
const isBlacklisted =
101+
isUnderBlacklistedRoot(pathNoLocale) ||
102+
(matchNoLocale && isUnderBlacklistedRoot(matchNoLocale));
103+
104+
// 1) Blacklisted: keep default, remove translations; don't recreate
105+
if (isBlacklisted) {
106+
if (isTranslated) {
107+
deletePage(page);
108+
}
109+
return;
110+
}
111+
112+
// 2) Not blacklisted: recreate **every** locale (default + translated) as a Jaen page
113+
// Per-locale Jaen id so each locale has its own editable metadata
114+
const stableJaenId = `path:${pathNoLocale}::${locale}`;
115+
116+
// Recreate with augmented context for Jaen
117+
deletePage(page);
118+
createPage({
119+
...page,
120+
context: {
121+
...page.context,
122+
__jaenRecreated: true,
123+
locale,
124+
// Jaen identifiers; keep both keys for compatibility
125+
jaenPageId: stableJaenId,
126+
jaenId: stableJaenId,
127+
// useful helper if you need to map back to base path in components
128+
originalPath: pathNoLocale,
129+
...(matchNoLocale ? { matchPathNoLocale: matchNoLocale } : {})
130+
}
131+
});
132+
};
133+
19134
export const onPostBuild: GatsbyNode['onPostBuild'] = async ({
20135
graphql,
21136
reporter
@@ -82,7 +197,6 @@ export const onPostBuild: GatsbyNode['onPostBuild'] = async ({
82197
reporter.panicOnBuild(
83198
`Error while running GraphQL query. ${result.errors}`
84199
);
85-
86200
return;
87201
}
88202

@@ -121,7 +235,6 @@ async function preparePagesAndBuildSearch(allJaenPage: {
121235
const originPath = node.buildPath;
122236

123237
let type = node.template;
124-
125238
if (type && path.extname(type)) {
126239
type = path.basename(type, path.extname(type));
127240
}

0 commit comments

Comments
 (0)