ASP.NET MVC 2 / Localization / Dynamic Default Value?
- by cyberblast
Hello
In an ASP.NET MVC 2 application, i'm having a route like this:
routes.MapRoute(
"Default", // Route name
"{lang}/{controller}/{action}/{id}", // URL with parameters
new // Parameter defaults
{
controller = "Home",
action = "Index",
lang = "de",
id = UrlParameter.Optional
},
new
{
lang = new AllowedValuesRouteConstraint(new string[] { "de", "en", "fr", "it" },
StringComparison.InvariantCultureIgnoreCase)
}
Now, basically I would like to set the thread's culture according the language passed in. But there is one exception:
If the user requests the page for the first time, like calling "http://www.mysite.com" I want to set the initial language if possible to the one "preferred by the browser".
How can I distinguish in an early procesing stage (like global.asax), if the default parameter has been set because of the default value or mentioned explicit through the URL? (I would prefer a solution where the request URL is not getting parsed).
Is there a way to dynamically provide a default-value for a paramter? Something like a hook? Or where can I override the default value (good application event?).
This is the code i'm actually experimenting with:
protected void Application_AcquireRequestState(object sender, EventArgs e)
{
string activeLanguage;
string[] validLanguages;
string defaultLanguage;
string browsersPreferredLanguage;
try
{
HttpContextBase contextBase = new HttpContextWrapper(Context);
RouteData activeRoute = RouteTable.Routes.GetRouteData(new HttpContextWrapper(Context));
if (activeRoute == null)
{
return;
}
activeLanguage = activeRoute.GetRequiredString("lang");
Route route = (Route)activeRoute.Route;
validLanguages = ((AllowedValuesRouteConstraint)route.Constraints["lang"]).AllowedValues;
defaultLanguage = route.Defaults["lang"].ToString();
browsersPreferredLanguage = GetBrowsersPreferredLanguage();
//TODO: Better way than parsing the url
bool defaultInitialized = contextBase.Request.Url.ToString().IndexOf(string.Format("/{0}/", defaultLanguage), StringComparison.InvariantCultureIgnoreCase) > -1;
string languageToActivate = defaultLanguage;
if (!defaultInitialized)
{
if (validLanguages.Contains(browsersPreferredLanguage, StringComparer.InvariantCultureIgnoreCase))
{
languageToActivate = browsersPreferredLanguage;
}
}
//TODO: Where and how to overwrtie the default value that it gets passed to the controller?
contextBase.RewritePath(contextBase.Request.Path.Replace("/de/", "/en/"));
SetLanguage(languageToActivate);
}
catch (Exception ex)
{
//TODO: Log
Console.WriteLine(ex.Message);
}
}
protected string GetBrowsersPreferredLanguage()
{
string acceptedLang = string.Empty;
if (HttpContext.Current.Request.UserLanguages != null && HttpContext.Current.Request.UserLanguages.Length > 0)
{
acceptedLang = HttpContext.Current.Request.UserLanguages[0].Substring(0, 2);
}
return acceptedLang;
}
protected void SetLanguage(string languageToActivate)
{
CultureInfo cultureInfo = new CultureInfo(languageToActivate);
if (!Thread.CurrentThread.CurrentUICulture.TwoLetterISOLanguageName.Equals(languageToActivate, StringComparison.InvariantCultureIgnoreCase))
{
Thread.CurrentThread.CurrentUICulture = cultureInfo;
}
if (!Thread.CurrentThread.CurrentCulture.TwoLetterISOLanguageName.Equals(languageToActivate, StringComparison.InvariantCultureIgnoreCase))
{
Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture(cultureInfo.Name);
}
}
The RouteConstraint to reproduce the sample:
public class AllowedValuesRouteConstraint : IRouteConstraint
{
private string[] _allowedValues;
private StringComparison _stringComparism;
public string[] AllowedValues
{
get { return _allowedValues; }
}
public AllowedValuesRouteConstraint(string[] allowedValues, StringComparison stringComparism)
{
_allowedValues = allowedValues;
_stringComparism = stringComparism;
}
public AllowedValuesRouteConstraint(string[] allowedValues)
{
_allowedValues = allowedValues;
_stringComparism = StringComparison.InvariantCultureIgnoreCase;
}
public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
{
if (_allowedValues != null)
{
return _allowedValues.Any(a => a.Equals(values[parameterName].ToString(), _stringComparism));
}
else
{
return false;
}
}
}
Can someone help me out with that problem?
Thanks, Martin