ASP.NET MVC 2 / Локализация / Динамическое значение по умолчанию? - PullRequest
1 голос
/ 08 марта 2010

В приложении ASP.NET MVC 2 у меня есть маршрут, подобный этому:

            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) 
            }

Теперь, в основном, я хотел бы установить культуру потока в соответствии с передаваемым языком. Но есть одно исключение: Если пользователь запрашивает страницу в первый раз, например, при вызове «http://www.mysite.com"», я хочу установить исходный язык, если это возможно, на язык, «предпочитаемый браузером».

Как я могу различить на ранней стадии обработки (например, global.asax), если параметр по умолчанию был установлен из-за значения по умолчанию или упоминается явно через URL? (Я бы предпочел решение, при котором URL-адрес запроса не обрабатывается).

Есть ли способ динамически предоставить значение по умолчанию для параметра? Что-то вроде крючка? Или где я могу переопределить значение по умолчанию (хорошее событие приложения?).

Это код, с которым я на самом деле экспериментирую:

        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);
        }
    }

Ограничение маршрута для воспроизведения образца:

    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;
        }
    }
}

Может кто-нибудь помочь мне с этой проблемой?

Спасибо, Мартин

Ответы [ 3 ]

0 голосов
/ 09 марта 2010

Как насчет использования фильтра действий?

это может быть что-то вроде этого:

public class LocalizationAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        if (filterContext.RouteData.Values["lang"] != null)
        {
            var lang = filterContext.RouteData.Values["lang"].ToString();
            //TODO: Validate the obtained value.
            Thread.CurrentThread.CurrentUICulture = CultureInfo.CreateSpecificCulture(lang);
        }
        else
        {
            var langHeader = filterContext.HttpContext.Request.UserLanguages[0];
            //TODO: Validate the obtained value.
            Thread.CurrentThread.CurrentUICulture = CultureInfo.CreateSpecificCulture(langHeader);
        }
    }
}

Это просто идея, конечно, вам нужно ее улучшить. Затем вы просто добавляете этот атрибут к своим контроллерам или создаете базовый контроллер и устанавливаете в нем атрибут (и делаете все ваши контроллеры подклассом этого базового контроллера).

С уважением.

0 голосов
/ 22 июня 2010

попробуйте это:

        RouteData data=RouteTable.Routes.GetRouteData(httpContext);
        if (data != null)
        {
            Route route = data.Route as Route;
            if (route != null && route.Defaults != null)
                route.Defaults["lang"] = lang.Name;
        }
0 голосов
/ 09 марта 2010

Во избежание несоответствия я предпочитаю перенаправить в корне язык браузера, а затем позволить пользователю изменить язык, если он / она предпочитает.

Просто поместите эти строки в default.aspx, и все готово.

Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load

    Select Case Mid(Request.UserLanguages(0).ToString(), 1, 2).ToLower
        Case "en"
            Response.Redirect("/en/")
        Case "pt"
            Response.Redirect("/pt/")
        Case Else
            Response.Redirect("/es/")
    End Select

End Sub
...