Логика мультиязычного сайта. Фильтр локализации

Данное руководство устарело. Актуальное руководство: Руководство по ASP.NET Core

Последнее обновление: 31.10.2015

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

Существуют различные способы определения культуры и непосредственной локализации, например, можно переопределять класс контроллера, доопределяя в нем OnActionExecuted и ExecuteCore. Но в данном случае мы поступим по-другому и создадим свой фильтр действий, который будет срабатывать при обращении к действиям контроллера и производить локализацию.

Создадим в проекте папку Filters и добавим в нее класс CultureAttribute со следующим содержанием:

using System;
using System.Collections.Generic;
using System.Globalization;
using System.Threading;
using System.Web;
using System.Web.Mvc;

namespace MultilingualSite.Filters
{
    public class CultureAttribute : FilterAttribute, IActionFilter
    {
        public void OnActionExecuted(ActionExecutedContext filterContext)
        {
            string cultureName = null;
            // Получаем куки из контекста, которые могут содержать установленную культуру
            HttpCookie cultureCookie = filterContext.HttpContext.Request.Cookies["lang"];
            if (cultureCookie != null)
                cultureName = cultureCookie.Value;
            else
                cultureName = "ru"; 

            // Список культур
            List<string> cultures = new List<string>() {"ru", "en", "de"};
            if (!cultures.Contains(cultureName))
            {
                cultureName = "ru";
            }
                Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture(cultureName);
                Thread.CurrentThread.CurrentUICulture = CultureInfo.CreateSpecificCulture(cultureName);
        }

        public void OnActionExecuting(ActionExecutingContext filterContext)
        {
            //не реализован
        }
    }
}

Метод OnActionExecuted срабатывает после вызова действия контроллера. В начале он получает установленную культуру из куков. Затем мы смотрим, есть ли такая культура в списке. Обратите внимание, что строковые значения культур в списке соответствуют суффиксам культур в названиях файлов ресурсов (за исключением русского языка, для которого используется культура по умолчанию).

Сама же установка культуры производится в следующих строках:

Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture(cultureName);
Thread.CurrentThread.CurrentUICulture = CultureInfo.CreateSpecificCulture(cultureName);

После этого для локализации система будет выбирать нужный файл ресурсов.

Теперь создадим собственно само приложение: контроллер и представления. Добавим в папку Controllers контроллер HomeController:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using MultilingualSite.Filters;
using MultilingualSite.Models;

namespace MultilingualSite.Controllers
{
    [Culture]
    public class HomeController : Controller
    {
        PersonContext db = new PersonContext();

        public ActionResult Index()
        {
            return View(db.Persons);
        }

        public ActionResult ChangeCulture(string lang)
        {
            string returnUrl = Request.UrlReferrer.AbsolutePath;
            // Список культур
            List<string> cultures = new List<string>() {"ru", "en", "de"};
            if (!cultures.Contains(lang))
            {
                lang = "ru";
            }
            // Сохраняем выбранную культуру в куки
            HttpCookie cookie = Request.Cookies["lang"];
            if (cookie != null)
                cookie.Value = lang;   // если куки уже установлено, то обновляем значение
            else
            {

                cookie = new HttpCookie("lang");
                cookie.HttpOnly = false;
                cookie.Value = lang;
                cookie.Expires = DateTime.Now.AddYears(1);
            }
            Response.Cookies.Add(cookie);
            return Redirect(returnUrl);
        }
    }
}

По сути контроллер от обычного отличается только тем, что к нему применен ранее созданный атрибут. И практически всю логику по локализации выполняет этот атрибут.

Также в контроллере определено действие ChangeCulture, которое меняет язык с помощью установки нужных куков и затем перенаправляет на ту же страницу.

Теперь добавим представление Index.cshtml, которое будет выглядеть так:

@model IEnumerable<MultilingualSite.Models.Person>

@{
    ViewBag.Title = @Resources.Resource.IndexHeader;
}

<h2>@Resources.Resource.IndexHeader</h2>
<p>
    @Html.ActionLink(@Resources.Resource.CreateLink, "Create")
</p>
<table>
    <tr>
        <th>
            @Html.DisplayNameFor(model => model.Name)
        </th>
        <th>
            @Html.DisplayNameFor(model => model.State)
        </th>
    </tr>

@foreach (var item in Model) {
    <tr>
        <td>
            @Html.DisplayFor(modelItem => item.Name)
        </td>
        <td>
            @Html.DisplayFor(modelItem => item.State)
        </td>
    </tr>
}
</table>

Это обычное представление, только вместо прямых вставок текста используются ресурсы: @Resources.Resource.IndexHeader. И изменим стандартную мастер-страницу _Layout.cshtml, добавив на нее функционал переключения языков:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width" />
    <title>@ViewBag.Title</title>
    @Styles.Render("~/Content/css")
    @Scripts.Render("~/bundles/modernizr")
</head>
<body>
    <div>
        @using (Html.BeginForm("ChangeCulture", "Home"))
        { 
            <select name="lang">
                <option disabled selected>@Resources.Resource.ChooseLang</option>
                <option value="ru">Русский</option>
                <option value="en">English</option>
                <option value="de">Deutsch</option>
           </select>
            <input type="submit" name="submit" value="@Resources.Resource.ChooseLang">
        }
    </div>
    @RenderBody()

    @Scripts.Render("~/bundles/jquery")
    @RenderSection("scripts", required: false)
</body>
</html>

Здесь мы добавили простую форму с выпадающим списком, которая будет отсылать выбор пользователя на сервер вышеопределенному методу ChangeCulture.

Запустим, и у нас отобразится страница на русском языке:

Выбрав в выпадающем списке другой язык и нажав Enter, мы получим локализацию уже на другой язык.

Также мы можем создать и другие представления, например, для создания пользователей. Но общие принципы останутся те же.

Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850