【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(香港簡體中文)。
幾個有用的屬性:
- CultureInfo.CurrentUICulture: 只讀屬性,不可更改。獲取當前系統的顯示語言(Display Language),系統顯示為英文就是英文語言,顯示中文就是中文語言。
- CultureInfo.CurrentCulture: 只讀屬性。獲取當前系統設定的區域性資訊。
可通過以下路徑“控制面板->時鐘、語言和區域→格式→格式”進行修改,預設值是“與Windows顯示語言匹配”。即通常來說CurrentCulture=CurrentUICulture。你可以進行更改,使二者不同。
- Thread.CurrentThread.CurrentUICulture:讀取或設定當前執行緒的區域資訊,只對當前執行緒有效。預設情況下此Culture等於CultureInfo.CurrentUICulture。
- 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上繫結的屬性”這種方法進行比較。