Перейти к содержанию

Расширение локализации для режима технического обслуживания

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

Файл с данными локализации

Вначале создадим файл с данными (localization.csv).

Name;Language;Value CustomMessage;ru;"Моё сообщение, в котором есть запятые; и переносы строк." CustomMessage;fr;"Mon message, qui contient des virgules; et les sauts de ligne." CustomMessage;;"My message, which has commas; and line breaks."

Tip

В данном случае использован нестандартный разделитель данных ;.

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

Название Описание
Name Название строки локализации. Обязательное.
Language Код языка локализации в формате ISO 639-1. Может быть не указан, если строка локализации подходит для всех языков (является универсальной).
Value Локализованная на указанном языке строка локализации.

Стратегия локализации

Для большей гибкости условимся, что будем задавать путь к файлу локализации в поле Localization.Csv. Для этого отредактируем файл app.json утилиты tadmin и добавим указанное поле следующим образом (всё остальное содержимое файла оставим без изменений).

{ "Settings": { "Maintenance": { "Localization.Csv": "c:/data/localization.csv", } } }

Important

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

Tip

Не забудьте либо поменять путь, либо поместить ваш файл с локализацией по указанному пути.

Important

Согласно принятым в команде tadmin Maintenance соглашениям, префикс Localization. будет отрезан и путь к файлу будет содержаться в дополнительных данных, предоставляемых команде по ключу Csv.

Заметим, что в нашем файле данных содержатся многострочные локализованные значения, которые также содержат специальные символы (, и ;), используемые в файле в качестве разделителей.

Чтобы упростить работу с файлом CSV и не выполнять разбор вручную, мы будем использовать специализированный пакет CsvHelper. Данный пакет уже содержится в зависимостях проекта Tessa.Extensions.Console.

Все стратегии, расширяющие локализацию для режима технического обслуживания, должны быть унаследованы от базового класса MaintenanceLocalizationStrategyBase. Создайте в проекте Tessa.Extensions.Console в директории Maintenance файл CsvMaintenanceLocalizationStrategy.cs следующего содержания.

#nullable enable

using System.Collections.Generic; using System.Globalization; using System.IO; using System.Threading; using System.Threading.Tasks; using CsvHelper; using CsvHelper.Configuration; using Tessa.Localization; using Tessa.Platform; using Tessa.Platform.Maintenance; using Tessa.Platform.Storage;

namespace Tessa.Extensions.Console.Maintenance { [Order(1)] public sealed class CsvMaintenanceLocalizationStrategy : MaintenanceLocalizationStrategyBase { #region Internal Classes

private class DataRecord { public string Name { get; set; } = string.Empty; public string? Language { get; set; } public string Value { get; set; } = string.Empty; }

private class DataMap : ClassMap<DataRecord> { public DataMap() { this.Map(static m => m.Name).Name("Name").Index(0); this.Map(static m => m.Language).Name("Language").Index(1); this.Map(static m => m.Value).Name("Value").Index(2); } }

#endregion

#region Private Fields

private const string CsvFileKey = "Csv";

#endregion

#region Base Overrides

/// <inheritdoc /> public override bool ShouldOverride() => true;

/// <inheritdoc /> public override async ValueTask<LocalizationEntryCollection> GetEntriesAsync( IReadOnlySet<string> names, IDictionary<string, object?> args, CancellationToken cancellationToken = default) { var collection = new LocalizationEntryCollection(); var filePath = args?.TryGet<string>(CsvFileKey) ?? string.Empty;

if (string.IsNullOrEmpty(filePath)) { return collection; }

var configuration = new CsvConfiguration(CultureInfo.InvariantCulture) { Delimiter = ";", };

using var reader = new StreamReader(filePath); using var csv = new CsvReader(reader, configuration); csv.Context.RegisterClassMap<DataMap>(); await foreach (var record in csv.GetRecordsAsync<DataRecord>(cancellationToken)) { if (!collection.TryGetItem(record.Name, out var entry)) { entry = new LocalizationEntry(record.Name); collection[entry.Name] = entry; }

var str = new LocalizationString(GetCultureInfo(record.Language), record.Value); entry.Strings[str.Culture] = str; }

return collection; }

#endregion

#region Private Methods

private static CultureInfo GetCultureInfo(string? lang) => string.IsNullOrEmpty(lang) || lang == CultureInfo.InvariantCulture.TwoLetterISOLanguageName ? CultureInfo.InvariantCulture : CultureInfo.GetCultureInfo(lang);

#endregion } }

Important

Следует обратить внимание на атрибут [Order(1)], указанный у данного класса. Он определяет условный номер данной стратегии в цепочке стратегий, использующихся для построения библиотеки локализации. Чем меньше номер, тем раньше будет вызвана стратегия и тем раньше она наполнит итоговую библиотеку. По умолчанию строки локализации не переопределяются, а могут лишь дополнить библиотеку, если строк с такими же именами в ней ещё нет. Поэтому порядок следования стратегии существенно влияет на её вклад в формировании итоговой библиотеки локализации. Подробнее о приоритетах (order) стандартных стратегий.

Important

Второй момент, на который необходимо обратить внимание - это метод ShouldOverride. Он указывает на то, что строки, возвращаемые библиотекой, должны полностью заменить аналогичные строки в итоговой библиотеке локализации. Если вы не уверены в подобной необходимости, используйте реализацию по умолчанию, возвращающую false.

Important

Обратите внимание, что стратегия локализации может вызываться при уже недоступном основном web-сервисе TESSA. В этом случае вы не сможете использовать большинство стандартного API. Определить режим работы можно при помощи ISessionTokenHolder.SessionToken (если он равен null, то API недоступно) так, как это делается в LocalizationServiceMaintenanceLocalizationStrategy.GetEntriesAsync.

Теперь зарегистрируем нашу стратегию. Создайте класс Registrator.cs в той же директории, что и только что созданный нами класс, со следующим содержимым:

#nullable enable

using Tessa.Platform.Maintenance; using Unity; using Unity.Lifetime;

namespace Tessa.Extensions.Console.Maintenance { [Registrator(Tag = RegistratorTag.ConsoleClient)] public sealed class Registrator : RegistratorBase { public override void RegisterUnity() { this.UnityContainer // Регистрация сервиса получения строк локализации для режима техобслуживания. .RegisterType<IMaintenanceLocalizationStrategy, CsvMaintenanceLocalizationStrategy>(nameof(CsvMaintenanceLocalizationStrategy), new ContainerControlledLifetimeManager()) ; } } }

На этом создание стратегии предоставления строк локализации для режима технического обслуживания завершено.

Back to top