支援多語言的核心無非是,切換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 Headernamespace 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}"/>