支持多语言的核心无非是,切换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}"/>