如何在 FormFlow(Bot Builder C# SDK)中使用 IFormBuilder.SaveResources 创建资源文件
How to create resourse file using IFormBuilder.SaveResources in FormFlow (Bot Builder C# SDK)
我需要将 FormFlow 中的所有字符串和枚举本地化为德语。我看过 https://docs.microsoft.com/en-us/bot-framework/dotnet/bot-builder-dotnet-formflow-localize
它说有两种方法。一个使用 IFormBuilder.SaveResources,第二个使用 RView 工具(我无法弄清楚)。
如何使用第一种方法生成和保存德语和英语的 .resx 文件,就像在 AnnotatedSandwich Bot 中一样?
- 比如下面的BuildLocalizeForm(),我应该把生成什么代码放在什么地方.resx,.de.resx 和 .en.resx 文件
这是示例:https://github.com/Microsoft/BotBuilder/tree/master/CSharp/Samples/AnnotatedSandwichBot
public static IForm<SandwichOrder> BuildLocalizedForm()
{
var culture = Thread.CurrentThread.CurrentUICulture;
IForm<SandwichOrder> form;
if (!_forms.TryGetValue(culture, out form))
{
OnCompletionAsyncDelegate<SandwichOrder> processOrder = async (context, state) =>
{
await context.PostAsync(DynamicSandwich.Processing);
};
// Form builder uses the thread culture to automatically switch framework strings
// and also your static strings as well. Dynamically defined fields must do their own localization.
var builder = new FormBuilder<SandwichOrder>()
.Message("Welcome to the sandwich order bot!")
.Field(nameof(Sandwich))
.Field(nameof(Length))
.Field(nameof(Bread))
.Field(nameof(Cheese))
.Field(nameof(Toppings),
validate: async (state, value) =>
{
var values = ((List<object>)value).OfType<ToppingOptions>();
var result = new ValidateResult { IsValid = true, Value = values };
if (values != null && values.Contains(ToppingOptions.Everything))
{
result.Value = (from ToppingOptions topping in Enum.GetValues(typeof(ToppingOptions))
where topping != ToppingOptions.Everything && !values.Contains(topping)
select topping).ToList();
}
return result;
})
.Message("For sandwich toppings you have selected {Toppings}.")
.Field(nameof(SandwichOrder.Sauces))
.Field(new FieldReflector<SandwichOrder>(nameof(Specials))
.SetType(null)
.SetActive((state) => state.Length == LengthOptions.FootLong)
.SetDefine(async (state, field) =>
{
field
.AddDescription("cookie", DynamicSandwich.FreeCookie)
.AddTerms("cookie", Language.GenerateTerms(DynamicSandwich.FreeCookie, 2))
.AddDescription("drink", DynamicSandwich.FreeDrink)
.AddTerms("drink", Language.GenerateTerms(DynamicSandwich.FreeDrink, 2));
return true;
}))
.Confirm(async (state) =>
{
var cost = 0.0;
switch (state.Length)
{
case LengthOptions.SixInch: cost = 5.0; break;
case LengthOptions.FootLong: cost = 6.50; break;
}
return new PromptAttribute(string.Format(DynamicSandwich.Cost, cost) + "{||}");
})
.Field(nameof(SandwichOrder.DeliveryAddress),
validate: async (state, response) =>
{
var result = new ValidateResult { IsValid = true, Value = response };
var address = (response as string).Trim();
if (address.Length > 0 && address[0] < '0' || address[0] > '9')
{
result.Feedback = DynamicSandwich.BadAddress;
result.IsValid = false;
}
return result;
})
.Field(nameof(SandwichOrder.DeliveryTime), "What time do you want your sandwich delivered? {||}")
.Confirm("Do you want to order your {Length} {Sandwich} on {Bread} {&Bread} with {[{Cheese} {Toppings} {Sauces}]} to be sent to {DeliveryAddress} {?at {DeliveryTime:t}}?")
.AddRemainingFields()
.Message("Thanks for ordering a sandwich!")
.OnCompletion(processOrder);
builder.Configuration.DefaultPrompt.ChoiceStyle = ChoiceStyleOptions.Auto;
form = builder.Build();
_forms[culture] = form;
}
return form;
}
行前
form = builder.Build();
您可以通过 IResourceWriter
.
调用 builder.SaveResources
要了解如何创建 ResourceWriter
,请阅读 https://msdn.microsoft.com/en-us/library/system.resources.resourcewriter(v=vs.110).aspx,但它基本上类似于:
ResourceWriter writer = new ResourceWriter("myResources.resources");
不过,我认为您应该选择 RView 选项。您没有按照这些步骤操作,就像让 Rview 工具位于 DLL 所在的同一路径或调用 RView 将完整路径传递给 DLL 一样简单。
我需要将 FormFlow 中的所有字符串和枚举本地化为德语。我看过 https://docs.microsoft.com/en-us/bot-framework/dotnet/bot-builder-dotnet-formflow-localize 它说有两种方法。一个使用 IFormBuilder.SaveResources,第二个使用 RView 工具(我无法弄清楚)。 如何使用第一种方法生成和保存德语和英语的 .resx 文件,就像在 AnnotatedSandwich Bot 中一样?
- 比如下面的BuildLocalizeForm(),我应该把生成什么代码放在什么地方.resx,.de.resx 和 .en.resx 文件
这是示例:https://github.com/Microsoft/BotBuilder/tree/master/CSharp/Samples/AnnotatedSandwichBot
public static IForm<SandwichOrder> BuildLocalizedForm()
{
var culture = Thread.CurrentThread.CurrentUICulture;
IForm<SandwichOrder> form;
if (!_forms.TryGetValue(culture, out form))
{
OnCompletionAsyncDelegate<SandwichOrder> processOrder = async (context, state) =>
{
await context.PostAsync(DynamicSandwich.Processing);
};
// Form builder uses the thread culture to automatically switch framework strings
// and also your static strings as well. Dynamically defined fields must do their own localization.
var builder = new FormBuilder<SandwichOrder>()
.Message("Welcome to the sandwich order bot!")
.Field(nameof(Sandwich))
.Field(nameof(Length))
.Field(nameof(Bread))
.Field(nameof(Cheese))
.Field(nameof(Toppings),
validate: async (state, value) =>
{
var values = ((List<object>)value).OfType<ToppingOptions>();
var result = new ValidateResult { IsValid = true, Value = values };
if (values != null && values.Contains(ToppingOptions.Everything))
{
result.Value = (from ToppingOptions topping in Enum.GetValues(typeof(ToppingOptions))
where topping != ToppingOptions.Everything && !values.Contains(topping)
select topping).ToList();
}
return result;
})
.Message("For sandwich toppings you have selected {Toppings}.")
.Field(nameof(SandwichOrder.Sauces))
.Field(new FieldReflector<SandwichOrder>(nameof(Specials))
.SetType(null)
.SetActive((state) => state.Length == LengthOptions.FootLong)
.SetDefine(async (state, field) =>
{
field
.AddDescription("cookie", DynamicSandwich.FreeCookie)
.AddTerms("cookie", Language.GenerateTerms(DynamicSandwich.FreeCookie, 2))
.AddDescription("drink", DynamicSandwich.FreeDrink)
.AddTerms("drink", Language.GenerateTerms(DynamicSandwich.FreeDrink, 2));
return true;
}))
.Confirm(async (state) =>
{
var cost = 0.0;
switch (state.Length)
{
case LengthOptions.SixInch: cost = 5.0; break;
case LengthOptions.FootLong: cost = 6.50; break;
}
return new PromptAttribute(string.Format(DynamicSandwich.Cost, cost) + "{||}");
})
.Field(nameof(SandwichOrder.DeliveryAddress),
validate: async (state, response) =>
{
var result = new ValidateResult { IsValid = true, Value = response };
var address = (response as string).Trim();
if (address.Length > 0 && address[0] < '0' || address[0] > '9')
{
result.Feedback = DynamicSandwich.BadAddress;
result.IsValid = false;
}
return result;
})
.Field(nameof(SandwichOrder.DeliveryTime), "What time do you want your sandwich delivered? {||}")
.Confirm("Do you want to order your {Length} {Sandwich} on {Bread} {&Bread} with {[{Cheese} {Toppings} {Sauces}]} to be sent to {DeliveryAddress} {?at {DeliveryTime:t}}?")
.AddRemainingFields()
.Message("Thanks for ordering a sandwich!")
.OnCompletion(processOrder);
builder.Configuration.DefaultPrompt.ChoiceStyle = ChoiceStyleOptions.Auto;
form = builder.Build();
_forms[culture] = form;
}
return form;
}
行前
form = builder.Build();
您可以通过 IResourceWriter
.
builder.SaveResources
要了解如何创建 ResourceWriter
,请阅读 https://msdn.microsoft.com/en-us/library/system.resources.resourcewriter(v=vs.110).aspx,但它基本上类似于:
ResourceWriter writer = new ResourceWriter("myResources.resources");
不过,我认为您应该选择 RView 选项。您没有按照这些步骤操作,就像让 Rview 工具位于 DLL 所在的同一路径或调用 RView 将完整路径传递给 DLL 一样简单。