turquoiseowl / i18n

Smart internationalization for ASP.NET
Other
556 stars 156 forks source link

Certain methods of generating URLs fail to be localized #297

Open ajbeaven opened 7 years ago

ajbeaven commented 7 years ago

I've found some issues with certain methods of generating URLs in MVC where the URLs fail to be localized correctly. Here are some crude examples that show the strange behaviour:

No additional parameters<br/>
1 - <a href="@Url.Action("Index", "Home")">link</a> - works<br />
2 - @Html.ActionLink("link", "Index", "Home") - works<br /><br />

Querystring parameter<br />
3 - <a href="@Url.Action("Index", "Home", new { thing = 123 })">link</a> - works<br />
4 - <a href="@Url.Action("Index", "Home")?thing=123">link</a> - works<br />
5 - <a href="?thing[0]=123">link</a> - works<br />
6 - <a href="http://localhost:8082?thing[0]=123">link</a> - works<br />
7 - @Html.ActionLink("link", "Index", "Home", new RouteValueDictionary { { "thing[0]", 123 } }, null) - works<br />
8 - <a href="@Url.Action("Index", "Home")?thing[0]=123">link</a> - doesn't work<br /><br />

Anchors<br />
9 - <a href="http://localhost:8082#thing">link</a> - works<br />
10 - <a href="#thing">link</a> - works<br />
11 - <a href="@Url.Action("Index", "Home")#thing">link</a> - doesn't work<br />
12 - @Html.ActionLink("link", "Index", "Home", null, null, "thing", null, null) - doesn't work<br />

I'm using Scheme2, a default language of en and am testing with a Content-Language set to ru.

I would have added some tests to ResponseFilterTests but I'd need to update them so they supported Url.Action and Html.ActionLink (where it seems the problems lie). I wanted to get your thoughts before doing something drastic like that.

As the examples show above, 8 can be supported by passing the parameter in as an Url.Action / Html.ActionLink argument, so that's not too much of a problem. When it comes to the anchors in 11 and 12 though, even passing it in as a Html.ActionLink argument doesn't work (Url.Action doesn't have an overload that takes an archor/fragment). I'd prefer not to hardcode all URLs that point to an anchor on a different page.

ajbeaven commented 7 years ago

Cancel that last point. An acceptable workaround for the anchor issue would be to specify the protocol:

13 - <a href="@Url.Action("Index", "Home", null, Request.Url.Scheme)#thing">link</a> - works<br />
turquoiseowl commented 7 years ago

What do you mean by 'doesn't work'?

ajbeaven commented 7 years ago

Oops, sorry forgot to add that part :/

The examples I gave above were rendered on a page at http://localhost:8082/ru. I would expect all the generated URLs to include the ru langtag in them. The cases above that 'didn't work' were the ones that did not.

turquoiseowl commented 7 years ago

Can I close this issue? Thanks.

ajbeaven commented 7 years ago

Unless something has changed with how the URLs are generated, I think this would still be an issue. I'll check when I'm back near a computer next week.

ajbeaven commented 7 years ago

Just confirmed that this is still an issue.

To clarify, when on a localized URL (eg. http://localhost/ru) the following methods of generating URLs will not be localized correctly (ie. http://localhost?test=a instead of http://localhost/ru?test=a):

Querystring

<a href="@Url.Action("Index", "Home")?test=a">link</a>

Anchor

<a href="@Url.Action("Index", "Home")#test">link</a>
@Html.ActionLink("link", "Index", "Home", null, null, "test", null, null)

Is this making any sense?

chgsantos commented 7 years ago

Same problem here. If I use @Url.Action inside a Javascript, it does not put the localization part of URL.

Example: var url = '@Url.Action("Action", "Controller")';

Actual result: /Controller/Action

Expected result: /pt/Controller/Action

ajbeaven commented 7 years ago

I don't think you're experiencing this bug sorry. i18n doesn't indiscriminately localise every URL - check out EarlyUrlLocalizer.cs. There might be a more efficient way, but you can use LanguageTag.SetLangTagInUrlPath and LanguageTag.ExtractLangTagFromUrl for your purposes.

chgsantos commented 7 years ago

@ajbeaven I'll take a look. Thanks!

turquoiseowl commented 7 years ago

Yes, during processing and patching of the HTTP response, i18n does its best to locate and then localize any URLs in the response. However, it does this based on the HTML spec.: looking in any/all attributes where URLs are expected e.g. hrefs. Which means if you are putting a URL into the response somewhere else, like some Javascript, then the URL isn't going to be detected.

So for these arbitrarily-located URLs we need a means to explicitly localize a URL. In fact, there is such a method: EarlyUrlLocalizer.LocalizeUrl, although it's currently inaccessible. I'm thinking it should be made accessible...

ajbeaven commented 7 years ago

It'd be nice if EarlyUrlLocalizer.LocalizeUrl had an optional langtag parameter and when not supplied it uses the current request's language/default language.