Сделать содержимое приложения ASP.NET Core локализуемым
Примечание.
Это не последняя версия этой статьи. В текущем выпуске см . версию .NET 9 этой статьи.
Предупреждение
Эта версия ASP.NET Core больше не поддерживается. Дополнительные сведения см. в политике поддержки .NET и .NET Core. В текущем выпуске см . версию .NET 9 этой статьи.
Внимание
Эта информация относится к предварительному выпуску продукта, который может быть существенно изменен до его коммерческого выпуска. Майкрософт не предоставляет никаких гарантий, явных или подразумеваемых, относительно приведенных здесь сведений.
В текущем выпуске см . версию .NET 9 этой статьи.
Хишем Бен Атея, Дэмиен Боуден, Барт Каликсто и Надем Афана
Одной из задач локализации приложения является перенос локализуемого содержимого с помощью кода, который упрощает замену содержимого для разных языков и региональных параметров.
IStringLocalizer
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
Используйте реализацию IHtmlLocalizer<TResource> для ресурсов, содержащих код HTML. IHtmlLocalizer Html-кодирует аргументы, отформатированные в строке ресурса, но не кодирует строку ресурса в формате HTML. В следующем выделенном коде только значение name
параметра закодировано в формате HTML.
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
На самом низком уровне 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."];
return View();
}
Приведенный выше код демонстрирует каждый из двух методов создания фабрики.
Общие ресурсы
Вы можете секционирование локализованных строк по контроллеру или области или только одному контейнеру. В примере приложения для SharedResource
общих ресурсов используется класс маркера. Класс маркера никогда не вызывается:
// Dummy class to group shared resources
namespace Localization;
public class SharedResource
{
}
В следующем примере 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
using System.ComponentModel.DataAnnotations;
namespace Localization.ViewModels.Account;
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; }
}
Локализованы атрибуты, не связанные с проверкой.
Использование одной строки ресурса для нескольких классов
В следующем коде показано, как использовать одну строку ресурса для атрибутов проверки с несколькими классами:
services.AddMvc()
.AddDataAnnotationsLocalization(options => {
options.DataAnnotationLocalizerProvider = (type, factory) =>
factory.Create(typeof(SharedResource));
});
В предыдущем коде класс, соответствующий RESX-файлу, SharedResource
в котором хранятся сообщения проверки. С помощью этого подхода DataAnnotations использует SharedResource
только ресурс, а не ресурс для каждого класса.
Настройка служб локализации
Службы локализации настраиваются в Program.cs
:
builder.Services.AddLocalization(options => options.ResourcesPath = "Resources");
builder.Services.AddMvc()
.AddViewLocalization(LanguageViewLocationExpanderFormat.Suffix)
.AddDataAnnotationsLocalization();
AddLocalization добавляет службы локализации в контейнер служб, включая реализации и
IStringLocalizer<T>
IStringLocalizerFactory
. Приведенный выше код также задает путь к ресурсам "Ресурсы".Метод AddViewLocalization добавляет поддержку файлов локализованных представлений. В этом примере локализация представления основана на суффиксе файла представления. Например, fr в
Index.fr.cshtml
файле.Метод AddDataAnnotationsLocalization добавляет поддержку локализованных сообщений проверки
DataAnnotations
посредством абстракцийIStringLocalizer
.
Примечание.
Возможно, вы не сможете вводить десятичные запятые в полях для десятичных чисел. Чтобы обеспечить поддержку проверки jQuery для других языков, кроме английского, используйте вместо десятичной точки запятую (","), а для отображения данных в форматах для других языков, кроме английского, выполните действия, необходимые для глобализации вашего приложения. См. этот комментарий GitHub 4076 для инструкций по добавлению десятичной запятой.
Следующие шаги
Локализация приложения также включает следующие задачи:
- Предоставление локализованных ресурсов для языков и региональных параметров, поддерживаемых приложением
- Реализация стратегии выбора языка или языка и региональных параметров для каждого запроса
Дополнительные ресурсы
- Поставщик языка и региональных параметров URL-адреса с помощью по промежуточного слоя в качестве фильтров в ASP.NET Core
- Применение RouteDataRequest CultureProvider глобально с по промежуточного слоя в качестве фильтров
- Глобализация и локализация в ASP.NET Core
- Предоставление локализованных ресурсов для языков и региональных параметров в приложении ASP.NET Core
- Стратегии выбора языка и языка и региональных параметров в локализованном приложении ASP.NET Core
- Устранение неполадок локализации ASP.NET Core
- Глобализация и локализация приложений .NET
- Проект Localization.StarterWeb, используемый в этой статье.
- Ресурсы в RESX-файлах
- Набор средств многоязычных приложений Майкрософт
- Локализация и универсальные шаблоны
Авторы: Рик Андерсон (Rick Anderson), Дэмиен Боуден (Damien Bowden), Барт Каликсто (Bart Calixto), Надим Афана (Nadeem Afana) и Хишам Бин Атея (Hisham Bin Ateya)
Одной из задач локализации приложения является перенос локализуемого содержимого с помощью кода, который упрощает замену содержимого для разных языков и региональных параметров.
IStringLocalizer
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
Используйте реализацию IHtmlLocalizer<T>
для ресурсов, содержащих код HTML. IHtmlLocalizer
Html-кодирует аргументы, отформатированные в строке ресурса, но не кодирует строку ресурса в формате HTML. В следующем выделенном коде только значение name
параметра закодировано в формате HTML.
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
На самом нижнем уровне интерфейс 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; }
}
В ASP.NET Core MVC 1.1.0 и более поздних версий атрибуты без проверки локализованы.
Использование одной строки ресурса для нескольких классов
В следующем коде показано, как использовать одну строку ресурса для атрибутов проверки с несколькими классами:
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc()
.AddDataAnnotationsLocalization(options => {
options.DataAnnotationLocalizerProvider = (type, factory) =>
factory.Create(typeof(SharedResource));
});
}
В предыдущем коде класс, соответствующий RESX-файлу, SharedResource
в котором хранятся сообщения проверки. С помощью этого подхода DataAnnotations использует SharedResource
только ресурс, а не ресурс для каждого класса.
Настройка служб локализации
Службы локализации настраиваются в методе Startup.ConfigureServices
:
services.AddLocalization(options => options.ResourcesPath = "Resources");
services.AddMvc()
.AddViewLocalization(LanguageViewLocationExpanderFormat.Suffix)
.AddDataAnnotationsLocalization();
AddLocalization
добавляет службы локализации в контейнер служб, включая реализации иIStringLocalizer<T>
IStringLocalizerFactory
. Приведенный выше код также задает путь к ресурсам "Ресурсы".Метод
AddViewLocalization
добавляет поддержку файлов локализованных представлений. В этом примере локализация представления основана на суффиксе файла представления. Например, fr вIndex.fr.cshtml
файле.Метод
AddDataAnnotationsLocalization
добавляет поддержку локализованных сообщений проверкиDataAnnotations
посредством абстракцийIStringLocalizer
.
Примечание.
Возможно, вы не сможете вводить десятичные запятые в полях для десятичных чисел. Чтобы обеспечить поддержку проверки jQuery для других языков, кроме английского, используйте вместо десятичной точки запятую (","), а для отображения данных в форматах для других языков, кроме английского, выполните действия, необходимые для глобализации вашего приложения. См. этот комментарий GitHub 4076 для инструкций по добавлению десятичной запятой.
Следующие шаги
Локализация приложения также включает следующие задачи:
- Предоставление локализованных ресурсов для языков и региональных параметров, поддерживаемых приложением
- Реализация стратегии выбора языка или языка и региональных параметров для каждого запроса
Дополнительные ресурсы
- Глобализация и локализация в ASP.NET Core
- Предоставление локализованных ресурсов для языков и региональных параметров в приложении ASP.NET Core
- Стратегии выбора языка и языка и региональных параметров в локализованном приложении ASP.NET Core
- Устранение неполадок локализации ASP.NET Core
- Глобализация и локализация приложений .NET
- Проект Localization.StarterWeb, используемый в этой статье.
- Ресурсы в RESX-файлах
- Набор средств многоязычных приложений Майкрософт
- Локализация и универсальные шаблоны
ASP.NET Core