如何用最简单的方法让WPF程序支持多国语言,并且语言文字用户可以随意编辑?

支持多语言的核心无非是,切换Applicaion级别的ResourceDictionary

 

语言文件随意编辑,无非是在程序启动时,加载一下某个资源文件而已。

 

为了支持界面使用多语言,我们自己定义了一个Resource扩展标记。

 

同时,为了防止,用户误将语言资源删除,而引起界面无任何文字的情况,我们内部定义了一个默认的资源文件,这样就不会没有显示了。

 

资源文件的目录结构:

Languages目录下有Default.xaml, en-US.xaml, zh-CN.xaml等

 

先上核心读取类LanguageReader:

 

#region Header

/**
 * <pre>
 *
 *  Work Force Management
 *  File: LanguageReader.cs
 *
 *  Grandsys, Inc.
 *  Copyright (C): 2009
 *
 *  Description:
 *  Init LanguageReader
 *
 *  Note
 *  Created By: Prime Li at 7/15/2009 2:10:04 PM
 *
 * </pre>
 */

#endregion Header

namespace Luna.Globalization
{
    using System;
    using System.Globalization;
    using System.IO;
    using System.Windows;
    using System.Windows.Markup;

    /// <summary>
    /// Read the Language
    /// </summary>
    public static class LanguageReader
    {
        #region Fields

        private const string LANGUAGE_PATH = @".\Languages\";
        private const string RESOURCE_FILE = @".\Resources\ApplicationResource.xaml";
        private static ResourceDictionary _currentLanguage;
        private static ResourceDictionary _defaultLanguage;

        #endregion Fields

        static LanguageReader()
        {
            Uri uri = new Uri("Luna.Globalization;component/Languages/default.xaml", UriKind.RelativeOrAbsolute);
            _defaultLanguage = Application.LoadComponent(uri) as ResourceDictionary;
            _currentLanguage = _defaultLanguage;
        }

        #region Methods

        /// <summary>
        /// Loads the specified culture.
        /// </summary>
        /// <param name="culture">The culture.</param>
        public static void Load(string culture)
        {
            bool isExistLanguage = CheckLanguageName(culture);
            if (isExistLanguage)
            {
                string path = LANGUAGE_PATH + culture + ".xaml";
                using (FileStream fs = File.OpenRead(path))
                {
                    _currentLanguage = XamlReader.Load(fs) as ResourceDictionary;
                    if (Application.Current.Resources.MergedDictionaries.Contains(_currentLanguage))
                    {
                        Application.Current.Resources.MergedDictionaries.Remove(_currentLanguage);
                    }

                    Application.Current.Resources.MergedDictionaries.Add(_currentLanguage);
                }

                Application.Current.Dispatcher.Thread.CurrentCulture = CultureInfo.GetCultureInfo(culture);
                Application.Current.Dispatcher.Thread.CurrentUICulture = CultureInfo.GetCultureInfo(culture);
            }
            else
            {
                //Use default Language
                Application.Current.Dispatcher.Thread.CurrentCulture = CultureInfo.GetCultureInfo("zh-CN");
                Application.Current.Dispatcher.Thread.CurrentUICulture = CultureInfo.GetCultureInfo("zh-CN");
            }
        }

        public static void LoadResource(string fileName)
        {
            if (File.Exists(fileName))
            {
                using (FileStream fs = File.OpenRead(fileName))
                {
                    ResourceDictionary dic = XamlReader.Load(fs) as ResourceDictionary;
                    Application.Current.Resources.MergedDictionaries.Add(dic);
                }
            }
        }

        public static void LoadDefaultResource()
        {
            LoadResource(RESOURCE_FILE);
        }

        /// <summary>
        /// Gets the value.
        /// </summary>
        /// <param name="key">The key.</param>
        /// <returns></returns>
        public static string GetValue(string key)
        {
            object value = GetValue((object)key);
            if (value == null)
                return string.Empty;
            return value.ToString();
        }

        /// <summary>
        /// Gets the value.
        /// </summary>
        /// <param name="key">The key.</param>
        /// <returns></returns>
        public static object GetValue(object key)
        {
            object value = _currentLanguage[key];
            if (value == null)
                value = _defaultLanguage[key];
            return value;
        }

        /// <summary>
        /// Gets the value.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key">The key.</param>
        /// <returns></returns>
        public static T GetValue<T>(object key)
        {
            object value = GetValue(key);
            if (value == null)
                return default(T);
            return (T)value;
        }

        public static bool ContainsKey(string key)
        {
            return ContainsKey((object)key);
        }

        public static bool ContainsKey(object key)
        {
            return _currentLanguage.Contains(key) || _defaultLanguage.Contains(key);
        }

        /// <summary>
        /// Checks the name of the language.
        /// </summary>
        /// <param name="languageName">Name of the language.</param>
        /// <returns></returns>
        private static bool CheckLanguageName(string languageName)
        {
            var allLanguageNames = Directory.GetFiles(LANGUAGE_PATH);
            foreach (var name in allLanguageNames)
            {
                if (name.Contains(languageName))
                {
                    return true;
                }
            }

            return false;
        }

        #endregion Methods
    }
}

然后就是自己的Resource扩展标记

 

using System;
using System.Windows;
using System.Windows.Markup;

namespace Luna.Globalization
{
    [MarkupExtensionReturnType(typeof(object)), Localizability(LocalizationCategory.NeverLocalize)]
    public class ResourceExtension : MarkupExtension
    {
        public ResourceExtension()
        { }

        public ResourceExtension(object key)
        {
            Key = key;
        }

        public override object ProvideValue(IServiceProvider serviceProvider)
        {
            return LanguageReader.GetValue(Key);
        }

        [ConstructorArgument("Key")]
        public object Key
        { get; set; }
    }
}

如何使用?

在App.config里面配置:

 

<add key="Language" value="zh-TW" />

在App.xaml.cs的启动时加载:

 

LanguageReader.Load(ConfigurationManager.AppSettings["Language"]);

 

 

在XAML文件里面使用:

 

 

<TextBlock Text="{inf:Resource OK}"/>

 

posted @ 2010-01-23 21:55  primeli  阅读(545)  评论(0编辑  收藏  举报