Примечание
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Локализация — это процесс преобразования ресурсов приложения в локализованные версии для каждой культуры, поддерживаемой приложением. Чтобы убедиться, что глобализированное приложение готово к локализации, перейдите к шагу локализации только после завершения шага проверки локализуемости.
Приложение, готовое к локализации, разделено на два концептуальных блока: блок, содержащий все элементы пользовательского интерфейса и блок, содержащий исполняемый код. Блок пользовательского интерфейса содержит только локализуемые элементы пользовательского интерфейса, такие как строки, сообщения об ошибках, диалоговые окна, меню, встроенные ресурсы объектов и т. д. для однородной культуры. Блок кода содержит только код приложения, используемый всеми поддерживаемыми культурами. Общая среда выполнения поддерживает модель ресурсов спутниковой сборки, которая отделяет исполняемый код приложения от ресурсов. Дополнительные сведения о реализации этой модели см. в разделе "Ресурсы" в .NET.
Для каждой локализованной версии приложения добавьте новую сборку-спутник, содержащую локализованный блок пользовательского интерфейса, переведенный на соответствующий язык для целевой культуры. Блок кода для всех культур должен оставаться одинаковым. Сочетание локализованной версии блока пользовательского интерфейса с блоком кода создает локализованную версию приложения.
В этой статье вы узнаете, как использовать реализации IStringLocalizer<T> и IStringLocalizerFactory. Весь пример исходного кода в этой статье зависит от пакетов NuGet Microsoft.Extensions.Localization
и Microsoft.Extensions.Hosting
. Дополнительные сведения о размещении см. в статье об универсальном узле .NET.
Файлы ресурсов
Основной механизм изоляции локализуемых строк — с файлами ресурсов. Файл ресурса — это XML-файл с расширением .resx. Файлы ресурсов переводятся перед выполнением используемого приложения, другими словами, они представляют переведенное содержимое в состоянии покоя. Имя файла ресурсов чаще всего содержит идентификатор языкового стандарта и принимает следующую форму:
<FullTypeName><.Locale>.resx
Где:
-
<FullTypeName>
представляет локализуемые ресурсы для конкретного типа. - Необязательный
<.Locale>
представляет локаль содержимого файла ресурса.
Указание локалей
Языковой стандарт должен определять язык, как минимум, но также может определять язык и региональные параметры (региональный язык), а также страну или регион. Эти сегменты обычно разделяются символом -
. При добавлении специфики языка и региональных параметров правила "резервный вариант языка и региональных параметров" применяются, где наиболее подходящие совпадения определяются приоритетами. Языковой код должен сопоставляться с известным тегом языка. Дополнительные сведения см. в разделе CultureInfo.Name.
Сценарии резервного использования культурных настроек
Представьте, что локализованное приложение поддерживает различные сербские языковые стандарты и содержит следующие файлы ресурсов для него MessageService
:
Файл | Региональный язык | Код страны |
---|---|---|
MessageService.sr-Cyrl-RS.resx | (Кириллица, Сербия) | РС |
MessageService.sr-Cyrl.resx | Кириллический | |
MessageService.sr-Latn-BA.resx | (Латиница, Босния и Герцеговина) | БА |
MessageService.sr-Latn-ME.resx | (Латиница, Черногория) | Я |
MessageService.sr-Latn-RS.resx | (Латиница, Сербия) | РС |
MessageService.sr-Latn.resx | Латинский | |
MessageService.sr.resx | † Латинский | |
MessageService.resx |
† Язык региона по умолчанию для этого языка.
При запуске приложения с CultureInfo.CurrentCulture набором языка и региональных параметров локализации "sr-Cyrl-RS"
пытается разрешить файлы в следующем порядке:
- MessageService.sr-Cyrl-RS.resx
- MessageService.sr-Cyrl.resx
- MessageService.sr.resx
- MessageService.resx
Однако если ваше приложение запущено с CultureInfo.CurrentCulture, установленным для культуры "sr-Latn-BA"
, то локализация пытается разрешить файлы в следующем порядке:
- MessageService.sr-Latn-BA.resx
- MessageService.sr-Latn.resx
- MessageService.sr.resx
- MessageService.resx
Правило "резервная культура" будет игнорировать локализации, если нет соответствующих совпадений, то есть будет выбран четвертый файл ресурсов, если не удается найти совпадение. Если культура установлена на "fr-FR"
, это приведет к тому, что локализация будет зависеть от файла MessageService.resx, что может вызвать проблемы. Дополнительные сведения см. в разделе «Процесс возврата к запасным ресурсам».
Поиск ресурсов
Файлы ресурсов автоматически обрабатываются в рамках процедуры поиска. Если имя файла проекта отличается от корневого пространства имен проекта, имя сборки может отличаться. Это может препятствовать успешному поиску ресурсов. Чтобы устранить это несоответствие, используйте RootNamespaceAttribute подсказку для служб локализации. При указании данный параметр используется при поиске ресурсов.
Пример проекта называется example.csproj, который создает example.dll и example.exe, однако используется пространство имен Localization.Example
.
assembly
Примените атрибут уровня, чтобы исправить это несоответствие:
[assembly: RootNamespace("Localization.Example")]
Регистрация служб локализации
Чтобы зарегистрировать службы локализации, вызовите один из AddLocalization методов расширения во время настройки служб. Это позволит включить внедрение зависимостей (DI) следующих типов:
- Microsoft.Extensions.Localization.IStringLocalizer<T>
- Microsoft.Extensions.Localization.IStringLocalizerFactory
Настройка параметров локализации
Перегрузка AddLocalization(IServiceCollection, Action<LocalizationOptions>) принимает параметр типа setupAction
, называемый Action<LocalizationOptions>
. Это позволяет настроить параметры локализации.
HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);
builder.Services.AddLocalization(options =>
{
options.ResourcesPath = "Resources";
});
// Omitted for brevity.
Файлы ресурсов могут жить в любом месте проекта, но существуют распространенные методики, которые оказались успешными. Чаще всего выбирают путь наименьшего сопротивления. Предыдущий код C#:
- Создает конструктор хост-приложения по умолчанию.
- Вызовы
AddLocalization
в коллекции служб, указывая LocalizationOptions.ResourcesPath как"Resources"
.
Это приведет к тому, что службы локализации будут искать в каталоге Resources файлы ресурсов.
Использование IStringLocalizer<T>
и IStringLocalizerFactory
После того как вы зарегистрировали (и при необходимости настроили) службы локализации, можно использовать следующие типы с DI:
Чтобы создать службу сообщений, которая может возвращать локализованные строки, рассмотрим следующее MessageService
:
using System.Diagnostics.CodeAnalysis;
using Microsoft.Extensions.Localization;
namespace Localization.Example;
public sealed class MessageService(IStringLocalizer<MessageService> localizer)
{
[return: NotNullIfNotNull(nameof(localizer))]
public string? GetGreetingMessage()
{
LocalizedString localizedString = localizer["GreetingMessage"];
return localizedString;
}
}
В приведенном выше коде C#:
- Поле
IStringLocalizer<MessageService> localizer
объявлено. - Основной конструктор определяет
IStringLocalizer<MessageService>
параметр и записывает его в качестве аргументаlocalizer
. - Метод
GetGreetingMessage
вызывает IStringLocalizer.Item[String], передавая"GreetingMessage"
в качестве аргумента.
IStringLocalizer
также поддерживает параметризованные строковые ресурсы; рассмотрите следующее ParameterizedMessageService
:
using System.Diagnostics.CodeAnalysis;
using Microsoft.Extensions.Localization;
namespace Localization.Example;
public class ParameterizedMessageService(IStringLocalizerFactory factory)
{
private readonly IStringLocalizer _localizer =
factory.Create(typeof(ParameterizedMessageService));
[return: NotNullIfNotNull(nameof(_localizer))]
public string? GetFormattedMessage(DateTime dateTime, double dinnerPrice)
{
LocalizedString localizedString = _localizer["DinnerPriceFormat", dateTime, dinnerPrice];
return localizedString;
}
}
В приведенном выше коде C#:
- Поле
IStringLocalizer _localizer
объявлено. - Основной конструктор принимает
IStringLocalizerFactory
параметр, который используется для созданияIStringLocalizer
изParameterizedMessageService
типа и назначает его полю_localizer
. - Метод
GetFormattedMessage
вызывает IStringLocalizer.Item[String, Object[]], передает"DinnerPriceFormat"
объектdateTime
иdinnerPrice
в качестве аргументов.
Это важно
IStringLocalizerFactory
не требуется. Вместо этого предпочтительнее, чтобы предоставляемые услуги требовали IStringLocalizer<T>.
Оба IStringLocalizer.Item[] индексатора возвращают LocalizedString, для которых неявные преобразования к string?
присутствуют.
Соберите всё вместе
Чтобы иллюстрировать приложение с помощью обеих служб сообщений, а также файлов локализации и ресурсов, рассмотрите следующий Program.cs файл:
using System.Globalization;
using Localization.Example;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Localization;
using Microsoft.Extensions.Logging;
using static System.Console;
using static System.Text.Encoding;
[assembly: RootNamespace("Localization.Example")]
OutputEncoding = Unicode;
if (args is [var cultureName])
{
CultureInfo.CurrentCulture =
CultureInfo.CurrentUICulture =
CultureInfo.GetCultureInfo(cultureName);
}
HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);
builder.Services.AddLocalization();
builder.Services.AddTransient<MessageService>();
builder.Services.AddTransient<ParameterizedMessageService>();
builder.Logging.SetMinimumLevel(LogLevel.Warning);
using IHost host = builder.Build();
IServiceProvider services = host.Services;
ILogger logger =
services.GetRequiredService<ILoggerFactory>()
.CreateLogger("Localization.Example");
MessageService messageService =
services.GetRequiredService<MessageService>();
logger.LogWarning(
"{Msg}",
messageService.GetGreetingMessage());
ParameterizedMessageService parameterizedMessageService =
services.GetRequiredService<ParameterizedMessageService>();
logger.LogWarning(
"{Msg}",
parameterizedMessageService.GetFormattedMessage(
DateTime.Today.AddDays(-3), 37.63));
await host.RunAsync();
В приведенном выше коде C#:
- Устанавливает RootNamespaceAttribute как корневое пространство имен для
"Localization.Example"
. - Console.OutputEncoding назначается Encoding.Unicode.
- При передаче одного аргумента в
args
, CultureInfo.CurrentCulture и CultureInfo.CurrentUICulture получают результат выполнения CultureInfo.GetCultureInfo(String) с учетомarg[0]
. - Создается Host по умолчанию.
- Службы локализации
MessageService
иParameterizedMessageService
зарегистрированы вIServiceCollection
для DI. - Чтобы исключить шум, ведение журнала настроено для игнорирования уровней журнала ниже уровня предупреждения.
- Итоговое сообщение после разрешения
MessageService
из экземпляраIServiceProvider
заносится в журнал. - Разрешение
ParameterizedMessageService
выполняется из экземпляраIServiceProvider
, а полученное отформатированное сообщение регистрируется.
Каждый из *MessageService
классов определяет набор RESX-файлов , каждый из которых содержит одну запись. Ниже приведен пример содержимого MessageService
для файлов ресурсов, начиная с MessageService.resx:
<?xml version="1.0" encoding="utf-8"?>
<root>
<data name="GreetingMessage" xml:space="preserve">
<value>Hi friends, the ".NET" developer community is excited to see you here!</value>
</data>
</root>
MessageService.sr-Cyrl-RS.resx:
<?xml version="1.0" encoding="utf-8"?>
<root>
<data name="GreetingMessage" xml:space="preserve">
<value>Здраво пријатељи, ".NЕТ" девелопер заједница је узбуђена што вас види овде!</value>
</data>
</root>
MessageService.sr-Latn.resx:
<?xml version="1.0" encoding="utf-8"?>
<root>
<data name="GreetingMessage" xml:space="preserve">
<value>Zdravo prijatelji, ".NET" developer zajednica je uzbuđena što vas vidi ovde!</value>
</data>
</root>
Ниже приведен пример содержимого ParameterizedMessageService
для файлов ресурсов, начиная с ParameterizedMessageService.resx:
<?xml version="1.0" encoding="utf-8"?>
<root>
<data name="DinnerPriceFormat" xml:space="preserve">
<value>On {0:D} my dinner cost {1:C}.</value>
</data>
</root>
ParameterizedMessageService.sr-Cyrl-RS.resx:
<?xml version="1.0" encoding="utf-8"?>
<root>
<data name="DinnerPriceFormat" xml:space="preserve">
<value>У {0:D} моја вечера је коштала {1:C}.</value>
</data>
</root>
ParameterizedMessageService.sr-Latn.resx:
<?xml version="1.0" encoding="utf-8"?>
<root>
<data name="DinnerPriceFormat" xml:space="preserve">
<value>U {0:D} moja večera je koštala {1:C}.</value>
</data>
</root>
Подсказка
Все XML-комментарии, схемы и <resheader>
элементы файла ресурсов намеренно опущены для краткости.
Примеры запусков
В следующем примере показаны различные локализованные выходные данные с учетом целевых языковых стандартов.
Рассмотрим "sr-Latn"
:
dotnet run --project .\example\example.csproj sr-Latn
warn: Localization.Example[0]
Zdravo prijatelji, ".NET" developer zajednica je uzbuđena što vas vidi ovde!
warn: Localization.Example[0]
U utorak, 03. avgust 2021. moja večera je koštala 37,63 ¤.
При пропуске аргумента в CLI .NET для запуска проекта используется культура системы по умолчанию. В этом случае "en-US"
:
dotnet run --project .\example\example.csproj
warn: Localization.Example[0]
Hi friends, the ".NET" developer community is excited to see you here!
warn: Localization.Example[0]
On Tuesday, August 3, 2021 my dinner cost $37.63.
При передаче "sr-Cryl-RS"
правильные соответствующие файлы ресурсов обнаруживаются и применяется локализация:
dotnet run --project .\example\example.csproj sr-Cryl-RS
warn: Localization.Example[0]
Здраво пријатељи, ".NЕТ" девелопер заједница је узбуђена што вас види овде!
warn: Localization.Example[0]
У уторак, 03. август 2021. моја вечера је коштала 38 RSD.
Пример приложения не предоставляет файлы ресурсов для "fr-CA"
, но при вызове с этой культурой используются нелокализованные файлы ресурсов.
Предупреждение
Поскольку культура найдена, но правильные файлы ресурсов отсутствуют, при применении форматирования в конечном итоге получается частичная локализация.
dotnet run --project .\example\example.csproj fr-CA
warn: Localization.Example[0]
Hi friends, the ".NET" developer community is excited to see you here!
warn: Localization.Example[0]
On mardi 3 août 2021 my dinner cost 37,63 $.