如何按文化加载 ResourceDictionary

How to load a ResourceDictionary by culture

欢迎使用我在此建议的方法以外的任何其他方法。

我有一个项目,我正在尝试使用 XAML 资源字典来管理本地化。为了避免必须在我所有的代码隐藏文件上实现本地化加载,我编写了以下转换器:

public class LocalizationConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        string filePrefix = value as string;

        string language;

        // Filter so only supported languages are let through
        switch (culture.Name.Substring(0, 2))
        {
            case "da":
                language = "da";
                break;

            default:
                language = "en";
                break;
        }

        return filePrefix + "." + language + ".xaml";
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

如何编写 XAML 加载语言词典,将文件前缀作为值?

第一步是卸载当前的语言资源字典,否则你将拥有大量合并的资源字典,它们什么都不做。

最好将所有语言文件放在一个文件夹中,如下所示:

现在,考虑以下方法:

public static void ReplaceLanguage(Uri source)
    {
        //The name of the folder where the languages are contained (could be a parameter)
        string folder = "languages";

        if (source == null)
            return;

        ResourceDictionary dictionary;

        try
        {
            dictionary = (ResourceDictionary)Application.LoadComponent(source);
        }
        catch (IOException)
        {
            //resource file doesn't exist.
            return;
        }

        //Remove current resource from the merged dictionaries
        var currentResource = Application.Current.Resources.MergedDictionaries.FirstOrDefault(x => x.Source != null && x.Source.ToString().Contains(folder));

        if (currentResource != null)
            Application.Current.Resources.MergedDictionaries.Remove(currentResource);

        //Add the new resource to the dictionary
        Application.Current.Resources.MergedDictionaries.Add(dictionary);
    }

这个方法的作用是:

  1. 从 URI 源加载资源字典。
  2. 根据文件夹名称查找并删除当前语言词典。
  3. 将新词典添加到合并的词典列表中。

要获取语言文件的 Uri,您可以这样做:

Uri languagePath = new Uri(string.Format("/YourAppNamespace;component/resources/languages/{0}.xaml", language), UriKind.Relative);

以上代码假定您的语言文件命名为 de.xamlen.xaml.

获得 Uri 后,您需要做的就是调用 ReplaceLanguage 方法。

好的。我最终使用静态方法来加载我的本地化。方法如下:

/// <summary>
/// Loads localization based on culture.
/// </summary>
/// <param name="dictionary">The dictionary to load localization to</param>
/// <param name="basePath">The base path of the localization files. See remarks for further info.</param>
/// <param name="cultureInfo">Culture to load localization for.</param>
/// <remarks>
/// The loaded localization file will be <code>basenameLocalization.languagecode.xaml</code>
/// (e.g. <code>MainWindowLocalization.de.xaml</code>), or <code>basenameLocalization.languagecode.xaml</code>
/// for the default localization.
/// </remarks>
internal static void ReplaceLocalization(
    ResourceDictionary dictionary,
    string basePath,
    CultureInfo cultureInfo)
{
    ResourceDictionary dict = new ResourceDictionary();

    // Clean out old localization
    ResourceDictionary oldLocalization = null;
    foreach (ResourceDictionary d in dictionary.MergedDictionaries)
    {
        if (d.Source.OriginalString.StartsWith(basePath + "Localization."))
        {
            oldLocalization = d;
        }
    }
    if (oldLocalization != null)
    {
        dictionary.MergedDictionaries.Remove(oldLocalization);
    }

    // Get thee language
    string language = "";
    if (cultureInfo.Name != null)
    {
        // We only need to look at the first two characters to determine language
        language = cultureInfo.Name.Substring(0, 2);
    }
    bool defaultLanguage = false;

    // Filter languages such that only supported languages are loadable,
    // and any other defaults to the default/neutral language.
    switch (language)
    {
        case "da":
            break;

        default:
            defaultLanguage = true;
            break;
    }

    // Construct the URI
    string uri;
    if (defaultLanguage)
    {
        uri = basePath + "Localization.xaml";
    }
    else
    {
        uri = basePath + "Localization." + language + ".xaml";
    }

    // Load new dictionary
    dict.Source = new Uri(uri, UriKind.Relative);
    dictionary.MergedDictionaries.Add(dict);
}

这也适用于在运行时更改语言。

请评论任何问题,以便我改进我的回答。