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

i18n: localized / translated routes #1130

Closed
wants to merge 4 commits into from

Conversation

pzerelles
Copy link
Contributor

This is now just a part of what #1037 implemented and also in a different way. The goal was to make alternate routes for the same page configurable.

There is a new configuration property "alternateRoutes" in the "kit" section of svelte.config.cjs. It optionally takes a function that receives a page's Part[][] and returns Part[][][], so the routes can be multiplied and the segments in Part[][] changed. This can be used e.g. to translate the routes or add a locale prefix.

Since the router has all the routes on the client, there is an alternates() function in "$app/navigation" that will return all alternate paths of a path. This is useful for language choosers for example.

I also added a usage example to "examples/svelte-kit-demo". Currently no translation is happening. This can be dealt with using translation libraries like svelte-i18n or svelte-intl-precompile.

@vercel
Copy link

vercel bot commented Apr 19, 2021

@pz-mxu is attempting to deploy a commit to the Svelte Team on Vercel.

A member of the Team first needs to authorize it.

@cibernox
Copy link

cibernox commented Apr 19, 2021

Answering here to some comments in #1037

@pz-mxu

I tried to create an extension point for routes. It currently fails to import svelte-intl-precompile into svelte.config.cjs due to "export * ...". Is there a workaround for that?

Maybe you're importing the runtime library instead of the built time plugin? Check this: https://github.com/cibernox/sveltekit-bug-with-plugin/blob/main/svelte.config.cjs

I know that your api is the same as for svelte-i18n, but if you compile the translations, wouldn't it be nicer to access them as object keys and functions with ts signature maybe? Like {$t.welcome(foo)} instead of {$t("welcome", { name: foo })}

I'm not so sure about that because it's very common for translations to have dashes for word separations (e.g. "header-title") and/or dots for namespacing (e.g. "forms.placeholders.name"), so invoking it with dot syntax would not be possible most of the time.

On that, since this library is the new kid in the block I wanted to make as easy as possible for people to give it a go. Svelte-i18n is by a fair margin the most popular library (and IMO the best too), so I chose to copy (sometimes literally copying chunks of code) from that one. I'm hesitant to come up with a new API when this one is so battle tested already.

@floratmin

First I thought the same, but except for javascript land the de facto standard is gettext. It is a little bit older and quirky but it has a superior workflow and a lot of tooling. When creating a multilingual site the workflow is extremely important. With gettext you get the following:

It's curious, my experience is exactly the opposite. Certainly in web the ICU message format is the most popular on the web (I am yet to see a web app using gettext), but even on android and iphone apps I never saw gettext used. I think I remember seeing it in a java project, but even on java the ICU message format is what I saw the most.

On those projects I worked with translation agencias and they seemed to have al the tooling they needed.

Regardless, the approach of my library is to compile translations into javascript functions ad build time, I think it would be amicable to supporting more than one i18n syntax like gettext or projectfluent, we'd just have to build a different plugin that can compile gettext po files into javascript functions.

@floratmin
Copy link

@cibernox
gettext-to-messageformat compiles .po files to ICU message format and messageformat compiles ICU message format strings to javascript functions. These projects are created by the OpenJS foundation.

@cibernox
Copy link

@floratmin I'm using messageformat already, but I'm using only the parser.

But it's great to know that gettext-to-messageformat can make easier to support gettext too.

@pzerelles
Copy link
Contributor Author

Answering here to some comments in #1037

@pz-mxu

I tried to create an extension point for routes. It currently fails to import svelte-intl-precompile into svelte.config.cjs due to "export * ...". Is there a workaround for that?

Maybe you're importing the runtime library instead of the built time plugin? Check this: https://github.com/cibernox/sveltekit-bug-with-plugin/blob/main/svelte.config.cjs

I didn't mean the import for Vite plugin. When I want to translate route segments with a function that is invoked during manifest creation, I need access to the compiled translations at this point.

@cibernox
Copy link

I may have to give it a go, I didn't consider importing translations from anywhere but application code. If you need to import it at build time for creating a manifest I need to check. If you can create a brach and link me to it I'll check it tonight.

@kobejean
Copy link

I'm really excited to see this work. This is exactly the kind of thing I need to get an i18n app working smoothly. I know this is probably still a work in progress, but I wanted to provide some feedback after playing around with this.

Allow alternativeRoute to work for endpoints

Endpoints are often defined in the same directory as the page that uses it. It would be nice if you allow alternativeRoute to work for endpoints in addition to pages (I've added some proposed code changes here: pzerelles#1 (comment))

Allow dynamic and spread options to work from alternativeRoute

It looks like currently props are processed before alternativeRoute is ever used and because of that the dynamic and spread parameters, when added by alternativeRoute, doesn't work.

const params = parent_params.slice();
params.push(...item.parts.filter((p) => p.dynamic).map((p) => p.content));

it would be nice to have the option to add a dynamic segment like locale as a path parameter by doing something like:

alternateRoutes: (segments) => {
	return [
		segments,
		// Ex. /{locale}/rest/of/path
		[
			[{ content: "locale", dynamic: true, spread: false }],
			...segments
		]
	];
}

Ease of Use

I honestly am not 100% sure about this idea but I think we need a more intuitive way to work with configuring alternateRoutes. What if instead of using segments, alternateRoutes could be configured like this:

alternateRoutes: (path) => {
	return [
		path,
		`/{locale}${path}`
	];
}

I think this would align more with how a svelte-kit user thinks about routing. But I can see how using segments might be easier to manipulate?


Let me know what you think and if there is anything you would like me to help with, I'd love to contribute.
Thanks

@pzerelles
Copy link
Contributor Author

pzerelles commented Apr 27, 2021

Allow alternativeRoute to work for endpoints

Endpoints are often defined in the same directory as the page that uses it. It would be nice if you allow alternativeRoute to work for endpoints in addition to pages (I've added some proposed code changes here: pz-mxu#1 (comment))

Allowing it for endpoints is an option, but if we do that, the alternativeRoutes() function should also get the route's type. Some people might not want to localize endpoints.

Allow dynamic and spread options to work from alternativeRoute

It looks like currently props are processed before alternativeRoute is ever used and because of that the dynamic and spread parameters, when added by alternativeRoute, doesn't work.

const params = parent_params.slice();
params.push(...item.parts.filter((p) => p.dynamic).map((p) => p.content));

it would be nice to have the option to add a dynamic segment like locale as a path parameter by doing something like:

alternateRoutes: (segments) => {
	return [
		segments,
		// Ex. /{locale}/rest/of/path
		[
			[{ content: "locale", dynamic: true, spread: false }],
			...segments
		]
	];
}

Interesting idea, I haven't thought about that yet. Will try to add the possibility and we can play around with it.

Ease of Use

I honestly am not 100% sure about this idea but I think we need a more intuitive way to work with configuring alternateRoutes. What if instead of using segments, alternateRoutes could be configured like this:

alternateRoutes: (path) => {
	return [
		path,
		`/{locale}${path}`
	];
}

I think this would align more with how a svelte-kit user thinks about routing. But I can see how using segments might be easier to manipulate?

I thought about that, too. But using the internal structure makes it easier to work with. Of course this way it's dependent on the internal structure of segments, that could maybe change some time. But I thought that the alternateRoutes() functions will probably be implemented by i18n-libraries, not directly by the user of svelte kit, although possible.

@kobejean
Copy link

Just added another code change proposal: pzerelles#2 (comment)

@benmccann benmccann added the feature / enhancement New feature or request label May 6, 2021
@pzerelles pzerelles force-pushed the alternate-routes branch from 5214872 to 15851cd Compare May 7, 2021 06:12
@pzerelles
Copy link
Contributor Author

I cleaned up the branch and rebased on the latest master.

@pzerelles pzerelles force-pushed the alternate-routes branch 3 times, most recently from 141ca6f to b6e910f Compare May 21, 2021 11:48
@pzerelles pzerelles force-pushed the alternate-routes branch 3 times, most recently from ebd1893 to 328e145 Compare June 3, 2021 07:24
@kobejean kobejean mentioned this pull request Jun 10, 2021
@maelp
Copy link

maelp commented Jun 11, 2021

What's the status on this branch? I'm interested by i18n routes

@changeset-bot
Copy link

changeset-bot bot commented Jul 16, 2021

⚠️ No Changeset found

Latest commit: 64394c0

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@benmccann benmccann changed the title Alternate routes for i18n i18n: localized / translated routes Jul 30, 2021
@netlify
Copy link

netlify bot commented Jan 19, 2022

✔️ Deploy Preview for kit-demo canceled.

🔨 Explore the source changes: dd52462

🔍 Inspect the deploy log: https://app.netlify.com/sites/kit-demo/deploys/61f80cb475268200085e3223

@CanRau
Copy link

CanRau commented Sep 28, 2022

Yes please 😍 any news on this PR? seems a little abandoned?
I'd really love to be able to translate routes in some way or another 🥰

.changeset/pre.json Outdated Show resolved Hide resolved
@@ -1,6 +1,6 @@
{
"name": "@sveltejs/kit",
"version": "1.0.0-next.251",
"version": "1.0.0-next.252",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this does not belong in a feature PR

@@ -1,5 +1,11 @@
# @sveltejs/kit

## 1.0.0-next.252
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

feature PRs must not modify the changelog

@dummdidumm dummdidumm marked this pull request as draft December 14, 2022 15:45
@elliott-with-the-longest-name-on-github
Copy link
Contributor

Given that this has been sitting around for ~3 years and the ecosystem has come a long way, I'm going to go ahead and close this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature / enhancement New feature or request router
Projects
None yet
Development

Successfully merging this pull request may close these issues.