Глобализация и локализация в ASP.NET Core

Авторы: Рик Андерсон (Rick Anderson), Дэмиен Боуден (Damien Bowden), Барт Каликсто (Bart Calixto), Надим Афана (Nadeem Afana) и Хишам Бин Атея (Hisham Bin Ateya)

Многоязычный веб-сайт позволяет веб-сайту достичь более широкой аудитории. ASP.NET Core предоставляет службы и ПО промежуточного слоя для локализации на разные языки и для разных региональных параметров.

Условия

  • Глобализация (G11N): процесс подготовки приложения к поддержке различных языков и регионов. Сокращение происходит от первых и последних букв и количества букв между ними.
  • Локализация (L10N): процесс настройки глобального приложения для определенных языков и регионов.
  • Интернационализация (I18N): глобализация и локализация.
  • Язык и региональные параметры: язык и, при необходимости, регион.
  • Нейтральный язык и региональные параметры: язык и региональные параметры, но не регион (например, en, es).
  • Конкретный язык и региональные параметры: язык и регион с заданным языком и регионом (например, en-US, en-GB, es-CL).
  • Родительский язык и региональные параметры: нейтральный язык и региональные параметры, содержащие определенный язык и региональные параметры (например, en-US и en-GB).
  • Языковой стандарт: тот же, что и язык и региональные параметры.

Коды языка и страны или региона

Формат RFC 4646 для имени языка и региональных параметров , <language code>-<country/region code>где <language code> определяет язык и <country/region code> определяет субкультуру. Примеры: es-CL для испанского языка (Чили), en-US для английского языка (США), en-AU для английского языка (Австралия). RFC 4646 — это комбинация двухбуквенного кода культуры ISO 639 в нижнем регистре (он связан с языком) и двухбуквенного кода субкультуры ISO 3166 в верхнем регистре (он связан со страной или регионом). Дополнительные сведения см. в разделе System.Globalization.CultureInfo.

Задачи локализации приложения

Глобализация и локализация приложения включает следующие задачи:

Просмотреть или скачать образец кода (описание загрузки)

Дополнительные ресурсы

Авторы: Рик Андерсон (Rick Anderson), Дэмиен Боуден (Damien Bowden), Барт Каликсто (Bart Calixto), Надим Афана (Nadeem Afana) и Хишам Бин Атея (Hisham Bin Ateya)

Многоязычный веб-сайт позволяет веб-сайту достичь более широкой аудитории. ASP.NET Core предоставляет службы и ПО промежуточного слоя для локализации на разные языки и для разных региональных параметров.

Условия

  • Глобализация (G11N): процесс подготовки приложения к поддержке различных языков и регионов. Сокращение происходит от первых и последних букв и количества букв между ними.
  • Локализация (L10N): процесс настройки глобального приложения для определенных языков и регионов.
  • Интернационализация (I18N): глобализация и локализация.
  • Язык и региональные параметры: язык и, при необходимости, регион.
  • Нейтральный язык и региональные параметры: язык и региональные параметры, но не регион (например, en, es).
  • Конкретный язык и региональные параметры: язык и регион с заданным языком и регионом (например, en-US, en-GB, es-CL).
  • Родительский язык и региональные параметры: нейтральный язык и региональные параметры, содержащие определенный язык и региональные параметры (например, en-US и en-GB).
  • Языковой стандарт: тот же, что и язык и региональные параметры.

Коды языка и страны или региона

Формат RFC 4646 для имени языка и региональных параметров , <language code>-<country/region code>где <language code> определяет язык и <country/region code> определяет субкультуру. Примеры: es-CL для испанского языка (Чили), en-US для английского языка (США), en-AU для английского языка (Австралия). RFC 4646 — это комбинация двухбуквенного кода культуры ISO 639 в нижнем регистре (он связан с языком) и двухбуквенного кода субкультуры ISO 3166 в верхнем регистре (он связан со страной или регионом). Дополнительные сведения см. в разделе System.Globalization.CultureInfo.

Задачи локализации приложения

Глобализация и локализация приложения включает следующие задачи:

Просмотреть или скачать образец кода (описание загрузки)

Дополнительные ресурсы

Авторы: Рик Андерсон (Rick Anderson), Дэмиен Боуден (Damien Bowden), Барт Каликсто (Bart Calixto), Надим Афана (Nadeem Afana) и Хишам Бин Атея (Hisham Bin Ateya)

Создание многоязычного веб-сайта позволит расширить аудиторию. ASP.NET Core предоставляет службы и ПО промежуточного слоя для локализации на разные языки и для разных региональных параметров.

В интернационализацию входит System.Globalization и локализация. Глобализация — это процесс разработки приложений, которые поддерживают разные языки и региональные параметры. Глобализация добавляет поддержку ввода отображения и вывода определенного набора языковых сценариев, относящихся к конкретным регионам.

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

Локализация приложения включает следующие задачи:

  1. обеспечение возможности локализации для содержимого приложения;
  2. Предоставление локализованных ресурсов для поддерживаемых языков и региональных параметров
  3. реализацию стратегии по выбору языка и региональных параметров для каждого запроса.

Просмотреть или скачать образец кода (описание загрузки)

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

IStringLocalizer и IStringLocalizer<T> создавались для повышения производительность при разработке локализованных приложений. IStringLocalizer использует классы ResourceManager и ResourceReader для предоставления ресурсов, связанных с определенным языком и региональными параметрами, во время выполнения. Этот интерфейс имеет индексатор и интерфейс IEnumerable для возврата локализованных строк. IStringLocalizer не требует сохранять строки на языке по умолчанию в файле ресурсов. Вы можете разрабатывать приложение, предназначенное для локализации, не создавая файлы ресурсов на ранних этапах разработки. В приведенном ниже коде показано, как подготовить строку "About Title" для локализации.

using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Localization;

namespace Localization.Controllers
{
    [Route("api/[controller]")]
    public class AboutController : Controller
    {
        private readonly IStringLocalizer<AboutController> _localizer;

        public AboutController(IStringLocalizer<AboutController> localizer)
        {
            _localizer = localizer;
        }

        [HttpGet]
        public string Get()
        {
            return _localizer["About Title"];
        }
    }
}

В предыдущем коде реализация IStringLocalizer<T> получена в результате внедрения зависимостей. Если локализованное значение для строки "About Title" не найдено, возвращается ключ индексатора, то есть строка "About Title". Вы можете оставить литеральные строки на языке по умолчанию и заключить их в средство локализации, чтобы сосредоточиться на разработке приложения. Вы разрабатываете приложение на языке по умолчанию и подготавливаете его к локализации, не создавая предварительно файл ресурсов по умолчанию. Вы также можете выбрать традиционный подход и предоставить ключ для извлечения строки на языке по умолчанию. Для многих разработчиков новый рабочий процесс, который не требует наличия файла RESX на языке по умолчанию и позволяет просто заключать строки для дальнейшей обработки, может помочь снизить затраты на локализацию приложения. Другие разработчики могут предпочесть традиционный рабочий процесс, так как он упрощает работу с более длинными строками и обновление локализованных строк.

Используйте реализацию IHtmlLocalizer<T> для ресурсов, содержащих код HTML. Интерфейс IHtmlLocalizer кодирует в HTML аргументы, отформатированные в строке ресурса, но не кодирует в HTML саму строку. В выделенной ниже строке в HTML кодируется только значение параметра name.

using System;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Localization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Localization;

namespace Localization.Controllers
{
    public class BookController : Controller
    {
        private readonly IHtmlLocalizer<BookController> _localizer;

        public BookController(IHtmlLocalizer<BookController> localizer)
        {
            _localizer = localizer;
        }

        public IActionResult Hello(string name)
        {
            ViewData["Message"] = _localizer["<b>Hello</b><i> {0}</i>", name];

            return View();
        }

Примечание.

Как правило, требуется локализовать только текст, но не код HTML.

На самом нижнем уровне интерфейс IStringLocalizerFactory можно получить из внедрения зависимостей:

{
    public class TestController : Controller
    {
        private readonly IStringLocalizer _localizer;
        private readonly IStringLocalizer _localizer2;

        public TestController(IStringLocalizerFactory factory)
        {
            var type = typeof(SharedResource);
            var assemblyName = new AssemblyName(type.GetTypeInfo().Assembly.FullName);
            _localizer = factory.Create(type);
            _localizer2 = factory.Create("SharedResource", assemblyName.Name);
        }       

        public IActionResult About()
        {
            ViewData["Message"] = _localizer["Your application description page."] 
                + " loc 2: " + _localizer2["Your application description page."];

В приведенном выше коде демонстрируются оба фабричных метода создания.

Вы можете разбивать локализованные строки по контроллеру, области или использовать всего один конвейер. В образце приложения для общих ресурсов применяется класс-заглушка с именем SharedResource.

// Dummy class to group shared resources

namespace Localization
{
    public class SharedResource
    {
    }
}

Некоторые разработчики используют класс Startup для хранения глобальных или общих строк. В примере ниже используются средства локализации InfoController и SharedResource.

public class InfoController : Controller
{
    private readonly IStringLocalizer<InfoController> _localizer;
    private readonly IStringLocalizer<SharedResource> _sharedLocalizer;

    public InfoController(IStringLocalizer<InfoController> localizer,
                   IStringLocalizer<SharedResource> sharedLocalizer)
    {
        _localizer = localizer;
        _sharedLocalizer = sharedLocalizer;
    }

    public string TestLoc()
    {
        string msg = "Shared resx: " + _sharedLocalizer["Hello!"] +
                     " Info resx " + _localizer["Hello!"];
        return msg;
    }

Локализация представления

Служба IViewLocalizer предоставляет локализованные строки для представления. Класс ViewLocalizer реализует этот интерфейс и находит расположение ресурсов по пути к файлу представления. В следующем примере кода демонстрируется использование реализации IViewLocalizer по умолчанию:

@using Microsoft.AspNetCore.Mvc.Localization

@inject IViewLocalizer Localizer

@{
    ViewData["Title"] = Localizer["About"];
}
<h2>@ViewData["Title"].</h2>
<h3>@ViewData["Message"]</h3>

<p>@Localizer["Use this area to provide additional information."]</p>

Реализация IViewLocalizer по умолчанию находит файл ресурсов по имени файла представления. Возможности использовать глобальный общий файл ресурсов нет. ViewLocalizer реализует средство локализации с помощью интерфейса IHtmlLocalizer, поэтому Razor не кодирует локализованную строку в HTML. Вы можете параметризовать строки ресурсов, и IViewLocalizer будет кодировать в HTML параметры, но не строки ресурсов. Рассмотрим следующую разметку Razor:

@Localizer["<i>Hello</i> <b>{0}!</b>", UserManager.GetUserName(User)]

Файл ресурсов на французском языке может содержать следующие ресурсы:

Ключ Значение
<i>Hello</i> <b>{0}!</b> <i>Bonjour</i> <b>{0} !</b>

Преобразованное для просмотра представление будет содержать разметку HTML из файла ресурсов.

Примечание.

Как правило, требуется локализовать только текст, но не код HTML.

Чтобы использовать в представлении общий файл ресурсов, внедрите IHtmlLocalizer<T>:

@using Microsoft.AspNetCore.Mvc.Localization
@using Localization.Services

@inject IViewLocalizer Localizer
@inject IHtmlLocalizer<SharedResource> SharedLocalizer

@{
    ViewData["Title"] = Localizer["About"];
}
<h2>@ViewData["Title"].</h2>

<h1>@SharedLocalizer["Hello!"]</h1>

Локализация DataAnnotations

Сообщения об ошибках DataAnnotations локализуются с помощью IStringLocalizer<T>. При использовании параметра ResourcesPath = "Resources" сообщения об ошибках в RegisterViewModel могут сохраняться по одному из следующих путей:

  • Resources/ViewModels.Account.RegisterViewModel.fr.resx
  • Resources/ViewModels/Account/RegisterViewModel.fr.resx
public class RegisterViewModel
{
    [Required(ErrorMessage = "The Email field is required.")]
    [EmailAddress(ErrorMessage = "The Email field is not a valid email address.")]
    [Display(Name = "Email")]
    public string Email { get; set; }

    [Required(ErrorMessage = "The Password field is required.")]
    [StringLength(8, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)]
    [DataType(DataType.Password)]
    [Display(Name = "Password")]
    public string Password { get; set; }

    [DataType(DataType.Password)]
    [Display(Name = "Confirm password")]
    [Compare("Password", ErrorMessage = "The password and confirmation password do not match.")]
    public string ConfirmPassword { get; set; }
}

Локализованы атрибуты, не связанные с проверкой.

Использование одной строки ресурса для нескольких классов

В следующем коде показано, как использовать одну строку ресурса для атрибутов проверки с несколькими классами:

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc()
        .AddDataAnnotationsLocalization(options => {
            options.DataAnnotationLocalizerProvider = (type, factory) =>
                factory.Create(typeof(SharedResource));
        });
}

В предыдущем коде SharedResource — это класс, соответствующий файлу RESX, в котором хранятся сообщения о проверке. При таком подходе DataAnnotations будут использовать только SharedResource, а не ресурс для каждого класса.

Предоставление локализованных ресурсов для поддерживаемых языков и региональных параметров

SupportedCultures и SupportedUICultures

ASP.NET Core позволяет указывать два значения языка и региональных параметров: SupportedCultures и SupportedUICultures. Объект CultureInfo для SupportedCultures определения результатов функций, зависимых от языка и региональных параметров, таких как дата, время, число и форматирование валют. SupportedCultures также определяет порядок сортировки текста, соглашения о регистре символов и способы сравнения строк. Дополнительные сведения о том, как сервер получает данные о языке и региональных параметрах, см. в статьях о CultureInfo.CurrentCulture и CultureInfo.CurrentUICulture. Определяет SupportedUICultures , какие переведенные строки (из .resx файлов) будут искаться ResourceManager. ResourceManager ищет связанные с языком и региональными параметрами строки, которые определяются значением CurrentUICulture. Каждый поток в .NET имеет объекты CurrentCulture и CurrentUICulture. Платформа проверяет эти значения при обработке функций, зависящих от языка и региональных параметров. Если для языка и региональных параметров текущего потока задано значение en-US (английский, США), DateTime.Now.ToLongDateString() отображает Thursday, February 18, 2016. Но если CurrentCulture имеет значение es-ES (испанский, Испания), результатом будет jueves, 18 de febrero de 2016.

Файлы ресурсов

Файл ресурсов — это полезное средство для отделения локализуемых строк от кода. Переведенные строки на языках, отличных от языка по умолчанию, содержатся в отдельных файлах ресурсов с расширением RESX. Например, вам нужно создать файл ресурсов для испанского языка с именем Welcome.es.resx, который будет содержать переведенные строки. "es" — это код испанского языка. Чтобы создать этот файл ресурсов в Visual Studio, выполните указанные ниже действия.

  1. В Обозревателе решений щелкните правой кнопкой мыши папку, которая будет содержать файл ресурсов, а затем выберите пункты >Добавить>Новый элемент.

    Nested contextual menu: In Solution Explorer, a contextual menu is open for Resources. A second contextual menu is open for Add showing the New Item command highlighted.

  2. В поле Поиск установленных шаблонов введите слово "ресурс" и укажите имя файла.

    Add New Item dialog

  3. Введите значение ключа (строку на исходном языке) в столбце Имя и переведенную строку в столбце Значение.

    Welcome.es.resx file (the Welcome resource file for Spanish) with the word Hello in the Name column and the word Hola (Hello in Spanish) in the Value column

    В Visual Studio отобразится файл Welcome.es.resx.

    Solution Explorer showing the Welcome Spanish (es) resource file

Именование файлов ресурсов

Имена ресурсов представляют собой полные имена типов соответствующего класса за исключением имени сборки. Например, ресурс на французском языке в проекте, главная сборка которого имеет имя LocalizationWebsite.Web.dll, для класса LocalizationWebsite.Web.Startup будет иметь имя Startup.fr.resx. У ресурса для класса LocalizationWebsite.Web.Controllers.HomeController будет имя Controllers.HomeController.fr.resx. Если пространство имен целевого класса не совпадает с именем сборки, необходимо использовать полное имя типа. Например, в образце проекта ресурс для типа ExtraNamespace.Tools будет иметь имя ExtraNamespace.Tools.fr.resx.

В примере проекта метод ConfigureServices присваивает свойству ResourcesPath значение Resources, поэтому относительный путь к файлу ресурсов на французском языке для контроллера Home в проекте будет иметь вид Resources/Controllers.HomeController.fr.resx. Кроме того, для упорядочения файлов ресурсов можно использовать папки. Для контроллера Home путь будет иметь вид Resources/Controllers/HomeController.fr.resx. Если параметр ResourcesPath не используется, файл RESX будет находиться в базовом каталоге проекта. У файла ресурса для HomeController будет имя Controllers.HomeController.fr.resx. Выбор соглашения об именовании на основе точечной нотации или пути зависит от того, как следует упорядочивать файлы ресурсов.

Имя ресурса Точечная нотация или путь
Resources/Controllers.HomeController.fr.resx Точки
Resources/Controllers/HomeController.fr.resx Путь

Файлы ресурсов, для которых используется директива @inject IViewLocalizer в представлениях Razor, следуют той же модели. Файлу ресурсов для представления может присваиваться имя на основе либо точечной нотации, либо пути. В файле ресурсов для представления Razor имитируется путь к связанному файлу представления. Если для ResourcesPath задано значение Resources, то файл ресурсов на французском языке, связанный с представлением Views/Home/About.cshtml, может иметь одно из следующих имен.

  • Resources/Views/Home/About.fr.resx

  • Resources/Views.Home.About.fr.resx

Если параметр ResourcesPath не используется, файл RESX для представления будет находиться в той же папке, что и представление.

RootNamespaceAttribute

Атрибут RootNamespaceAttribute предоставляет корневое пространство имен сборки, если корневое пространство имен сборки отличается от имени сборки.

Предупреждение

Это может произойти, если имя проекта — недопустимый идентификатор .NET. Например, my-project-name.csproj будет использовать корневое пространство имен my_project_name и имя сборки my-project-name, что повлечет эту ошибку.

Если корневое пространство имен сборки отличается от имени сборки

  • Локализация не работает по умолчанию.
  • Локализация завершается сбоем из-за метода поиска ресурсов в сборке. RootNamespace — это значение во время сборки, которое недоступно выполняющемуся процессу.

Если RootNamespace отличается от AssemblyName, включите следующее в файл AssemblyInfo.cs (со значениями параметров, замененными фактическими значениями).

using System.Reflection;
using Microsoft.Extensions.Localization;

[assembly: ResourceLocation("Resource Folder Name")]
[assembly: RootNamespace("App Root Namespace")]

Приведенный выше код обеспечивает успешное разрешение RESX-файлов.

Резервный язык и региональные параметры

При поиске ресурса локализации использует резервный язык и региональные параметры. Если запрошенный язык и региональные параметры не найдены, используется родительский язык и региональные параметры. В стороне CultureInfo.Parent свойство представляет родительский язык и региональные параметры. Обычно (но не всегда) это означает удаление национального символа из ISO. Например, диалект испанского в Мексике — es-MX. Родительский элемент "es" (испанский) не относится к той или иной стране.

Допустим, сайт получает запрос на ресурс "Приветствие" с использованием языка и региональных параметров fr-CA. Система локализации ищет в следующих ресурсах по порядку и выбирает первое совпадение:

  • Welcome.fr-CA.resx
  • Welcome.fr.resx
  • Welcome.resx (если NeutralResourcesLanguage — fr-CA)

Если вы удалите указатель языка и региональных параметров ".fr" и при этом задан французский язык и региональные параметры, будет считан файл ресурсов по умолчанию и строки локализуются. Диспетчер ресурсов назначает ресурс по умолчанию или резервный ресурс на тот случай, когда соответствия запрошенному языку и региональным параметрам не найдено. Если нужно, чтобы при отсутствии ресурса для запрошенного языка и региональных параметров просто возвращался ключ, не используйте файл ресурсов по умолчанию.

Создание файлов ресурсов с помощью Visual Studio

Если вы создаете в Visual Studio файл ресурсов, в имени которого не указаны язык и региональные параметры (например, Welcome.resx), Visual Studio создаст класс C# со свойством для каждой строки. В ASP.NET Core обычно требуется иное поведение. Как правило, файл ресурсов RESX по умолчанию (файл RESX без указания языка и региональных параметров) не используется. Мы рекомендуем создать файл RESX с указанием языка и региональных параметров (например, Welcome.fr.resx). При создании файла RESX с указанием языка и региональных параметров среда Visual Studio не создает файл класса.

Добавление других языков и региональных параметров

Каждое сочетание языка и региональных параметров (кроме языка по умолчанию) требует уникального файла ресурсов. Создавая файлы ресурсов для разных языков, языковых стандартов и региональных параметров, вы включаете в их имена коды языков ISO (например, en-us, ru-ru и fr-ca). Эти коды ISO помещаются между именем файла и расширением RESX, например Welcome.es-MX.resx (испанский, Мексика).

реализацию стратегии по выбору языка и региональных параметров для каждого запроса.

Настройка локализации

Локализация настраивается в методе Startup.ConfigureServices:

services.AddLocalization(options => options.ResourcesPath = "Resources");

services.AddMvc()
    .AddViewLocalization(LanguageViewLocationExpanderFormat.Suffix)
    .AddDataAnnotationsLocalization();
  • Метод AddLocalization добавляет службы локализации в контейнер служб. В приведенном выше коде также задается путь к ресурсам "Resources".

  • Метод AddViewLocalization добавляет поддержку файлов локализованных представлений. В этом примере локализация образца представления основана на суффиксе файла представления, Например, fr в Index.fr.cshtml файле.

  • Метод AddDataAnnotationsLocalization добавляет поддержку локализованных сообщений проверки DataAnnotations посредством абстракций IStringLocalizer.

Промежуточный слой локализации

Текущий язык и региональные параметры в запросе задаются в промежуточном слое локализации. Промежуточный слой локализации включается в методе Startup.Configure. ПО промежуточного слоя локализации должно настраиваться перед другим ПО промежуточного слоя, которое может проверять язык и региональные параметры запроса (например, app.UseMvcWithDefaultRoute()). ПО промежуточного слоя локализации должно находиться после ПО промежуточного слоя маршрутизации, если используется RouteDataRequestCultureProvider. Дополнительные сведения о порядке ПО промежуточного слоя см. в статье ПО промежуточного слоя ASP.NET Core.

var supportedCultures = new[] { "en-US", "fr" };
var localizationOptions = new RequestLocalizationOptions().SetDefaultCulture(supportedCultures[0])
    .AddSupportedCultures(supportedCultures)
    .AddSupportedUICultures(supportedCultures);

app.UseRequestLocalization(localizationOptions);

Если вы хотите увидеть комментарии к коду, переведенные на языки, отличные от английского, сообщите нам на странице обсуждения этой проблемы на сайте GitHub.

UseRequestLocalization инициализирует объект RequestLocalizationOptions. При каждом запросе проверяется список поставщиков RequestCultureProvider в объекте RequestLocalizationOptions и используется первый поставщик, который может успешно определить язык и региональные параметры запроса. Поставщики по умолчанию берутся из класса RequestLocalizationOptions:

  1. QueryStringRequestCultureProvider
  2. CookieRequestCultureProvider
  3. AcceptLanguageHeaderRequestCultureProvider

В списке по умолчанию поставщики следуют от наиболее конкретных до наиболее общих. Далее в этой статье вы узнаете, как можно изменить этот порядок и даже добавить пользовательский поставщик языка и региональных параметров. Если ни один из поставщиков не может определить язык и региональные параметры запроса, используется DefaultRequestCulture.

QueryStringRequestCultureProvider

Для задания CultureInfoнекоторых приложений используется строка запроса. Если в приложении для этого применяется файл cookie или заголовок Accept-Language, добавление строки запроса к URL-адресу может быть полезным в целях отладки и тестирования кода. По умолчанию поставщик QueryStringRequestCultureProvider регистрируется в качестве первого поставщика локализации в списке RequestCultureProvider. Вы передаете параметры строки запроса culture и ui-culture. В следующем примере в качестве языка и региональных параметров (язык и регион) задаются испанский язык и Мексика:

http://localhost:5000/?culture=es-MX&ui-culture=es-MX

Если передан только один из двух параметров (culture или ui-culture), поставщик строки запроса задаст с его помощью оба значения. Например, если передан только язык и региональные параметры, будут заданы оба значения Culture и UICulture:

http://localhost:5000/?culture=es-MX

CookieRequestCultureProvider

Рабочие приложения часто предоставляют механизм для указания языка и региональных параметров с помощью соответствующего файла cookie ASP.NET Core. Чтобы создать файл MakeCookieValue, используйте метод cookie.

CookieRequestCultureProviderDefaultCookieName возвращает имя файла cookie по умолчанию, с помощью которого отслеживается предпочтительный язык и региональные параметры пользователя. Имя cookie по умолчанию — .AspNetCore.Culture.

Файл cookie имеет формат c=%LANGCODE%|uic=%LANGCODE%, где c — это Culture, а uic — это UICulture, например:

c=en-UK|uic=en-US

Если указаны либо только язык и региональные параметры, либо только язык и региональные параметры пользовательского интерфейса, это значение будет использоваться для обоих параметров.

Заголовок HTTP Accept-Language

Заголовок Accept-Language может задаваться в большинстве браузеров и изначально предназначался для указания языка пользователя. Он показывает, какой язык был выбран в браузере или унаследован от базовой операционной системы. Заголовок HTTP Accept-Language в запросе из браузера — это не самый надежный способ определения предпочтительного языка пользователя (см. статью Настройка языковых предпочтений в браузере). В рабочем приложении должна быть возможность выбора языка и региональных параметров пользователем.

Задание заголовка HTTP Accept-Language в Internet Explorer

  1. Щелкните значок шестеренки и выберите пункт Свойства браузера.

  2. Нажмите кнопку Языки.

    Internet Options

  3. Нажмите Задать предпочитаемые языки.

  4. Нажмите Добавить язык.

  5. Добавьте язык.

  6. Выберите язык, а затем нажмите кнопку Вверх.

Использование пользовательского поставщика

Предположим, необходимо, чтобы ваши клиенты могли сохранять информацию о своем языке и региональных параметрах в ваших базах данных. Можно написать поставщик, который будет искать эти значения для пользователя. В следующем примере кода показано, как добавить пользовательский поставщик:

private const string enUSCulture = "en-US";

services.Configure<RequestLocalizationOptions>(options =>
{
    var supportedCultures = new[]
    {
        new CultureInfo(enUSCulture),
        new CultureInfo("fr")
    };

    options.DefaultRequestCulture = new RequestCulture(culture: enUSCulture, uiCulture: enUSCulture);
    options.SupportedCultures = supportedCultures;
    options.SupportedUICultures = supportedCultures;

    options.AddInitialRequestCultureProvider(new CustomRequestCultureProvider(async context =>
    {
        // My custom request culture logic
        return await Task.FromResult(new ProviderCultureResult("en"));
    }));
});

Для добавления или удаления поставщиков локализации используйте объект RequestLocalizationOptions.

Изменение порядка поставщиков языка и региональных параметров запроса

В RequestLocalizationOptions три поставщика языка и региональных параметров запроса по умолчанию: QueryStringRequestCultureProvider, CookieRequestCultureProvider и AcceptLanguageHeaderRequestCultureProvider. Чтобы изменить порядок этих поставщиков, используйте свойство [RequestLocalizationOptions.RequestCultureProviders]](xref:Microsoft.AspNetCore.Builder.RequestLocalizationOptions.RequestCultureProviders), как показано ниже:

    app.UseRequestLocalization(options =>
    {
        var questStringCultureProvider = options.RequestCultureProviders[0];    
        options.RequestCultureProviders.RemoveAt(0);
        options.RequestCultureProviders.Insert(1, questStringCultureProvider);
    });

В приведенном примере порядок QueryStringRequestCultureProvider и CookieRequestCultureProvider изменен, поэтому RequestLocalizationMiddleware сначала ищет язык и региональные параметры в файлах cookie, а затем в строке запроса.

Как уже упоминалось, нужно добавить пользовательский поставщик с помощью метода AddInitialRequestCultureProvider, который назначает приоритет 0, чтобы этот поставщик имел приоритет над другими.

Задание языка и региональных параметров программным образом

В образце проекта Localization.StarterWeb в GitHub есть пользовательский интерфейс для задания значения Culture. Файл Views/Shared/_SelectLanguagePartial.cshtml позволяет выбрать язык и региональные параметры из списка поддерживаемых языков и региональных параметров:

@using Microsoft.AspNetCore.Builder
@using Microsoft.AspNetCore.Http.Features
@using Microsoft.AspNetCore.Localization
@using Microsoft.AspNetCore.Mvc.Localization
@using Microsoft.Extensions.Options

@inject IViewLocalizer Localizer
@inject IOptions<RequestLocalizationOptions> LocOptions

@{
    var requestCulture = Context.Features.Get<IRequestCultureFeature>();
    var cultureItems = LocOptions.Value.SupportedUICultures
        .Select(c => new SelectListItem { Value = c.Name, Text = c.DisplayName })
        .ToList();
    var returnUrl = string.IsNullOrEmpty(Context.Request.Path) ? "~/" : $"~{Context.Request.Path.Value}";
}

<div title="@Localizer["Request culture provider:"] @requestCulture?.Provider?.GetType().Name">
    <form id="selectLanguage" asp-controller="Home" 
          asp-action="SetLanguage" asp-route-returnUrl="@returnUrl" 
          method="post" class="form-horizontal" role="form">
        <label asp-for="@requestCulture.RequestCulture.UICulture.Name">@Localizer["Language:"]</label> <select name="culture"
          onchange="this.form.submit();"
          asp-for="@requestCulture.RequestCulture.UICulture.Name" asp-items="cultureItems">
        </select>
    </form>
</div>

Файл Views/Shared/_SelectLanguagePartial.cshtml добавляется в раздел footer файла макета, поэтому он доступен всем представлениям:

<div class="container body-content" style="margin-top:60px">
    @RenderBody()
    <hr>
    <footer>
        <div class="row">
            <div class="col-md-6">
                <p>&copy; @System.DateTime.Now.Year - Localization</p>
            </div>
            <div class="col-md-6 text-right">
                @await Html.PartialAsync("_SelectLanguagePartial")
            </div>
        </div>
    </footer>
</div>

Метод SetLanguage задает файл cookie языка и региональных параметров.

[HttpPost]
public IActionResult SetLanguage(string culture, string returnUrl)
{
    Response.Cookies.Append(
        CookieRequestCultureProvider.DefaultCookieName,
        CookieRequestCultureProvider.MakeCookieValue(new RequestCulture(culture)),
        new CookieOptions { Expires = DateTimeOffset.UtcNow.AddYears(1) }
    );

    return LocalRedirect(returnUrl);
}

Вы не можете подключить _SelectLanguagePartial.cshtml пример кода для этого проекта. В проекте Localization.StarterWeb в GitHub есть код для передачи объекта RequestLocalizationOptions в частичное представление Razor посредством контейнера внедрения зависимостей.

Данные маршрутов привязки модели и строки запросов

См. раздел Поведение глобализации для данных маршрутов привязки модели и строк запросов.

Термины, относящиеся к глобализации и локализации

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

Возможность локализации — это определяемое на промежуточной стадии состояние готовности глобализованного приложения к локализации.

Формат RFC 4646 для названия языка и региональных параметров имеет вид <languagecode2>-<country/regioncode2>, где <languagecode2> — это код языка, а <country/regioncode2> — код субкультуры. Примеры: es-CL для испанского языка (Чили), en-US для английского языка (США), en-AU для английского языка (Австралия). RFC 4646 — это комбинация двухбуквенного кода культуры ISO 639 в нижнем регистре (он связан с языком) и двухбуквенного кода субкультуры ISO 3166 в верхнем регистре (он связан со страной или регионом). Дополнительные сведения см. в разделе System.Globalization.CultureInfo.

Вместо слова "интернационализация" (internationalization) часто используют аббревиатуру "I18N". В аббревиатуру включаются первая и последняя буквы слова, а также число букв между ними, то есть 18 — это число букв между первой ("I") и последней ("N") буквами. То же самое касается глобализации (Globalization — G11N) и локализации (Localization — L10N).

Термины:

  • Глобализация (G11N): процесс подготовки приложения к поддержке различных языков и регионов.
  • Локализация (L10N): процесс настройки приложения для работы с конкретным языком и регионом.
  • Интернационализация (I18N): включает в себя глобализацию и локализацию.
  • Язык и региональные параметры: обозначает язык и (необязательно) регион.
  • Нейтральные язык и региональные параметры: язык и региональные параметры, для которых указан язык, но не регион (например, "en", "es").
  • Конкретные язык и региональные параметры: язык и региональные параметры, для которых указаны язык и регион (например, "en-US", "en-GB", "es-CL").
  • Родительские язык и региональные параметры: нейтральные язык и региональные параметры, содержащие конкретные язык и региональные параметры (например, "en" — это родительские язык и региональные параметры для "en-US" и "en-GB").
  • Языковой стандарт: тот же, что и язык и региональные параметры.

Примечание.

Возможно, вы не сможете вводить десятичные запятые в полях для десятичных чисел. Чтобы обеспечить поддержку проверки jQuery для других языков, кроме английского, используйте вместо десятичной точки запятую (","), а для отображения данных в форматах для других языков, кроме английского, выполните действия, необходимые для глобализации вашего приложения. См. этот комментарий GitHub 4076 для инструкций по добавлению десятичной запятой.

Примечание.

Если запрашиваемый язык и региональные параметры не поддерживаются, перед запуском ASP.NET Core 3.0 веб-приложения записывают по одному журналу типа LogLevel.Warning на запрос. Запись одного LogLevel.Warning на запрос может привести к большим файлам журнала с избыточной информацией. Эту реакцию на событие изменено в ASP.NET 3.0. RequestLocalizationMiddleware записывает журнал типа LogLevel.Debug, который сокращает размер рабочих журналов.

Дополнительные ресурсы