繁体   English   中英

使用动态内容本地化WPF

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM