I'm working on a multi-language ASP.NET MVC site, and I need some help setting the language in the main action from a partial view.
My default route is declared as:
routes.MapRoute(
name: "Default",
url: "{language}/{controller}/{action}/{id}",
defaults: new { language = "en", controller = "Home", action = "Index", id = UrlParameter.Optional }
);
In my _Layout.cshtml, I've declared a partial reference as:
@Html.Partial("_LanguagePartial")
This Partial invokes an Action in the Language Controller:
@Html.Action("Index","Language")
This controller action just pumps the released languages to the view:
public class LanguageController : BaseController
{
//
// GET: /Language/
public PartialViewResult Index()
{
List<Language> languages = new List<Language>();
foreach (Language language in Global.Data.Languages.Values)
{
if (language.IsReleased)
languages.Add(language);
}
return PartialView(languages);
}
public ActionResult SelectLanguage(string code)
{
//I tried to change the route value here, but this only affects the route to this action
var routeDataDict = HttpContext.Request.RequestContext.RouteData.Values;
routeDataDict["language"] = code;
return RedirectToRoute(routeDataDict);
}
}
The actual view that is shown in the partial, looks like this:
<div class="float-center">
<table><tr>
@foreach (var language in Model) {
<td>
<a href="@Url.Action("SelectLanguage", new { code = language.CultureCode })">
<!--The css for the correct sprite is generated by language.Icon.ToString()
The result will look like "background: url("/Images/Icons.png") -0px -100px; display: block; width: 32px; height: 20px; text-indent: -9999px;"-->
<img alt="" src="" style="@Url.Content(@language.Icon.ToString());border=1" />
</a>
</td>
}
</tr></table>
Now this partial is rendered in every page of the site, like it should, but when I'm for example on mydomain/en/SomeController/SomeAction and I click on let's say the German icon, it should take me to mydomain/de/SomeController/SomeAction.
Off course the action and controller are not fixed.
Any ideas on how I can perform such an action?
Maybe I've implemented the partial wrong and I'll be able to access the route if I implement it differently.
EDIT:
With the help of meilke's answer, I've made following edit to the Language controller:
public ActionResult SelectLanguage(string code)
{
string url = ReplaceLanguageCode(Request.UrlReferrer.ToString(), code);
return Redirect(url);
}
private string ReplaceLanguageCode(string url, string code)
{
Language language = GetLanguage(url);
if (language == null)
{
//No Language is set in the url e.g. http://mydomain/
string domain = Request.Url.AbsoluteUri.ToString().Replace(Request.Url.PathAndQuery, "");
return url.Replace(domain, domain + "/" + code);
}
else
//A Language was already set in the url e.g. http://mydomain/en/
return url.Replace("/" + language.CultureCode + "/", "/" + code + "/");
}
private Language GetLanguage(string url)
{
//Loop the apps languages to see if one is set in the url
foreach (Language language in Global.Data.Languages.Values)
{
if (url.ToLower().Contains("/" + language.CultureCode + "/"))
return language;
}
return null;
}
The SetLanguage action is changed to use the UrlReferrer as stated by meilke's answer. I also added ReplaceLanguageCode to create the new url and GetLanguage to get the language if the original url contains one.