Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support paraglide i18n routing #24

Open
LorisSigrist opened this issue Jan 26, 2024 · 5 comments
Open

Support paraglide i18n routing #24

LorisSigrist opened this issue Jan 26, 2024 · 5 comments
Labels

Comments

@LorisSigrist
Copy link

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 for super-sitemap. Namely:

  • No [[lang]] parameter in the routes
  • Translated Paths

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 from super-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?

With a mapping like that the current [[lang]] based API wouldn't be necessary anymore, since it could easily be re-implemented with the proposed functionality.

@jasongitmail
Copy link
Owner

jasongitmail commented Jan 28, 2024

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:

  1. 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.)

  2. 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:

  • Your envisioned method would do all replacements of paramValues for parameterized routes, correct?
  • 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.

Those are my initial thoughts. Thanks again for writing.

@LorisSigrist
Copy link
Author

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 rerouted 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.

@jasongitmail
Copy link
Owner

jasongitmail commented Jan 29, 2024

To be sure we're on the same page:

  • 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?
  • Will Paraglide enable translating dynamic routes? (e.g. /blog/[slug] where a different array of slug paramValues are used per different language)
  • Do you plan for Paraglide to support translations on alternate subdomains 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.)

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

@LorisSigrist
Copy link
Author

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!

@jasongitmail jasongitmail changed the title More general i18n routing Support paraglide i18n routing Feb 29, 2024
@IslamZaoui
Copy link

Is there any update on this?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants