kit
kit copied to clipboard
Optional route parameters
Describe the problem
I'm trying to add multiple languages to a site with a leading /[locale]/...
route parameter.
There are two things that I cannot do right now without much overhead:
-
Having a default locale that has NO
[locale]
prefix. This would currently involve copying everything under/[locale]
to/
as well. Using/[...locale]
does not work either, because a/[...locale]/[...slug]
would not match correctly for many cases. -
When using
adapter-static
and pre-rendering all routes, only routes picked up through crawling links will be rendered behind/[locale]
. Usingkit.prerender.entries: ["*", "/de/something"]
will only pre-render/de/something
but nothing else.
Describe the proposed solution
-
Add optional parameters with e.g.
[locale?]
syntax -
Allow more wildcards in
kit.prerender.entries
, like/de/*
Alternatives considered
No response
Importance
would make my life easier
Additional Information
No response
How would you have /[locale?]/[...slug]
match? That seems to fall into the same problem as /[...locale]/[...slug]
.
How would you have
/[locale?]/[...slug]
match? That seems to fall into the same problem as/[...locale]/[...slug]
.
Without a matcher, you are right. So maybe the way the matcher is called should be changed. Right now, for an url /about/me
and a matcher that accepts empty string or two characters, the matcher is only called for "about/me" and the route is discarded.
For the route /[...locale:matcher]/[...slug]
, parts of the url should be tested as well, also the case where locale is empty.
Depending on the matcher, there might be multiple ways an url can be matched when there are more than one rest parameters. I suggest to match the first rest param with as much from the path as possible and then continue to the right.
Looking at the source code, this is not easy because the route's regex match takes place before the matchers are called in exec
. Maybe an optional regex defined with the matcher could override the default regex for a parameter?
If I were to tackle this problem of multiple languages, I'd probably do a "multibuild". For each language, build with some environment variable setting the language, then put all those build folders under one parent folder, something like this pseudocode:
['en', 'es', 'fr', 'zh'].forEach(lang => {
VITE_LANG=${lang} npm run build
mv /build/* /megabuild/${lang}
})
Just an idea. Might be tricky to get the asset paths right. And you'd need some smart rewriting in your web server.
What about adding a prefix before local as following.
/la/something
for default
/la-en/something
for english and so on.
How about src/routes/[~locale]/whatever
? ~
is an allowed character, and is often used in text to mean 'ish', which isn't a million miles away from the intent here.
For reference, these are the forbidden characters — everything else is fair game:
< > : " / \ | ? *
Ideally it should be just like any other dynamic parameter, except for the prefix, so that we can do things like this:
[~locale=locale]`
(i.e. we use the locale
parameter matcher, which verifies that it's a valid locale, which allows us to follow it with [x]
or [...y]
without ambiguity.)
Alternatives include these, though most of them have slightly confusing connotations:
[`locale]
[!locale]
[@locale]
[$locale]
[%locale]
[^locale]
[-locale]
[=locale]
[.locale]
[(locale)]
[[locale]]
I'd like to use an optional route parameter, but for a different use case than adding an optional local in the path. I'd like to have URL like /my-page[optional-variant=matcher]
which could match /my-page-var1
, my-page-var2
, but also /my-page
without the optional variant. Currently I have to define 2 identical routes, one with the parameter and one without it.
(This is of course doable by using a query param to define the page variants, but I prefer to use this schema because I already use query params for another feature of my pages)
I'd like to use an optional route parameter, but for a different use case than adding an optional local in the path. I'd like to have URL like
/my-page[optional-variant=matcher]
which could match/my-page-var1
,my-page-var2
, but also/my-page
without the optional variant. Currently I have to define 2 identical routes, one with the parameter and one without it.(This is of course doable by using a query param to define the page variants, but I prefer to use this schema because I already use query params for another feature of my pages)
I think that is already possible with the current matchers (not tested).
// src/params/my-page.js
/** @type {import('@sveltejs/kit').ParamMatcher */
const regex = /^my-page(-var(\d+))?$/
export function match(param) {
return regex.test(param);
}
/**
* @type {string} param
*/
export function getVariant(params) {
return param["my-page"].match(regex)[2]
}
// src/routes/[my-page=my-page]/+page.js
import { getVariant } from '../../params/my-page'
/** @type {import('./$types').PageLoad */
export function load({ params }) {
const variant = getVariant(params);
return {
variant
}
}
If you visit /my-page-var123
variant will be 123
NextJS uses [[...param]]
for optional catch-all routes, so there's precedence for this syntax. Nuxt uses the same [[param]]
notation for optional params. Feels like an emerging standard, maybe worth going this route.