asp.net локализация mvc - PullRequest
       19

asp.net локализация mvc

5 голосов
/ 19 марта 2009

Я пытаюсь реализовать локализацию с маршрутами

У меня есть следующее:

routes.MapRoute( "DefaultLocalized", 
                 "{lang}/{controller}/{action}/{id}",
                 new { controller = "Home",
                       action = "Index",
                       id = "",
                       lang = "en" }
               );

routes.MapRoute( "Default",
                 "{controller}/{action}/{id}",
                 new { controller = "Home",
                       action = "Index",
                       id = "" }
               );

Когда я вызываю свою страницу domain/en/home/index, она работает нормально, но когда я звоню domain/home/index, я получаю ошибку 404: ресурс не найден.

Также, когда я нахожусь на domain/en/home/index и щелкаю защищенную страницу, меня перенаправляют на domain/Account/login, как я могу быть перенаправлен на domain/en/Account/login?

Также, когда я получаю ошибку приложения, как я могу быть перенаправлен на domain/en/home/error?

Реальный вопрос в том, как я могу реализовать локализацию с языком в качестве параметра маршрута?

Ответы [ 4 ]

10 голосов
/ 19 марта 2009

Маршруты будут совпадать по умолчанию слева направо, поэтому «домен / дом / индекс» будет сначала совпадать с lang = домен, контроллер = индекс, действие (по умолчанию для индекса), id (по умолчанию для 0 / нуль).

Чтобы исправить это, я полагаю, вы можете указать регулярное выражение в MapRoute (например, для языков с ровно 2 символами) - оно изменилось в какой-то момент, хотя ... (извините, на данный момент нет IDE, поэтому я не могу проверить точно).

По памяти может быть:

routes.MapRoute( "DefaultLocalized", 
             "{lang}/{controller}/{action}/{id}",
             new { controller = "Home",
                   action = "Index",
                   id = "",},
             new { lang = "[a-z]{2}" }
           );

Обратите внимание, что вы, вероятно, не захотите, чтобы каждое действие выполняло "строковый язык", поэтому вам следует обрабатывать часть маршрута "lang" либо в базовом контроллере, либо в фильтре действий (в любом регистр, предположительно добавьте информацию в ViewData).

6 голосов
/ 16 октября 2013

Я знаю, что это очень старый вопрос, но мне просто нужно было решить полный набор связанных проблем, и я решил поделиться своим решением.

Ниже представлено комплексное решение, включающее несколько дополнительных приемов, позволяющих легко менять язык. Он учитывает конкретные культуры, а не только конкретные языки (но в этом примере сохраняется только языковая часть).

Особенности включают в себя:

  • Откат к языку браузера в определении языка
  • Использует куки для сохранения языка при посещении
  • Переопределить язык с помощью URL
  • Поддерживает изменение языка по ссылке (например, простые пункты меню)

Шаг 1: Изменить RegisterRoutes в RouteConfig

Эта новая маршрутизация включает в себя ограничение (как и другие), чтобы языковой маршрут не захватывал определенные стандартные пути. Нет необходимости в значении языка по умолчанию, поскольку все это обрабатывается LocalisationAttribute (см. Шаг 2).

    public static void RegisterRoutes(RouteCollection routes)
    {
        ...

        // Special localisation route mapping - expects specific language/culture code as first param
        routes.MapRoute(
            name: "Localisation",
            url: "{lang}/{controller}/{action}/{id}",
            defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional },
            constraints: new { lang = @"[a-z]{2}|[a-z]{2}-[a-zA-Z]{2}" }
        );

        // Default routing
        routes.MapRoute(
            name: "Default",
            url: "{controller}/{action}/{id}",
            defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
        );

    }

Шаг 2. Создание атрибута локализации

При этом будут проверяться запросы контроллера перед их обработкой и изменяться текущая культура на основе URL-адреса, файла cookie или культуры браузера по умолчанию.

// Based on: http://geekswithblogs.net/shaunxu/archive/2010/05/06/localization-in-asp.net-mvc-ndash-3-days-investigation-1-day.aspx
public class LocalisationAttribute : ActionFilterAttribute
{
    public const string LangParam = "lang";
    public const string CookieName = "mydomain.CurrentUICulture";

    // List of allowed languages in this app (to speed up check)
    private const string Cultures = "en-GB en-US de-DE fr-FR es-ES ro-RO ";

    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        // Try getting culture from URL first
        var culture = (string)filterContext.RouteData.Values[LangParam];

        // If not provided, or the culture does not match the list of known cultures, try cookie or browser setting
        if (string.IsNullOrEmpty(culture) || !Cultures.Contains(culture))
        {
            // load the culture info from the cookie
            var cookie = filterContext.HttpContext.Request.Cookies[CookieName];
            var langHeader = string.Empty;
            if (cookie != null)
            {
                // set the culture by the cookie content
                culture = cookie.Value;
            }
            else
            {
                // set the culture by the location if not specified - default to English for bots
                culture = filterContext.HttpContext.Request.UserLanguages == null ? "en-EN" : filterContext.HttpContext.Request.UserLanguages[0];
            }
            // set the lang value into route data
            filterContext.RouteData.Values[LangParam] = langHeader;
        }

        // Keep the part up to the "-" as the primary language
        var language = culture.Split(new char[] { '-' }, StringSplitOptions.RemoveEmptyEntries)[0];
        filterContext.RouteData.Values[LangParam] = language;

        // Set the language - ignore specific culture for now
        Thread.CurrentThread.CurrentUICulture = CultureInfo.CreateSpecificCulture(language);

        // save the locale into cookie (full locale)
        HttpCookie _cookie = new HttpCookie(CookieName, culture);
        _cookie.Expires = DateTime.Now.AddYears(1);
        filterContext.HttpContext.Response.SetCookie(_cookie);

        // Pass on to normal controller processing
        base.OnActionExecuting(filterContext);
    }
}

Шаг 3: применить локализацию ко всем контроллерам

, например

[Localisation]  <<< ADD THIS TO ALL CONTROLLERS (OR A BASE CONTROLLER)
public class AccountController : Controller
{

Шаг 4: Чтобы изменить язык (например, из меню)

Это то место, где он стал немного хитрым и потребовал некоторых обходных путей.

Добавьте метод ChangeLanguage в свой контроллер аккаунта. Это позволит удалить любой существующий языковой код из «предыдущего пути», чтобы новый язык вступил в силу.

    // Regex to find only the language code part of the URL - language (aa) or locale (aa-AA) syntax
    static readonly Regex removeLanguage = new Regex(@"/[a-z]{2}/|/[a-z]{2}-[a-zA-Z]{2}/", RegexOptions.Compiled);

    [AllowAnonymous]
    public ActionResult ChangeLanguage(string id)
    {
        if (!string.IsNullOrEmpty(id))
        {
            // Decode the return URL and remove any language selector from it
            id = Server.UrlDecode(id);
            id = removeLanguage.Replace(id, @"/");
            return Redirect(id);
        }
        return Redirect(@"/");
    }

Шаг 5. Добавление ссылок на языковые меню

Пункты меню состоят из ссылки с новым языком, указанным в качестве параметра маршрута.

например. (Пример бритвы)

<li>@Html.ActionLink("English", "ChangeLanguage", "Account", new { lang = "en", id = HttpUtility.UrlEncode(Request.RawUrl) }, null)</li>
<li>@Html.ActionLink("Spanish", "ChangeLanguage", "Account", new { lang = "es", id = HttpUtility.UrlEncode(Request.RawUrl) }, null)</li>

Возвращаемым URl является текущая страница, закодированная так, что она может стать параметром id URL-адреса. Это означает, что вам нужно включить определенные escape-последовательности, которые Razor иначе отклонит как потенциальное нарушение безопасности.

Примечание: для установок без бритвы вы в основном хотите привязку с новым языком и относительным URL текущей страницы в пути, подобном следующему: http://website.com/{language}/account/changelanguage/{existingURL}

, где {language} - это новый код культуры, а {existingURL} - это URL-кодированная версия текущего относительного адреса страницы (чтобы мы вернулись на ту же страницу с выбранным новым языком).

Шаг 6. Включение определенных «небезопасных» символов в URL-адресах

Требуемая кодировка обратного URL означает, что вам нужно будет включить определенные escape-символы в web.config, или существующий параметр URL вызовет ошибку.

В вашем web.config найдите тег httpRuntime (или добавьте его) в <system.web> и добавьте к нему следующее (в основном удалите%, который есть в стандартной версии этого атрибута):

  requestPathInvalidCharacters="&lt;,&gt;,&amp;,:,\,?"

В вашем web.config найдите раздел <system.webserver> и добавьте в него следующее:

<security>
  <requestFiltering allowDoubleEscaping="true"/>
</security>
4 голосов
/ 19 марта 2009

Добавить ограничение как новый {lang = "[a-z] {2}"}.

Кроме того, удалите значение по умолчанию lang = "en". Если вы этого не сделаете, маршрутизация захватит правило языка, когда вы просматриваете его без него. Поэтому, если вы просматриваете домен и выбираете О, он будет использовать домен / en / Home / About вместо более простого домена / Home / About

3 голосов
/ 19 марта 2009

Вы также можете ввести ограничение, даже более жесткое, чем Марк Грэвелл и Фредди Риос.

что-то вроде "en | de | fr | es". Это означало бы жесткое программирование языков, но обычно их мало и они известны.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...