FluentValidation 實作多國語系紀錄
關鍵問題資訊
FluentValidation 本身已支援多國語系。在錯誤訊息會依當時語系跳出相應語系錯誤訊息,不過其中的 {PropertyName}
的語系應沒有多國的欄位名稱設定所以不會應語系變更。解法已知有二:
一、可以使用.WithName()
指令指定錯誤訊息的{PropertyName}
。
二、改寫DisplayNameResolver
,經由自訂的PropertyNameAttribute
欄位屬性拿取當時語系的{PropertyName}
。
多國語系時的自訂錯誤訊息問題
自訂訊息就用 .WithMessage()
指令指定錯誤訊息。
實作相關技術-如何取得現在語系
CultureInfo.CurrentCulture Property // 取得當時語系
CultureInfo.CurrentUICulture Property // 取得當時UI語系
開發環境
平台: .NET6 IDE: Visual Studio 2022 框架: Blazor WASM App
程式碼紀錄 - DisplayNameResolver
DisplayNameResolver
自訂 PropertyNameAttribute
[AttributeUsage(
AttributeTargets.Field |
AttributeTargets.Property,
AllowMultiple = true)]
public class PropertyNameAttribute : Attribute
{
public string Name { get; set; }
public string Culture { get; set; }
public PropertyNameAttribute(string name)
{
Name = name;
Culture = string.Empty;
}
public PropertyNameAttribute(string name, string culture)
{
Name = name;
Culture = culture;
}
}
經由 PropertyNameAttribute 指定多國語系欄位名稱,範例:
public class OrderModel
{
[PropertyName("名稱", "zh-TW")]
[PropertyName("Name", "en-US")]
public string Name { get; set; } = "郝聰明";
[PropertyName("信用卡號", "zh-TW")]
[PropertyName("Credit card No", "en-US")]
public string CCNumber { get; set; } = "4012 8888 8888 1881";
[PropertyName("地址", "zh-TW")]
[PropertyName("Address", "en-US")]
public AddressModel Address { get; set; } = new AddressModel();
[...略...]
}
實作 DisplayNameResolver
依解析多國語系欄位名稱
/// global type handling helper
public static class GT
{
/// 於 FluentValidation 註冊 DisplayNameResolver 解析程序。
public static string? ResolveDisplayName(MemberInfo member)
{
//## 支援多國語系,情境如下:
//# 依 [PropertyName("欄位名稱","zh-TW")] 取 PropertyName,限定語系為 "zh-TW"
//# 依 [PropertyName("欄位名稱","en-US")] 取 PropertyName,限定語系為 "en-US"
//# 依 [PropertyName("欄位名稱")] 取 PropertyName 不指定語系
string culture = CultureInfo.CurrentUICulture.Name; // 取現在語系
var withPropertyName = member?.GetCustomAttributes(typeof(PropertyNameAttribute), false)
.Select(property => (PropertyNameAttribute)property)
.Where(c => c.Culture == culture || c.Culture == string.Empty)
.OrderByDescending(c => c.Culture)
.FirstOrDefault();
if (withPropertyName != null) return withPropertyName.Name;
return null;
}
}
套入 FluentValidation 以解析出多國語系欄位名稱
//## 多國語系 - FluentValidation
//※ 系統一開始就執行此註冊動作,就是 Program.cs 第一行執行指令。
FluentValidation.ValidatorOptions.Global.DisplayNameResolver =
(type, member, expression) => GT.ResolveDisplayName(member);
程式碼紀錄 - WithName
WithName
直接在 Fluent 的 Validattor 依現在語系指定多國欄位名稱。
/// 客製錯誤訊
public class OrderValidator : AbstractValidator<OrderModel>
{
public OrderValidator()
{
var culture = CultureInfo.CurrentUICulture; //取現在語系
bool zhTW = culture.Name == "zh-TW";
bool enUS = culture.Name == "en-US";
// 比如未修改前是這樣
RuleFor(x => x.Name)
.NotEmpty()
.Length(1, 20);
// 依語系指定欄位名稱。
RuleFor(x => x.Name)
.NotEmpty()
.Length(1, 3)
.WithName(x => zhTW ? "名稱" : "Name");
// 依語系指定完整錯誤訊息。
RuleFor(x => x.Name)
.NotEmpty().WithMessage(zhTW ? "{PropertyName} 不可空白哦~" : "{PropertyName} no empty ~。")
.Length(1, 3).WithMessage(zhTW ? "{PropertyName} 長度不合3~" : "{PropertyName} length invalid ~。")
.WithName(x => zhTW ? "客製化名稱" : "Customized Name");
[...略...]
}
}
完整程式碼
參考文章
Last updated