Настройка локализации переносных объектов в ASP.NET Core

Хишем Бен Атея и Себастиен Рос.

Эта статья описывает действия по использованию файлов переносимых объектов в приложении ASP.NET Core с помощью платформы Orchard Core.

Примечание. Orchard Core не является продуктом корпорации Майкрософт. Корпорация Майкрософт не поддерживает эту функцию.

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

Что такое файл переносимых объектов?

Файлы переносимых объектов (PO) распространяются как текстовые файлы со строками, переведенными на заданный язык. Файлы PO обеспечивают определенные преимущества по сравнению с файлами RESX, например:

  • Файлы PO поддерживают преобразование во множественную форму, файлы RESX — нет.
  • Файлы PO не компилируются подобно файлам RESX. Поэтому потребность в специальных инструментах и действиях сборки отпадает.
  • Файлы PO хорошо работают со средствами редактирования, предназначенными для совместной работы по сети.

Пример

В следующем примере PO-файла содержится перевод двух строк на французском языке, включая один с его формой множественного числа:

fr.po

#: Pages/Index.cshtml:13
msgid "Hello world!"
msgstr "Bonjour le monde!"

msgid "There is one item."
msgid_plural "There are {0} items."
msgstr[0] "Il y a un élément."
msgstr[1] "Il y a {0} éléments."

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

  • #:: комментарий, указывающий контекст переводимой строки. Одну и ту же строку можно перевести по-разному в зависимости от характера ее использования.
  • msgid: непереведенная строка.
  • msgstr: переведенная строка.

Для поддержки плюрализации можно определить дополнительные записи.

  • msgid_plural: непереведенная строка во множественной форме.
  • msgstr[0]: переведенная строка для случая 0.
  • msgstr[N]: переведенная строка для случая N.

Спецификацию файла PO см. здесь.

Настройка поддержки файлов PO в ASP.NET Core

Этот пример основан на веб-приложении ASP.NET Core, созданном из шаблона проекта Visual Studio 2022.

Указание ссылок на пакет

Добавьте ссылку на пакет NuGet OrchardCore.Localization.Core.

Теперь .csproj файл содержит строку, похожую на следующую (номер версии может отличаться):

<PackageReference Include="OrchardCore.Localization.Core" Version="1.5.0" />

Регистрация службы

Добавьте необходимые службы Program.csв:

builder.Services.AddPortableObjectLocalization();

builder.Services
    .Configure<RequestLocalizationOptions>(options => options
        .AddSupportedCultures("fr", "cs")
        .AddSupportedUICultures("fr", "cs"));

builder.Services
    .AddRazorPages()
    .AddViewLocalization();

Добавьте следующий код на выбор Razor страницы. В этом примере используется Index.cshtml.

@page
@using Microsoft.AspNetCore.Mvc.Localization
@inject IViewLocalizer Localizer
@{
    ViewData["Title"] = "Home";
}

<div class="text-center">
    <h1 class="display-4">Welcome</h1>
    <p>Learn about <a href="https://docs.microsoft.com/aspnet/core">building Web apps with ASP.NET Core</a>.</p>
</div>

<p>@Localizer["Hello world!"]</p>

Экземпляр IViewLocalizer внедряется и используется для перевода текста "Hello world!".

Создание файла PO

Создайте файл с именем <culture code>.po в корневой папке приложения. В этом примере файл имеет имя fr.po, так как используется французский язык:

msgid "Hello world!"
msgstr "Bonjour le monde!"

Данный файл содержит как строку на перевод, так и строку, переведенную на французский язык. При необходимости переводы возвращаются к своим родительским языку и региональным параметрам. В этом примере файл fr.po используется, если запрошены язык и региональные параметры fr-FR или fr-CA.

Тестирование приложения

Запустите приложение, отображается текст Hello world!

Перейдите к URL-адресу /Index?culture=fr-FR. Отображается текст Bonjour le monde!.

Преобразование во множественную форму

Файлы PO поддерживают преобразование во множественную форму, что удобно, когда одну и ту же строку нужно переводить по-разному в зависимости от кратности. Эта задача осложняется тем, что каждый язык имеет собственные правила для выбора строк в зависимости от кратности.

Пакет локализации Orchard предоставляет API для автоматического вызова этих различных форм множественного числа.

Создание файлов PO с множественными формами

Добавьте в указанный ранее файл fr.po следующее содержимое:

msgid "There is one item."
msgid_plural "There are {0} items."
msgstr[0] "Il y a un élément."
msgstr[1] "Il y a {0} éléments."

Сведения о том, что означает каждая запись в этом примере, см. в разделе Что такое файл переносимых объектов?.

Добавление языка с использованием различных форм множественного числа

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

Подобные правила действуют не во всех языках. Это показано на примере чешского языка, где форм множественного числа три.

Создайте файл cs.po, как показано ниже, и обратите внимание, что для преобразования во множественную форму нужно три разных перевода:

msgid "Hello world!"
msgstr "Ahoj světe!!"

msgid "There is one item."
msgid_plural "There are {0} items."
msgstr[0] "Existuje jedna položka."
msgstr[1] "Existují {0} položky."
msgstr[2] "Existuje {0} položek."

Чтобы принять локализации на чешский язык, добавьте "cs" в список поддерживаемых языков и региональных параметров в методе Configure:

builder.Services
    .Configure<RequestLocalizationOptions>(options => options
        .AddSupportedCultures("fr", "cs")
        .AddSupportedUICultures("fr", "cs"));

Измените файл Pages/Index.cshtml, чтобы отобразить локализованные строки с учетом множественного числа для нескольких кратностей.

<p>@Localizer.Plural(1, "There is one item.", "There are {0} items.")</p>
<p>@Localizer.Plural(2, "There is one item.", "There are {0} items.")</p>
<p>@Localizer.Plural(5, "There is one item.", "There are {0} items.")</p>

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

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

Для /Index:

There is one item.
There are 2 items.
There are 5 items.

Для /Index?culture=fr:

Il y a un élément.
Il y a 2 éléments.
Il y a 5 éléments.

Для /Index?culture=cs:

Existuje jedna položka.
Existují 2 položky.
Existuje 5 položek.

Для чешской культуры три перевода отличаются. На французском и английском языках для двух последних переведенных строк используется одинаковая конструкция.

Расширенные задачи

Учет контекста строк

Приложения часто содержат переводимые строки в нескольких местах. Одна и та же строка, находящаяся в разных местах приложения (представления Razor или файлы классов), может переводиться по-разному. Файл PO поддерживает понятие контекста файла, которое можно использовать для классификации представляемых строк. В зависимости от контекста файла (или его отсутствия) строку можно перевести по-разному.

Службы локализации PO используют имя полного класса или представление, используемые при переводе строки. Это достигается путем установки значения для записи msgctxt.

Рассмотрим небольшое дополнение к предыдущему примеру fr.po. Страница, расположенная Razor в Pages/Index.cshtml качестве контекста файла, задав значение зарезервированной msgctxt записи:

msgctxt "Views.Home.About"
msgid "Hello world!"
msgstr "Bonjour le monde!"

При такой настройке msgctxt перевод текста отображается при переходе по адресу /Index?culture=fr-FR. Перевод не происходит при переходе к /Privacy?culture=fr-FR.

Если с заданным контекстом файла не совпадает ни одна из конкретных записей, резервный механизм Orchard Core ищет соответствующий файл PO без контекста. Если предположить, что для Pages/Privacy.cshtml никакой конкретный файловый контекст не задан, при переходе к /Privacy?culture=fr-FR загружается файл PO, как показано ниже.

msgid "Hello world!"
msgstr "Bonjour le monde!"

Изменение расположения для файлов PO

Расположение по умолчанию для файлов PO можно изменить в Programs.cs:

services.AddPortableObjectLocalization(options => options.ResourcesPath = "Localization");

В этом примере файлы PO загружаются из папки Localization.

Реализация настраиваемой логики для поиска файлов локализации

Когда для поиска файлов PO требуется более сложная логика, можно реализовать интерфейс OrchardCore.Localization.PortableObject.ILocalizationFileLocationProvider и зарегистрировать его как службу. Это удобно, когда файлы PO могут храниться в различных расположениях или должны находиться в иерархии папок.

Использование языка с другими формами множественного числа по умолчанию

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

Можно использовать более универсальную перегрузку Plural(int count, string[] pluralForms, params object[] arguments), которая принимает строковый массив переводов.

Авторы: Себастьен Рос (Sébastien Ros), Скотт Эдди (Scott Addie) и Хишам Бин Атея (Hisham Bin Ateya)

Эта статья описывает действия по использованию файлов переносимых объектов в приложении ASP.NET Core с помощью платформы Orchard Core.

Примечание. Orchard Core не является продуктом корпорации Майкрософт. Поэтому корпорация Майкрософт не предоставляет поддержку для этого компонента.

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

Что такое файл переносимых объектов?

Файлы переносимых объектов (PO) распространяются как текстовые файлы со строками, переведенными на заданный язык. Файлы PO обеспечивают определенные преимущества по сравнению с файлами RESX, например:

  • Файлы PO поддерживают преобразование во множественную форму, файлы RESX — нет.
  • Файлы PO не компилируются подобно файлам RESX. Поэтому потребность в специальных инструментах и действиях сборки отпадает.
  • Файлы PO хорошо работают со средствами редактирования, предназначенными для совместной работы по сети.

Пример

Ниже приведен пример файла PO, содержащего перевод двух строк на французский язык, для одной из которых приведена форма во множественном числе:

fr.po

#: Pages/Index.cshtml:13
msgid "Hello world!"
msgstr "Bonjour le monde!"

msgid "There is one item."
msgid_plural "There are {0} items."
msgstr[0] "Il y a un élément."
msgstr[1] "Il y a {0} éléments."

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

  • #:: комментарий, указывающий контекст переводимой строки. Одну и ту же строку можно перевести по-разному в зависимости от характера ее использования.
  • msgid: непереведенная строка.
  • msgstr: переведенная строка.

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

  • msgid_plural: непереведенная строка во множественной форме.
  • msgstr[0]: переведенная строка для случая 0.
  • msgstr[N]: переведенная строка для случая N.

Спецификацию файла PO см. здесь.

Настройка поддержки файлов PO в ASP.NET Core

Этот пример основан на приложении ASP.NET Core MVC, созданном из шаблона проекта Visual Studio 2019.

Указание ссылок на пакет

Добавьте ссылку на пакет NuGet OrchardCore.Localization.Core.

Теперь .csproj файл содержит строку, похожую на следующую (номер версии может отличаться):

<PackageReference Include="OrchardCore.Localization.Core" Version="1.2.0" />

Регистрация службы

Добавьте необходимые службы в ConfigureServices метод Startup.cs:

public void ConfigureServices(IServiceCollection services)
{
    services.AddRazorPages()
        .AddViewLocalization(LanguageViewLocationExpanderFormat.Suffix);

    services.AddPortableObjectLocalization();

    services.Configure<RequestLocalizationOptions>(options => options
        .AddSupportedCultures("fr", "cs")
        .AddSupportedUICultures("fr", "cs")
    );
}

Добавьте требуемое ПО промежуточного слоя в метод ConfigureStartup.cs:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseExceptionHandler("/Home/Error");
    }

    app.UseRouting();
    app.UseStaticFiles();

    app.UseRequestLocalization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllerRoute(name: "default", pattern: "{controller=Home}/{action=Index}/{id?}");
    });
}

Добавьте следующий код на выбор Razor страницы. В этом примере используется Index.cshtml.

@page
@using Microsoft.AspNetCore.Mvc.Localization
@inject IViewLocalizer Localizer
@{
    ViewData["Title"] = "Home";
}

<div class="text-center">
    <h1 class="display-4">Welcome</h1>
    <p>Learn about <a href="https://docs.microsoft.com/aspnet/core">building Web apps with ASP.NET Core</a>.</p>
</div>

<p>@Localizer["Hello world!"]</p>

Экземпляр IViewLocalizer внедряется и используется для перевода текста "Hello world!".

Создание файла PO

Создайте файл с именем <culture code>.po в корневой папке приложения. В этом примере файл имеет имя fr.po, так как используется французский язык:

msgid "Hello world!"
msgstr "Bonjour le monde!"

Данный файл содержит как строку на перевод, так и строку, переведенную на французский язык. При необходимости переводы возвращаются к своим родительским языку и региональным параметрам. В этом примере файл fr.po используется, если запрошены язык и региональные параметры fr-FR или fr-CA.

Тестирование приложения

Запустите приложение и перейдите по URL-адресу /Index. Отображается текст Hello world!.

Перейдите к URL-адресу /Index?culture=fr-FR. Отображается текст Bonjour le monde!.

Преобразование во множественную форму

Файлы PO поддерживают преобразование во множественную форму, что удобно, когда одну и ту же строку нужно переводить по-разному в зависимости от кратности. Эта задача осложняется тем, что каждый язык имеет собственные правила для выбора строк в зависимости от кратности.

Пакет локализации Orchard предоставляет API для автоматического вызова этих различных форм множественного числа.

Создание файлов PO с множественными формами

Добавьте в указанный ранее файл fr.po следующее содержимое:

msgid "There is one item."
msgid_plural "There are {0} items."
msgstr[0] "Il y a un élément."
msgstr[1] "Il y a {0} éléments."

Сведения о том, что означает каждая запись в этом примере, см. в разделе Что такое файл переносимых объектов?.

Добавление языка с использованием различных форм множественного числа

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

Подобные правила действуют не во всех языках. Это показано на примере чешского языка, где форм множественного числа три.

Создайте файл cs.po, как показано ниже, и обратите внимание, что для преобразования во множественную форму нужно три разных перевода:

msgid "Hello world!"
msgstr "Ahoj světe!!"

msgid "There is one item."
msgid_plural "There are {0} items."
msgstr[0] "Existuje jedna položka."
msgstr[1] "Existují {0} položky."
msgstr[2] "Existuje {0} položek."

Чтобы принять локализации на чешский язык, добавьте "cs" в список поддерживаемых языков и региональных параметров в методе ConfigureServices:

services.Configure<RequestLocalizationOptions>(options => options
                .AddSupportedCultures("fr", "cs")
                .AddSupportedUICultures("fr", "cs")
            );

Измените файл Pages/Index.cshtml, чтобы отобразить локализованные строки с учетом множественного числа для нескольких кратностей.

<p>@Localizer.Plural(1, "There is one item.", "There are {0} items.")</p>
<p>@Localizer.Plural(2, "There is one item.", "There are {0} items.")</p>
<p>@Localizer.Plural(5, "There is one item.", "There are {0} items.")</p>

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

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

Для /Index:

There is one item.
There are 2 items.
There are 5 items.

Для /Index?culture=fr:

Il y a un élément.
Il y a 2 éléments.
Il y a 5 éléments.

Для /Index?culture=cs:

Existuje jedna položka.
Existují 2 položky.
Existuje 5 položek.

Обратите внимание, что для чешского языка все три перевода различаются. На французском и английском языках для двух последних переведенных строк используется одинаковая конструкция.

Расширенные задачи

Учет контекста строк

Приложения часто содержат переводимые строки в нескольких местах. Одна и та же строка, находящаяся в разных местах приложения (представления Razor или файлы классов), может переводиться по-разному. Файл PO поддерживает понятие контекста файла, которое можно использовать для классификации представляемых строк. В зависимости от контекста файла (или его отсутствия) строку можно перевести по-разному.

Службы локализации PO используют имя полного класса или представление, используемые при переводе строки. Это достигается путем установки значения для записи msgctxt.

Рассмотрим небольшое дополнение к предыдущему примеру fr.po. Представление Razor, расположенное в файле Pages/Index.cshtml, можно определить в качестве контекста файла, задав зарезервированное значение записи msgctxt.

msgctxt "Pages.Index"
msgid "Hello world!"
msgstr "Bonjour le monde!"

При такой настройке msgctxt перевод текста отображается при переходе по адресу /Index?culture=fr-FR. При переходе по адресу /Privacy?culture=fr-FR перевод не отображается.

Если с заданным контекстом файла не совпадает ни одна из конкретных записей, резервный механизм Orchard Core ищет соответствующий файл PO без контекста. Если предположить, что для Pages/Privacy.cshtml никакой конкретный файловый контекст не задан, при переходе к /Privacy?culture=fr-FR загружается файл PO, как показано ниже.

msgid "Hello world!"
msgstr "Bonjour le monde!"

Изменение расположения для файлов PO

Расположение по умолчанию для файлов PO можно изменить в ConfigureServices:

services.AddPortableObjectLocalization(options => options.ResourcesPath = "Localization");

В этом примере файлы PO загружаются из папки Localization.

Реализация настраиваемой логики для поиска файлов локализации

Когда для поиска файлов PO требуется более сложная логика, можно реализовать интерфейс OrchardCore.Localization.PortableObject.ILocalizationFileLocationProvider и зарегистрировать его как службу. Это удобно, когда файлы PO могут храниться в различных расположениях или должны находиться в иерархии папок.

Использование языка с другими формами множественного числа по умолчанию

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

Можно использовать более универсальную перегрузку Plural(int count, string[] pluralForms, params object[] arguments), которая принимает строковый массив переводов.

Авторы: Себастьен Рос (Sébastien Ros), Скотт Эдди (Scott Addie) и Хишам Бин Атея (Hisham Bin Ateya)

Эта статья описывает действия по использованию файлов переносимых объектов в приложении ASP.NET Core с помощью платформы Orchard Core.

Примечание. Orchard Core не является продуктом корпорации Майкрософт. Поэтому корпорация Майкрософт не предоставляет поддержку для этого компонента.

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

Что такое файл переносимых объектов?

Файлы переносимых объектов (PO) распространяются как текстовые файлы со строками, переведенными на заданный язык. Файлы PO обеспечивают определенные преимущества по сравнению с файлами RESX, например:

  • Файлы PO поддерживают преобразование во множественную форму, файлы RESX — нет.
  • Файлы PO не компилируются подобно файлам RESX. Поэтому потребность в специальных инструментах и действиях сборки отпадает.
  • Файлы PO хорошо работают со средствами редактирования, предназначенными для совместной работы по сети.

Пример

Ниже приведен пример файла PO, содержащего перевод двух строк на французский язык, для одной из которых приведена форма во множественном числе:

fr.po

#: Services/EmailService.cs:29
msgid "Enter a comma separated list of email addresses."
msgstr "Entrez une liste d'emails séparés par une virgule."

#: Views/Email.cshtml:112
msgid "The email address is \"{0}\"."
msgid_plural "The email addresses are \"{0}\"."
msgstr[0] "L'adresse email est \"{0}\"."
msgstr[1] "Les adresses email sont \"{0}\""

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

  • #:: комментарий, указывающий контекст переводимой строки. Одну и ту же строку можно перевести по-разному в зависимости от характера ее использования.
  • msgid: непереведенная строка.
  • msgstr: переведенная строка.

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

  • msgid_plural: непереведенная строка во множественной форме.
  • msgstr[0]: переведенная строка для случая 0.
  • msgstr[N]: переведенная строка для случая N.

Спецификацию файла PO см. здесь.

Настройка поддержки файлов PO в ASP.NET Core

Этот пример основан на приложении ASP.NET Core MVC, созданном из шаблона проекта Visual Studio 2017.

Указание ссылок на пакет

Добавьте ссылку на пакет NuGet OrchardCore.Localization.Core.

Теперь .csproj файл содержит строку, похожую на следующую (номер версии может отличаться):

<PackageReference Include="OrchardCore.Localization.Core" Version="1.0.0" />

Регистрация службы

Добавьте необходимые службы в ConfigureServices метод Startup.cs:

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc()
        .AddViewLocalization(LanguageViewLocationExpanderFormat.Suffix);

    services.AddPortableObjectLocalization();

    services.Configure<RequestLocalizationOptions>(options =>
        {
            var supportedCultures = new List<CultureInfo>
            {
                new CultureInfo("en-US"),
                new CultureInfo("en"),
                new CultureInfo("fr-FR"),
                new CultureInfo("fr")
            };

            options.DefaultRequestCulture = new RequestCulture("en-US");
            options.SupportedCultures = supportedCultures;
            options.SupportedUICultures = supportedCultures;
        });
}

Добавьте требуемое ПО промежуточного слоя в метод ConfigureStartup.cs:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseExceptionHandler("/Home/Error");
    }

    app.UseRouting();
    app.UseStaticFiles();

    app.UseRequestLocalization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllerRoute(name: "default", pattern: "{controller=Home}/{action=Index}/{id?}");
    });
}

Добавьте следующий код в нужное представление Razor. В этом примере используется About.cshtml.

@using Microsoft.AspNetCore.Mvc.Localization
@inject IViewLocalizer Localizer

<p>@Localizer["Hello world!"]</p>

Экземпляр IViewLocalizer внедряется и используется для перевода текста "Hello world!".

Создание файла PO

Создайте файл с именем <culture code>.po в корневой папке приложения. В этом примере файл имеет имя fr.po, так как используется французский язык:

msgid "Hello world!"
msgstr "Bonjour le monde!"

Данный файл содержит как строку на перевод, так и строку, переведенную на французский язык. При необходимости переводы возвращаются к своим родительским языку и региональным параметрам. В этом примере файл fr.po используется, если запрошены язык и региональные параметры fr-FR или fr-CA.

Тестирование приложения

Запустите приложение и перейдите по URL-адресу /Home/About. Отображается текст Hello world!.

Перейдите к URL-адресу /Home/About?culture=fr-FR. Отображается текст Bonjour le monde!.

Преобразование во множественную форму

Файлы PO поддерживают преобразование во множественную форму, что удобно, когда одну и ту же строку нужно переводить по-разному в зависимости от кратности. Эта задача осложняется тем, что каждый язык имеет собственные правила для выбора строк в зависимости от кратности.

Пакет локализации Orchard предоставляет API для автоматического вызова этих различных форм множественного числа.

Создание файлов PO с множественными формами

Добавьте в указанный ранее файл fr.po следующее содержимое:

msgid "There is one item."
msgid_plural "There are {0} items."
msgstr[0] "Il y a un élément."
msgstr[1] "Il y a {0} éléments."

Сведения о том, что означает каждая запись в этом примере, см. в разделе Что такое файл переносимых объектов?.

Добавление языка с использованием различных форм множественного числа

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

Подобные правила действуют не во всех языках. Это показано на примере чешского языка, где форм множественного числа три.

Создайте файл cs.po, как показано ниже, и обратите внимание, что для преобразования во множественную форму нужно три разных перевода:

msgid "Hello world!"
msgstr "Ahoj světe!!"

msgid "There is one item."
msgid_plural "There are {0} items."
msgstr[0] "Existuje jedna položka."
msgstr[1] "Existují {0} položky."
msgstr[2] "Existuje {0} položek."

Чтобы принять локализации на чешский язык, добавьте "cs" в список поддерживаемых языков и региональных параметров в методе ConfigureServices:

var supportedCultures = new List<CultureInfo>
{
    new CultureInfo("en-US"),
    new CultureInfo("en"),
    new CultureInfo("fr-FR"),
    new CultureInfo("fr"),
    new CultureInfo("cs")
};

Измените файл Views/Home/About.cshtml, чтобы отобразить локализованные строки с учетом множественного числа для нескольких кратностей.

<p>@Localizer.Plural(1, "There is one item.", "There are {0} items.")</p>
<p>@Localizer.Plural(2, "There is one item.", "There are {0} items.")</p>
<p>@Localizer.Plural(5, "There is one item.", "There are {0} items.")</p>

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

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

Для /Home/About:

There is one item.
There are 2 items.
There are 5 items.

Для /Home/About?culture=fr:

Il y a un élément.
Il y a 2 éléments.
Il y a 5 éléments.

Для /Home/About?culture=cs:

Existuje jedna položka.
Existují 2 položky.
Existuje 5 položek.

Обратите внимание, что для чешского языка все три перевода различаются. На французском и английском языках для двух последних переведенных строк используется одинаковая конструкция.

Расширенные задачи

Учет контекста строк

Приложения часто содержат переводимые строки в нескольких местах. Одна и та же строка, находящаяся в разных местах приложения (представления Razor или файлы классов), может переводиться по-разному. Файл PO поддерживает понятие контекста файла, которое можно использовать для классификации представляемых строк. В зависимости от контекста файла (или его отсутствия) строку можно перевести по-разному.

Службы локализации PO используют имя полного класса или представление, используемые при переводе строки. Это достигается путем установки значения для записи msgctxt.

Рассмотрим небольшое дополнение к предыдущему примеру fr.po. Представление Razor, расположенное в файле Views/Home/About.cshtml, можно определить в качестве контекста файла, задав зарезервированное значение записи msgctxt.

msgctxt "Views.Home.About"
msgid "Hello world!"
msgstr "Bonjour le monde!"

При такой настройке msgctxt перевод текста отображается при переходе по адресу /Home/About?culture=fr-FR. При переходе по адресу /Home/Contact?culture=fr-FR перевод не отображается.

Если с заданным контекстом файла не совпадает ни одна из конкретных записей, резервный механизм Orchard Core ищет соответствующий файл PO без контекста. Если предположить, что для Views/Home/Contact.cshtml никакой конкретный файловый контекст не задан, при переходе к /Home/Contact?culture=fr-FR загружается файл PO, как показано ниже.

msgid "Hello world!"
msgstr "Bonjour le monde!"

Изменение расположения для файлов PO

Расположение по умолчанию для файлов PO можно изменить в ConfigureServices:

services.AddPortableObjectLocalization(options => options.ResourcesPath = "Localization");

В этом примере файлы PO загружаются из папки Localization.

Реализация настраиваемой логики для поиска файлов локализации

Когда для поиска файлов PO требуется более сложная логика, можно реализовать интерфейс OrchardCore.Localization.PortableObject.ILocalizationFileLocationProvider и зарегистрировать его как службу. Это удобно, когда файлы PO могут храниться в различных расположениях или должны находиться в иерархии папок.

Использование языка с другими формами множественного числа по умолчанию

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

Можно использовать более универсальную перегрузку Plural(int count, string[] pluralForms, params object[] arguments), которая принимает строковый массив переводов.