1. 程式人生 > >【C#】winform多語言方案

【C#】winform多語言方案

1.CultureInfo的獲取和設定

CultureInfo通常由兩位小寫的LanguageCode+兩位大寫的Country/RegionCode組成,如:zh-CN,zh-TW,jr-JP,en-US,zh-HK。部分地區由languageCode+sripttag+country/regioncode,如zh-Hans-HK(香港簡體中文)。
幾個有用的屬性:

  1. CultureInfo.CurrentUICulture: 只讀屬性,不可更改。獲取當前系統的顯示語言(Display Language),系統顯示為英文就是英文語言,顯示中文就是中文語言。
  2. CultureInfo.CurrentCulture: 只讀屬性。獲取當前系統設定的區域性資訊。
    可通過以下路徑“控制面板->時鐘、語言和區域→格式→格式”進行修改,預設值是“與Windows顯示語言匹配”。即通常來說CurrentCulture=CurrentUICulture。你可以進行更改,使二者不同。
    這裡寫圖片描述
  3. Thread.CurrentThread.CurrentUICulture:讀取或設定當前執行緒的區域資訊,只對當前執行緒有效。預設情況下此Culture等於CultureInfo.CurrentUICulture。
  4. CultureInfo.DefaultThreadCurrentUICulture:同上,唯一不同的是對所有執行緒都有效。

2.兩種常見的多語言方式

(1). 使用Visual Studio自動生成對應的語言的resource檔案。參考演練:本地化 Windows 窗體
這裡寫圖片描述
這裡寫圖片描述
這裡寫圖片描述
如上圖所示,一個窗體對應若干個多語言檔案。多語言檔案使用了同一個Name,但是Value是翻譯過的。啟動時系統自動將根據不同的使用者設定顯示對應的語言,如果沒有對應語言的字串則使用預設的字串。

(2). 手動向專案中新增resource檔案。
這裡寫圖片描述
如圖:首先新增預設語言檔案lang.resx,然後再新增不同的語言版本的resx。
使用時,通過ResourceManager來讀取資原始檔:

ResourceManager LocRM = new ResourceManager("Namespace.lang",typeof(Form1).Assembly);
MessageBox.Show(LocRM.GetString("STR_KEY"));

雖然構造LocRM時傳入的是lang.resx,但系統會根據不同的語言讀取不同的resx。
(3). 兩種方式的比較

  • VS自動生成:
    不用寫程式碼,省力; 熱切換方便。
    自由度不高; 操作複雜與設計器結合太緊 ;不容易分離和重用 ;擴充套件不方便。
  • 手動新增:
    能夠靈活控制 ;方便分離和重用 ;後期編輯修改方便。
    要寫程式碼將翻譯好的字串繫結到UI上; 熱切換要麻煩一點。

3.應用到winform客戶端中

考慮到以後的擴充套件和開發時的效率,我認為選擇“手動新增”的這種方式比較好。
(1).對於程式部署到不同國家和地區中所共有的部分,如前端UI部分,前端HardCode部分,部分服務端資料返回。
前端UI:將對應的str_key繫結到control上。
前端HardCode:統一讀取str_key對應的value。
部分服務端返回資料:如果屬於文字型別,根據傳入的language_id返回對應語言的版本;如果是dll外掛型別,編碼時應與UI編碼方式一致,直接把dll載入到主程式時會自動本地化。
(2).差異部分,如在使用過程中逐漸累積的資料。
這部分資料因為大部分都存在資料庫中,且與多語言無關。

4.實現

(1).新增多語言類庫Globalization
這裡存放所有翻譯好的多語言檔案。
(2).對於需要本地化的專案引用Globalization即可。
在系統啟動時載入多語言資原始檔:
LocRM = new ResourceManager(“Globalization.lang”, typeof(Class1).Assembly);
(3).構建多語言的Model並繫結到Controle

public class LangModel:INotifyPropertyChanged
    {
        public static LangModel Instance { get; } = new LangModel();
        public string IDS_CANCEL
        {
            get
            {
                return Program.LocRM.GetString("IDS_CANCEL");
            }
        }
        public string IDS_HELLO
        {
            get
            {
                return Program.LocRM.GetString("IDS_HELLO");
            }
        }
        public string IDS_OK
        {
            get
            {
                return Program.LocRM.GetString("IDS_OK");
            }
        }
        public string IDS_REPORT
        {
            get
            {
                return Program.LocRM.GetString("IDS_REPORT");
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;
        void OnPropertyChanged(string propertyName)
        {
            if(PropertyChanged!=null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }
        public void NotifyTarget()
        {
            //OnPropertyChanged("xxx");
            //OnPropertyChanged("xxx");
            //....
        }
    }

(4).多語言熱切換。
設定CultureInfo.DefaultThreadCurrentUICulture = new CultureInfo(“xx-XX”),然後NotifyTarget。
可能存在的問題:如果多語言字串非常多,NotifyTarget方法會通知所有的繫結,可能會有效能問題。需要和“只通知當前顯示的UI上繫結的屬性”這種方法進行比較。