[英]Localize WPF with dynamic content
我是WPF的新手,但想使用XAML中定义的UI构建Windows应用程序,该UI从一开始就支持本地化。 不仅需要对UI元素进行本地化,而且数据库中还包含许多内容 。
我已经建立了一个数据库结构以能够保存本地化的信息,但是我不确定如何根据所选的语言环境显示该信息,例如“ en-US”或“ de-DE”。
如何以WPF / XAML自然的方式将本地化的文本提供给XAML UI元素? 我不想依赖任何第三方代码,如WPFLocalizationExtension 。
我已经看到资源文件如何做到这一点,但是它将仅支持对已知UI元素的本地化,而不支持动态生成的内容。
是否有我应该实施的特定提供者,或者我缺少完全不同的东西?
我最终解决此问题的方式如下。 记住,我需要从数据库/远程api中提取本地化的文本。
使用此解决方案,我可以像这样进行数据绑定,并且当我更改语言时,所有绑定的文本将自动更改:
<Label Content="{Binding Path=Strings.ErrorLevelColumnHeaderLabel}"/>
当然,必须可以从所有数据上下文访问Strings
对象。
字符串存储在如下所示的数据库表中,一个ID列和每种支持的语言的一列:
ID en da de
24 'Level' 'Niveau' 'Stufe'
我创建了一个UIStringsVM
类,该类实现了INotifyPropertyChanged
接口。 在我的示例中,我已经在名为Observable
的基类中实现了这一点,我敢肯定,还有很多其他的类。 有关详细信息,请参见此答案 。
public class UIStringsVM : Observable
{
public static UIStringsVM CurrentStringsInstance;
private bool stringsAreLoading = false;
private Dictionary<int, string> stringDictionary;
}
UIStringsVM
类为需要本地化的每个字符串都有一个属性。 因为该类通过基类支持INotifyPropertyChanged
接口,所以我可以依赖于更改语言时将其反映在UI中。
在UIStringsVM
类内部,当前语言的字符串存储在Dictionary<int, string>
。 原因是我可以使用数据库中的字符串ID来访问正确的字符串。
现在,我可以使用属性Get方法中的ID返回该值存储的任何字符串。 因此,属性将如下所示:
public string ErrorLevelColumnHeaderLabel
{
get =>
this.stringDictionary[24].Replace("\\n", Environment.NewLine);
private set =>
this.stringDictionary[24] = value;
}
这些属性永远不会单独设置,因此可以忽略设置器。
构造函数:
public UIStringsVM()
{
this.stringDictionary = new Dictionary<int, string>();
// Initialize with default values. The ! at the end makes it easier to identify missing values in the database.
this.LoginButtonText = "Login!";
this.LogoutButtonText = "Logout!";
this.UserLabelFormatString = "{0} logged in!";
this.ErrorLevelColumnHeaderLabel = "Level!";
UIStringsVM.CurrentStringsInstance = this;
}
为了加载字符串,我使用以下方法:
public async Task LoadStringsAsync(string languageCode, CancellationToken ct)
{
if (languageCode.Length != 2)
throw new ArgumentException("languageCode must be exactly 2 characters.", nameof(languageCode));
this.StringsAreLoading = true;
var client = new UIStringsClient(AppVM.BaseURL);
try
{
var apiStrings = await client.GetByLanguageAsync(languageCode, ct);
foreach (var r in apiStrings)
{
/* Note: this will make it impossible to overwrite a string with an empty string from the database,
* thus always keeping the string defined in this class' constructor. However strings will always
* have a value as defined in the constructor even if one does not exist in the database.
* */
if (string.IsNullOrWhiteSpace(r.Value))
continue;
this.stringDictionary[r.Key] = r.Value;
}
this.OnPropertyChanged((string)null); // Raise a change event for the entire object, not just a named property
}
finally
{
this.StringsAreLoading = false;
}
}
希望这对可能碰到这个较晚答案的人有所帮助。 我已经运行了15个月左右的解决方案,并且与它一起工作真的很棒。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.