I am going to include the code how I have it. I felt like what I had should work because I got no squiggly lines. lol But I end up with a Redirect Loop.
First off I got the basic implementation from Nadeem Afana's blog. I don't think the CultureHelper.cs or the BaseController.cs may be needed to implement a returnUrl functionality, but since they are part of the code I am including them here so that you don't have to dig through his website to look for it. I have tried to eliminate scrolling for you as well.
HERE IS MY CODE:
Helpers/CultureHelper.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Web;
namespace xxxUSA.Helpers
{
public static class CultureHelper
{
// Valid cultures REMOVED SOME CODES FOR BREVITY
private static readonly List<string> _validCultures = new List<string>
{ "en-AU", "en-BZ", "en-CA", "en-029", "en-IN", "en-IE", "en-JM",
"en-MY", "en-NZ", "en-PH", "en-SG", "en-ZA", "en-TT", "en-GB",
"en-US", "en-ZW", "es-CR", "es-DO", "es-EC", "es-SV", "es-GT",
"es-HN", "es-MX", "es-NI", "es-PA", "es-PY", "es-PE", "es-PR",
"es-ES", "es-US", "es-UY", "es-VE" };
private static readonly List<string> _cultures = new List<string> {
"en-US", // first culture is the DEFAULT
"es", // Spanish NEUTRAL culture
"ar" // Arabic NEUTRAL culture
};
public static bool IsRightToLeft()
{
return
System.Threading.Thread.CurrentThread
.CurrentCulture.TextInfo.IsRightToLeft;
}
public static string GetImplementedCulture(string name)
{
// make sure it's not null
if (string.IsNullOrEmpty(name))
return GetDefaultCulture(); // return Default culture
if (_validCultures.Where(c => c.Equals(name,
StringComparison.InvariantCultureIgnoreCase)).Count() == 0)
return GetDefaultCulture(); // return Default if invalid
if (_cultures.Where(c => c.Equals(name,
StringComparison.InvariantCultureIgnoreCase)).Count() > 0)
return name; // accept it
var n = GetNeutralCulture(name);
foreach (var c in _cultures)
if (c.StartsWith(n))
return c;
return GetDefaultCulture(); // return Default if no match
}
public static string GetDefaultCulture()
{
return _cultures[0]; // return Default culture
}
public static string GetCurrentCulture()
{
return Thread.CurrentThread.CurrentCulture.Name;
}
public static string GetCurrentNeutralCulture()
{
return GetNeutralCulture(Thread.CurrentThread.CurrentCulture.Name);
}
public static string GetNeutralCulture(string name)
{
if (name.Length < 2)
return name;
return name.Substring(0, 2);
}
}
}
Controllers/BaseController.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Web;
using System.Web.Mvc;
using xxxUSA.Helpers;
namespace xxxUSA.Controllers
{
public class BaseController : Controller
{
protected override IAsyncResult BeginExecuteCore(
AsyncCallback callback, object state)
{
string cultureName = null;
// Attempt to read the culture cookie from Request
HttpCookie cultureCookie = Request.Cookies["_culture"];
if (cultureCookie != null)
cultureName = cultureCookie.Value;
else
cultureName = Request.UserLanguages != null &&
Request.UserLanguages.Length > 0 ? Request.UserLanguages[0]
: null; // obtain it from HTTP header AcceptLanguages
// Validate culture name
cultureName = CultureHelper.GetImplementedCulture(cultureName);
// Modify current thread's cultures
Thread.CurrentThread.CurrentCulture = new
System.Globalization.CultureInfo(cultureName);
Thread.CurrentThread.CurrentUICulture =
Thread.CurrentThread.CurrentCulture;
return base.BeginExecuteCore(callback, state);
}
}
}
OK, now we get into where I have modified some things. I will comment on anything I added
Controllers/HomeController.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using xxxUSA.Helpers;
using xxxUSA.Models;
namespace xxxUSA.Controllers
{
public class HomeController : BaseController
{
ApplicationDbContext _db = new ApplicationDbContext();
public ActionResult Index()
{
return View();
}
public ActionResult About()
{
return View();
}
public ActionResult Contact()
{
return View();
}
//I ADDED THIS LAST PARAMETER
public ActionResult SetCulture(string culture, string returnUrl)
{
// Validate input
culture = CultureHelper.GetImplementedCulture(culture);
// Save culture in a cookie
HttpCookie cookie = Request.Cookies["_culture"];
if (cookie != null)
cookie.Value = culture; // update cookie value
else
{
cookie = new HttpCookie("_culture");
cookie.Value = culture;
cookie.Expires = DateTime.Now.AddYears(1);
}
Response.Cookies.Add(cookie);
//THIS WORKS
return Redirect(returnUrl);
//THIS DOES NOT
if (!string.IsNullOrEmpty(returnUrl) && Url.IsLocalUrl(returnUrl))
{
return Redirect(returnUrl);
}
else
{
return RedirectToAction("Index", "Home");
}
}
Now for the code on the Home Page
Views/Home/Index.cshtml
@{
var culture = System.Threading.Thread.CurrentThread
.CurrentUICulture.Name.ToLowerInvariant();
ViewBag.Title = culture;
}
//I ADDED THIS LAST PARAMETER
@helper selected(string c, string culture, string returnUrl)
{
if (c == culture)
{
@:checked="checked"
}
}
@using (Html.BeginForm("SetCulture", "Home"))
{
@Resources.ChooseYourLanguage
<input name="culture" id="en-us" value="en-us"
//I ADDED THIS LAST PARAMETER "About"
type="radio" @selected("en-us", culture, "About") /> English
<input type="Hidden" name="returnUrl" value="About" />
<input name="culture" id="es" value="es"
//I ADDED THIS LAST PARAMETER "About"
type="radio" @selected("es", culture, "About") /> Español
}
//LOTS OF STUFF LOADS HERE LIKE RESOURCE REFERENCES, GRAPHICS, CONTENT,
//NOT IMPORTANT FOR THE IMPLEMENTATION REMOVED FOR BREVITY
@section Scripts {
@Scripts.Render("~/bundles/jqueryval")
<script type="text/javascript">
(function ($) {
$("input[type = 'radio']").click(function () {
$(this).parents("form").submit(); // post form
});
})(jQuery);
</script>
}
So the reason I added the "About" was so if I got it to work, It would redirect to the "About" Action instead of back to the same homepage. It doesn't work though.
Can I not overload the checkboxes @Selected Method the way I have?
Also, NOT IMPORTANT NOW, but what if I wanted to add this to other views from other controllers, Could I include another parameter to designate the controller and action it needs to return to so that I don't have to repeat the code in each controller?
I have contacted Nadeem on twitter and he said he would check it out and try and help. I really appreciate his work and seems like a very kind fellow.. Thanks in advance for simply helping in any capacity!
OK so I have a products/Ingredients page where I have stuff coming from the database, here how I hacked that to show the right field from the database. This is a total HACK BEWARE.
Views/Products.cshtml
@model IEnumerable<xxxUSA.Models.Ingredient>
@{
var culture = System.Threading.Thread.CurrentThread
.CurrentUICulture.Name.ToLowerInvariant();
ViewBag.Title = culture;
}
@helper selected(string c, string culture)
{
if (c == culture)
{@:checked="checked"}
}
<div class="row">
<div class="large-12 columns">
@using(Html.BeginForm("SetCulture", "Ingredient"))
{
<div class="row">
<div class="large-6 columns">
<label>@Resources.ChooseYourLanguage</label>
<input type="Hidden" name="returnUrl" value="/Prodcuts/" />
<input name="culture" id="en-us" value="en-us" type="radio"
@selected("en-us", culture) /> English
<input name="culture" id="es" value="es" type="radio"
@selected("es", culture) /> Español
</div>
</div>
}
@{ViewBag.Culture = System.Threading.Thread.CurrentThread
.CurrentUICulture.Name.ToLowerInvariant();}
//Here is where the conditional logic hack I use to show one field
//or another from the database based on culture
@if (ViewBag.Culture == "en-us") {
@Html.DisplayFor(modelItem => item.IngredientNameEn)
} else {
@Html.DisplayFor(modelItem => item.IngredientNameEs) }
Basically using that conditional logic anywhere I have data that has a spanish or english version. it's hacky as hell though.
Try this:
public ActionResult SetCulture(string culture, string returnUrl)
{
// Validate input
culture = CultureHelper.GetImplementedCulture(culture);
// Save culture in a cookie
HttpCookie cookie = Request.Cookies["_culture"];
if (cookie != null)
cookie.Value = culture; // update cookie value
else
{
cookie = new HttpCookie("_culture");
cookie.Value = culture;
cookie.Expires = DateTime.Now.AddYears(1);
}
Response.Cookies.Add(cookie);
if (!string.IsNullOrEmpty(returnUrl) && Url.IsLocalUrl(returnUrl))
{
return Redirect(returnUrl);
}
else
{
return RedirectToAction("Index", "Home");
}
}