C# - 在程式中加入全球化(Globalization)機制

在這個地球村的時代下,一個軟體要廣泛讓世界各地的大眾使用就要考慮到各地的語言文化。我們常常在一些大型的國際網站上看到可以選擇語言,然後網站就會轉換成對應的語言,這個機制為全球化(Globalization),在 .Net是有此機制的,所以今天限量就要來簡單說明如何在 .Net的程式中加入 Globalization


Globalization的實作有幾個主要關鍵,CultureInfoResources File(.resx)

CultureInfo 是 .Net中的一個類別,它代表的是一個文化,在日期, 字串, 數字相關類別中的方法可以看的到它的一些蹤影。

Resources File 的副檔名為 .resx 是 .Net專案中集中資源的地方,它可以放置影像, 二進制數值, 字串, 圖示, 音訊與其他種類型的資源,Resource File 與 Culture 可以搭配使用,各種 Culture 的可有對應的 Resource File,其命名規則如下:[File Name].[Culture Code].resx,例如:ErrorCode.zh-TW.resx, ErrorCode.en-US.resx。

接下來就來按照步驟加入 Globalization 吧:

首先先加入預設 Culture 的 Resources File,在專案按右鍵 [加入新項目] => 選擇 [Resources File]加入。

*注意:預設的 Resource File 一定要加入,因為VS會根據這個檔案自動產生處理資源的類別,所以如果沒有的話就會無法取得資源檔。

接著編輯資源檔。

再來依照同樣步驟加入另一個 Culture 的 Resources File 並編輯。

*注意:各 Culture 內的資源數量與 Name 要一致,因為程式會使用 Name 去抓取對應的資源。

建立完成後可以看到VS幫我們建立了一個 CodeMsg.Designer.cs 的檔案,這個檔案就是讓我們可以在開發時期去呼叫的資源類別,類別名稱與 Resources File 檔名相同,剛剛所定義的字串皆可以直接調用取得值。

CodeMsg.Designer.cs
//------------------------------------------------------------------------------
// 
//     This code was generated by a tool.
//     Runtime Version:4.0.30319.42000
//
//     Changes to this file may cause incorrect behavior and will be lost if
//     the code is regenerated.
// 
//------------------------------------------------------------------------------

namespace TestSolution {
    using System;
    
    
    /// 
    ///   A strongly-typed resource class, for looking up localized strings, etc.
    /// 
    // This class was auto-generated by the StronglyTypedResourceBuilder
    // class via a tool like ResGen or Visual Studio.
    // To add or remove a member, edit your .ResX file then rerun ResGen
    // with the /str option, or rebuild your VS project.
    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
    [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
    internal class CodeMsg {
        
        private static global::System.Resources.ResourceManager resourceMan;
        
        private static global::System.Globalization.CultureInfo resourceCulture;
        
        [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
        internal CodeMsg() {
        }
        
        /// 
        ///   Returns the cached ResourceManager instance used by this class.
        /// 
        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
        internal static global::System.Resources.ResourceManager ResourceManager {
            get {
                if (object.ReferenceEquals(resourceMan, null)) {
                    global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("TestSolution.CodeMsg", typeof(CodeMsg).Assembly);
                    resourceMan = temp;
                }
                return resourceMan;
            }
        }
        
        /// 
        ///   Overrides the current thread's CurrentUICulture property for all
        ///   resource lookups using this strongly typed resource class.
        /// 
        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
        internal static global::System.Globalization.CultureInfo Culture {
            get {
                return resourceCulture;
            }
            set {
                resourceCulture = value;
            }
        }
        
        /// 
        ///   Looks up a localized string similar to 錯誤.
        /// 
        internal static string REPLY_ERROR {
            get {
                return ResourceManager.GetString("REPLY_ERROR", resourceCulture);
            }
        }
        
        /// 
        ///   Looks up a localized string similar to 正確.
        /// 
        internal static string REPLY_OK {
            get {
                return ResourceManager.GetString("REPLY_OK", resourceCulture);
            }
        }
    }
}


另外,如果不想用產生出來的資源檔類別來存取資源的時候,可以自己使用ResourceManager GetString GetXXX 的方式來取得,因為VS把資源的Name Build 成 Property,這樣動態使用起來比較不方便。

以下使用 ResourceManager 取得資源的範例程式:

Program.cs
class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine("Enter culture code: ");
        var culture = Console.ReadLine();

        if(!string.IsNullOrWhiteSpace(culture))
        {
            // 取得目前主執行續並設定ResourceManager的Culture
            Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo(culture);
        }
        Console.WriteLine(string.Format("Culture: {0}", CultureInfo.CurrentUICulture.Name));

        // 產生ResourceManager實體
        var rm = new ResourceManager("TestSolution.CodeMsg", Assembly.GetExecutingAssembly());
        // 取得資源檔中的Name為REPLY_OK的字串
        var str = rm.GetString("REPLY_OK");

        Console.WriteLine(string.Format("REPLY_OK: {0}", str));
        Console.Read();
    }
}

執行結果:





留言