Локализация FormFlow в Microsoft Bot Framework

Привет. Сегодня рассмотри процесс локализации FormFlow в Microsoft Bot Framework(BotBuilder SDK). А именно научим чат-бот работать с несколькими языками. Делая отступление, скажу, что будет сделан упор именно на FormFlow из-за того, что остальные компоненты BotBuilder SDK в плане локализации ничем особенным не выделяются.

Для начала создадим класс, необходимый для заполнения

public enum SexOptions
{
    Male,
    Female
};


public enum LangOptions
{
    Russian,
    English,
    Spanish,
    Italian,
    German,
    Chinese,
    Other
};

public enum MessengerOptions
{
    Skype,
    Telegram,
    Viber,
    WhatsApp,
    Bleep,
    FacebookMessenger,
    Icq
};

[Serializable]
public class InterviewInfo
{
    public string Name;

    public SexOptions? Sex;

    public LangOptions? Language;

    [Numeric(18, 100)]
    public int Age = 18;

    public List Messenger;

    public static IForm BuildForm()
    {
        var form = new FormBuilder<InterviewInfo>().Build();
        return form;
    }
};

Данный класс можно заполнять автоматически, используя возможности FowmFlow, используя подобный вызов:

await context.Forward(MakeInterviewDialog(), ResumeAfterNewDialog, activity, CancellationToken.None);

Вместо нового диалога, можно создать форму для заполнения.

internal static IDialog MakeInterviewDialog()
{
    return Chain.From(() => FormDialog.FromForm(InterviewInfo.BuildForm));
}

Выглядеть это будет следующем образом:

Если переключиться на русский язык

Как можно заметить, локализация для полей для класса InterviewInfo не меняется. Но элементы «интерфейсов» FormFlow самого BotBuilder SDK уже переведены на множество языков, в том числе на русский.

Мы можем получить файл ресурсов, сгенерированный из нашей модели, это можно сделать, вызвав IFormBuilder.SaveResources

Например, мы можем сохранить сгенерированный файл ресурсов:

var form = new FormBuilder<InterviewInfo>().Build();
var resourceWriter = new System.Resources.ResXResourceWriter(@"C:\temp\resGen.resx"); 
form.SaveResources(resourceWriter);
resourceWriter.Close();

Он будет иметь следующий вид:

<data name="Name_description;VALUE" xml:space="preserve">
  <value>Name</value>
</data>
<data name="Sex_description;VALUE" xml:space="preserve">
  <value>Sex</value>
</data>
<data name="SexOptions.Male;VALUE" xml:space="preserve">
  <value>Male</value>
</data>
<data name="SexOptions.Female;VALUE" xml:space="preserve">
  <value>Female</value>
</data>
<data name="Language_description;VALUE" xml:space="preserve">
  <value>Language</value>
</data>
<data name="LangOptions.Russian;VALUE" xml:space="preserve">
  <value>Russian</value>
</data>
<data name="LangOptions.English;VALUE" xml:space="preserve">
  <value>English</value>
</data>
<data name="LangOptions.Spanish;VALUE" xml:space="preserve">
  <value>Spanish</value>
</data>

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

Также, для генерации файла ресурсов можно воспользоваться утилитой RView, которая входит в состав BotBuilder SDK

Здесь можно увидеть её исходный код и разобраться, как именно идёт генерация: https://github.com/Microsoft/BotBuilder/blob/master/CSharp/Tools/RView/Program.cs

Вызов для генерации будет примерно следующий:

rview -g TestBot.dll TestBot.Models.BuildForm

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

Сперва следует установить язык проекта. Для этого в настройках проекта, выберем «Assembly Information». Я установил русский язык, именно он будет языком по умолчанию в проекте.

В BuildForm можно указать какую сборку и файл ресурсов нужно использовать:

var form = new FormBuilder<InterviewInfo>().Build(Assembly.GetAssembly(typeof(AutoResources)), "AutoResources");

После этого параметры, которые были переведены, отображаются на целевом языке:

Использовать сгенерированные файлы ресурсов не обязательно. Можно использовать атрибуты. Например, атрибут Describe позволяет задать имя для требуемой переменной.

[Describe("наименование")]
public string Name;

Для того чтобы использовать файлы ресурсов в подобных атрибутах, можно использовать собственные атрибуты, которые наследуются от тех, что вам необходимы. Например, для показанного Describe можно сделать следующее:

    public class LocalizableDescribeAttribute: DescribeAttribute
    {
        private readonly PropertyInfo _nameOfProperty;

        public LocalizableDescribeAttribute(string descriptionKey, Type resourceType, string description = null, string image = null, string message = null, string title = null, string subTitle = null)
            : base(description, image,message, title, subTitle)
        {
            if (resourceType != null)
            {               
                _nameOfProperty = resourceType.GetProperty(descriptionKey,
                    BindingFlags.Static | BindingFlags.Public);
            }

            if (_nameOfProperty != null)
            {
                Description = (string)_nameOfProperty.GetValue(_nameOfProperty.DeclaringType, null);
            }
            
        }
    }

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

[LocalizableDescribe("Name", typeof(Resources.Resources))]
public string Name;

Для атрибута Prompt можно сделать что-то следующее:

    public class LocalizablePromptAttribute : PromptAttribute
    {
        private readonly PropertyInfo _nameOfProperty;

        public LocalizablePromptAttribute(string descriptionKey, Type resourceType, string[] patterns = null)
            : base(patterns)
        {
            if (resourceType != null)
            {
                _nameOfProperty = resourceType.GetProperty(descriptionKey,
                    BindingFlags.Static | BindingFlags.Public);
            }

            if (_nameOfProperty != null)
            {
                Patterns = new[] { (string)_nameOfProperty.GetValue(_nameOfProperty.DeclaringType, null) };
            }

        }
    }

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

Приятного программирования.

Добавить комментарий