diff --git a/.changeset/rewrite-routes-exclude.md b/.changeset/rewrite-routes-exclude.md new file mode 100644 index 00000000000..c88f68a2c7d --- /dev/null +++ b/.changeset/rewrite-routes-exclude.md @@ -0,0 +1,5 @@ +--- +'@qwik.dev/router': minor +--- + +feat(router): add an `exclude` option to `rewriteRoutes` to skip generating localized routes for matching path patterns. diff --git a/packages/docs/src/routes/docs/(qwikrouter)/routing/index.mdx b/packages/docs/src/routes/docs/(qwikrouter)/routing/index.mdx index ceb884c1015..5d12004425c 100644 --- a/packages/docs/src/routes/docs/(qwikrouter)/routing/index.mdx +++ b/packages/docs/src/routes/docs/(qwikrouter)/routing/index.mdx @@ -428,6 +428,22 @@ export default defineConfig(async () => { }); ``` +By default a config rewrites every matching route. Add `exclude` to skip routes that should not be rewritten under that config. The patterns use the same glob syntax as the SSG `include`/`exclude` and are matched per config: + +```tsx +rewriteRoutes: [ + { + prefix: 'it', + paths: { + 'docs': 'documentazione', + 'products': 'prodotti', + }, + // `/blog` stays English-only: no `/it` mirror is generated for it. + exclude: ['/blog/*'], + }, +], +``` + ## Advanced routing Qwik Router also supports: diff --git a/packages/qwik-router/src/buildtime/build-pages-rewrited.unit.ts b/packages/qwik-router/src/buildtime/build-pages-rewrited.unit.ts index 90610492bac..3af18235189 100644 --- a/packages/qwik-router/src/buildtime/build-pages-rewrited.unit.ts +++ b/packages/qwik-router/src/buildtime/build-pages-rewrited.unit.ts @@ -333,3 +333,14 @@ testSameRoutes( assert.equal(r.pathname, '/produkt/'); } ); + +const testExclude = testAppSuite('Rewrite routes with exclude', { + rewriteRoutes: [{ prefix: 'it', paths: {}, exclude: ['/docs/*'] }], +}); + +testExclude('exclude skips localized mirrors for matched routes', ({ ctx }) => { + const it = ctx.routeTrie.children.get('it'); + assert.ok(it, 'prefix mirror "it" should exist for non-excluded routes'); + assert.ok(it!.children.get('about-us'), 'non-excluded route is mirrored under "it"'); + assert.is(it!.children.get('docs'), undefined, '"/docs/*" is excluded from the "it" mirror'); +}); diff --git a/packages/qwik-router/src/buildtime/build.ts b/packages/qwik-router/src/buildtime/build.ts index b6e2a6fe057..3187e82de51 100644 --- a/packages/qwik-router/src/buildtime/build.ts +++ b/packages/qwik-router/src/buildtime/build.ts @@ -1,6 +1,7 @@ import { addError, addWarning } from '../utils/format'; import { createFileId, getPathnameFromDirPath } from '../utils/fs'; import { ensureSlash } from '../utils/pathname'; +import { createRouteTester } from '../ssg/routes'; import { resolveMenu } from './markdown/menu'; import { resolveLayout, resolveRoute } from './routing/resolve-source-file'; import { routeSortCompare } from './routing/sort-routes'; @@ -323,8 +324,15 @@ function applyRewriteRoutes(root: BuildTrieNode, rewriteConfigs: RewriteRouteOpt for (const config of rewriteConfigs) { const translations = config.paths || {}; const translatable = new Set(Object.keys(translations).map((k) => k.toLowerCase())); + const isExcluded = config.exclude?.length + ? createRouteTester('/', config.exclude, undefined) + : undefined; for (const { steps } of routables) { + const originalKeyPath = steps.map((s) => s.key).join('/'); + if (isExcluded?.('/' + originalKeyPath)) { + continue; + } // Check if any segment is translatable or if there's a prefix const hasTranslatable = steps.some((s) => translatable.has(s.key)); if (!hasTranslatable && !config.prefix) { @@ -335,9 +343,6 @@ function applyRewriteRoutes(root: BuildTrieNode, rewriteConfigs: RewriteRouteOpt continue; } - // Build the original key path - const originalKeyPath = steps.map((s) => s.key).join('/'); - // Build translated steps const translatedSteps: TriePathStep[] = []; diff --git a/packages/qwik-router/src/buildtime/types.ts b/packages/qwik-router/src/buildtime/types.ts index 22c443f59bd..4d7f9708da6 100644 --- a/packages/qwik-router/src/buildtime/types.ts +++ b/packages/qwik-router/src/buildtime/types.ts @@ -135,6 +135,7 @@ export interface ParsedMenuItem { export interface RewriteRouteOption { prefix?: string; paths: Record; + exclude?: string[]; } /** @public */