ASP.NET MVC 2 / Localization / Dynamic Default Value?

Posted by cyberblast on Stack Overflow See other posts from Stack Overflow or by cyberblast
Published on 2010-03-08T17:16:03Z Indexed on 2010/03/09 0:06 UTC
Read the original article Hit count: 465

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

© Stack Overflow or respective owner

Related posts about asp.net-mvc

Related posts about route