Open LorisSigrist opened 5 months ago
Hi Loris, Thanks for writing.
(Context: I still need to read up on Paraglide, but want to respond to help advance the thinking on this too.)
This problem isn't exclusive to Paraglide. With the new reroute hook added in SvelteKit 2.3 any route could get rendered from any path. In order to provide a Sitemap here, users will need a config point / hook where they can generate all possible URLs that point to a given route + params.
Yeah, this is the crux to overcome, especially given paraglide allows changing path text per language.
I agree that doing more within hooks seems necessary in a reroute
-enabled SvelteKit world.
Perhaps something like a i18n.getAlternateLinks: (routeId, params) => ({ href, hreflang })[] function could work?
On the right track, but needs a bit more data:
the routeId should be included as part of the response.
I imagine an object structure will be necessary, where with each key is a unique routeId and its value is probably an array of objects like you have, each representing a specific path (e.g. /about), with a separate object for every other language version of that path too. Why do we need the routeId? It would allow Super Sitemap to do further processing on all paths for a given routeId, such as adding supplementary data like image or video sitemap extension data for every path generated for a given route. (A feature that does not yet exist in SuperSitemap, and won't unless there's demand, but I'd like to stay flexible enough to implement it.)
each path object must also contain info for its "sibling" paths (I'm making up that term) that are in alternate languages.
For example, to generate:
<url>
<loc>https://example.com/about</loc>
<xhtml:link rel="alternate" hreflang="en" href="https://example.com/about" />
<xhtml:link rel="alternate" hreflang="zh" href="https://example.com/zh/about" />
<xhtml:link rel="alternate" hreflang="de" href="https://example.com/de/about" />
</url>
Although, iirc Paraglide will be adding alternate tags to the page HTML header, is that right? I'd need to double check the sitemap spec, but that might be sufficient and could remove the need for the above within the sitemap XML itself, if it's sufficiently handled within the page HTML.
Questions:
Those are my initial thoughts. Thanks again for writing.
Your envisioned method would do all replacements of paramValues for parameterized routes, correct?
Paraglide doesn't need the params just the resolved path would be fine, but I can imagine that other i18n solutions will want the params
, so I suggested it.
Although, iirc Paraglide will be adding alternate tags to the page HTML header, is that right? I'd need to double check the sitemap spec, but that might be sufficient and could remove the need for the above within the sitemap XML itself, if it's sufficiently handled within the page HTML.
Yes, Paraglide adds <link alternate...
tags to the <head>
of the page. Is that sufficient to replace a sitemap?
I have a feeling that even if this is technically ok, people are going to keep asking.
the routeId should be included as part of the response.
I'm not sure I understand the need for this. My suggested hook would map a routeId
to all the paths that would get reroute
d to that routeId
. Isn't the routeId the same for all returned paths?
Would you envision it to return fully formed paths for ALL routes or only certain paths where paraglide is enabled? The former would be cleaner for Super Sitemap, rather than receiving only a subset from it and then still reading routes from disk and de-duplicating on routeIds, but either way could work.
If it's easier for you we can return fully formed paths for all routes. That being said, reroute
gives you the option to not return anything, which will cause the default route-resolution behaviour. Perhaps you want some conceptual symmetry there? Either way is fine for paraglide.
To be sure we're on the same page:
i18n.getAlternateLinks: (routeId, params) => ({ href, hreflang })[]
) would be created and exported by Paraglide? Your method is suggested because b/c Paraglide can change a route in unexpected ways now, using reroute (/about
-> /acerca
). Correct?/blog/[slug]
where a different array of slug paramValues are used per different language)Why do we need the routeId? It would allow Super Sitemap to do further processing on all paths for a given routeId, such as adding supplementary data like image or video sitemap extension data for every path generated for a given route. (A feature that does not yet exist in SuperSitemap, and won't unless there's demand, but I'd like to stay flexible enough to implement it.)
I'm not sure I understand the need for this
See the quote. SuperSitemap needs the opportunity to do further processing on all paths associated with a given route, to add data like lastmod
, image & video data for those sitemap extensions, etc.
__
If i18n.getAlternateLinks()
is called once per route, then we implicitly know what route all paths returned from it are associated with, and that's fine. But we should probably name it i18n.getPaths(route, params)
since it's actually telling us what the paths or urls are for the route too, since we can't make any assumptions about that following predictable pattern now.
But since we need paths for all routes, and only Paraglide knows the routing logic in this world, wouldn't it be best to have a function like i18n.getAllPaths()
to return object values for each path grouped by the unique route?
When only Paraglide can be aware of its routing logic, it also needs to take care of param replacement too to generate the paths for the sitemap.
Yes, Paraglide adds <link alternate... tags to the
of the page. Is that sufficient to replace a sitemap? I have a feeling that even if this is technically ok, people are going to keep asking.
Let's revisit this to decide later.
hreflang
is not actually part of the Sitemap 1.0 protocol–if you search it for hreflang
, there are no results.
It exists, afaik, because of Google's suggestion for how to handle alternate language versions of a page, which there are two ways that are equally valid for Google, see the link.
But let's come back to this later.
This sounds likely to get to get extremely complex
This sounds likely to get to get extremely complex
It will certainly add complexity, but hopefully not too much. When reroute
was initially proposed, it had a sister-hook called resolveDestination
, which would basically do the reverse mapping (sveltejs/kit#11223). AFAICT this is close to what's needed here.
I'll try my best to answer your questions:
your proposed function (i18n.getAlternateLinks: (routeId, params) => ({ href, hreflang })[]) would be created and exported by Paraglide? Your method is suggested because b/c Paraglide can change a route in unexpected ways now, using reroute (/about -> /acerca). Correct?
The implementation for the hook could be provided by Paraglide, yes, but super-sitemap
would need to offer a place to use it. Paraglide's imlementation can be adjusted to whatever works for super-sitemap
, so I wouldn't worry too much. If you can find a solution for the general reroute
case, not just i18n routing, Paraglide will be able to work with it.
Will Paraglide enable translating dynamic routes? (e.g. /blog/[slug] where a different array of slug paramValues are used per different language)
Paraglide does support Params in translated paths, but all languages must have the same set of params. Otherwise params would get lost in translation (imagine switching from a language with two params to a language with one, and the back. That just doesn't work).
Do you plan for Paraglide to support translations on alternate subdomains too?
Currently no
i18n.getPaths(route, params)
I like this suggestion much more than getAllPaths
. With getAllPaths
you would somehow need to pass the entire routing configuration (all routeIds + params) as a parameter. However, the reverse-mapping of reroute
only ever depends on a single routeId + params, so everyone using this hook will just manually iterate over the routes + params and call an inner-function that's basically just i18n.getPaths(route, params)
. I don't see why super-sitemap
can't do this iteration itself & just call i18n.getPaths(route, params)
directly.
Yes, Paraglide adds <link alternate... tags to the of the page. Is that sufficient to replace a sitemap? I have a feeling that even if this is technically ok, people are going to keep asking.
Let's revisit this to decide later.
Sounds good
Thanks for all the careful thought you clearly put into this, this library is incredibly valuable for the Svelte community. Let's find the best solution here!
Is there any update on this?
The update: I would like to see either 1.) this implemented by SvelteKit (i.e. the ability to programmatically get all routes), which is most ideal by far, or 2.) for Paraglide to become the i18n solution recommended by the Svelte core team in the docs before completely rewriting super-sitemap.
The reality that this will require a major rewrite of super-sitemap despite any assertions to the contrary (b/c it is currently based on Vite's import.meta.glob
for gathering paths).
But that said, if anyone feels it can be done easily, and has looked through super-sitemap's code to support this and are willing to code it, I'm very open to receiving an RFC to discuss and PR with implementation!
Hi, Paraglide Maintainer here
We recently released
@inlang/paraglide-js-adapter-sveltekit
(docs) which enables some very powerful i18n routing. As pointed out in #22, some of the features / design choices throw some curveballs forsuper-sitemap
. Namely:[[lang]]
parameter in theroutes
With this, it's no longer possible to determine all routes based purely on the filesystem.
This problem isn't exclusive to Paraglide. With the new
reroute
hook added in SvelteKit 2.3 any route could get rendered from any path. In order to provide a Sitemap here, users will need a config point / hook where they can generate all possible URLs that point to a given route + params.i18n routing is a special case of that, since you don't only need the path, but also the language of the page. The route mapping from
(routeId, params) => ({ href, hreflang })[]
, can easily be implemented in userland. What would be needed fromsuper-sitemap
is a hook / config point where that mapping can be used.Perhaps something like a
i18n.getAlternateLinks: (routeId, params) => ({ href, hreflang })[]
function could work?