在之前幾講中,老白給大家介紹了C#中module和Assembly的生成和使用。在這一篇中,老白將更加深入的介紹下Assembly其中的一個知識點——本地化(Localization)。
什麼是本地化如何標識本地化Assembly中的本地化示例什麼是本地化在我們進入正題之前,我們需要先搞清楚什麼是本地化。
顧名思義,本地化就是將C#所使用的資源變成本地所特有的一些性質或形式或方式等。有了本地化我們可以很方便的為某一個專案或應用程式提供多語言的版本,比如XX中文版、XX繁體版和XX英文版等。
有了本地化的好處就是,我們可以使用同一個應用程式來適配各個不同國家地區的不同語言使用者的使用習慣。而不需要每種語言或者針對每個地區來開發不同的程式。這也進而方便維護以及管理程式。
如何標識本地化既然本地化能夠適配各個地區和不同語言的使用者,那要如何進行標識或者區分不同的地區和語言呢?
我相信很多同學都想到了,沒錯就是類似於cn這樣的標識,我們在上網的時候其實也會經常用到。比如蘋果中國的官網就是https://www.apple.com.cn/而如果是訪問的香港的頁面那就是https://www.apple.com/hk/(至於為什麼一個是/hk一個是.cn這個就不用太糾結了,多半是因為域名管理的問題)。但是即使是香港,有些人使用的是英語有些朋友使用的是中文,那要怎麼進行區分呢?預設的https://www.apple.com/hk/使用的是繁體中文,如果需要使用英文可以使用https://www.apple.com/hk/en/。也就是hk代表了地區是香港,en代表了是英語(英語和英語還是有些不同的,所以地區+語言的組合能夠更加準備的代表使用習慣)。
在上面的例子中我們看到了如何進行標識本地化。這部分的定義,感興趣的同學可以查閱RFC 4646。裡面為每一個區域定義了唯一名稱。其標準的格式是“小寫兩字母語言程式碼-大寫兩字母/三字母語言程式碼”。比如zh-CN中的zh代表了中文,CN代表了中國,這使用的都是兩字母程式碼。
預設情況下,Assembly中嵌入的是預設的資原始檔,而支援本地化的資原始檔應該是另外獨立的檔案。這樣做的能夠達到一種隔離效果:
本地化處理不會對主程式產生影響本地化的準備可以外包給第三方團隊因此,Assembly需要兩部分來支援本地化:
Assembly本身內嵌預設的資原始檔為每一個所需要支援的本地化標識建立一個資料夾,比如支援ja-JP,就需要建立一個資料夾是ja-JP。資料夾包含針對這個語言的資原始檔的Assembly其中的資原始檔又有如下要求:
資原始檔必須是副檔名為.resources的二進位制檔案預設資原始檔不需包含本地化標識,本地化資原始檔需要包含。比如預設資原始檔是./A.resources。那麼在ja-JP使用的資原始檔就應該是./ja-JP/A.ja-JP.resources資原始檔需要打包成Assembly,且Assembly名需包含resources以上的內容想必看起來晦澀難懂,讓我們一起看看示例。
示例準備資原始檔
首先,我們建立一個資料夾,en-US。在資料夾下建立資原始檔。
en-US/resource.en-US.txt內容如下:
note=(en-US)嵌入到Assembly檔案中的文字
建立預設資原始檔resource.txt內容如下:
note=(預設)嵌入到Assembly檔案中的文字
注意,這裡的資原始檔的內容都是鍵值對。這個例子中,鍵是note,一會我們需要使用這個鍵來訪問其對應的值。
準備原始碼
更改下我們之前使用到的Program.cs和Free.cs檔案,Free.cs檔案如下:
這裡我們使用的是ResourceManager(name, assembly)這個建構函式,name是完整的資源名。在我們這個例子中預設的資原始檔是resource.resources(一會會談到這個檔案如何生成),因此name就是resource。
剛剛提到,我們資原始檔儲存的是鍵值對,這裡透過GetString(key)來訪問note這個鍵。
再來看看更改後的Program.cs檔案:
public sealed class Program{ public static void Main() { System.Console.WriteLine("hello world"); System.Console.WriteLine("========Free Function========"); Free.Run(); }}
資料夾結構
專案目錄 |---Program.cs |---Free.cs |---resource.txt |---en-US |---resource.en-US.txt
轉換和新增資原始檔
在前面提到過,資原始檔必須是.resources二進位制檔案,之前準備的txt檔案並不能直接使用(在上一篇中我們直接使用了txt檔案,使用ResourceManager來進行管理我們就不能直接使用txt檔案了)。因此,我們需要將txt檔案轉換成resources檔案。然後再將resources檔案嵌入到Assembly中。
以en-US的為例,使用resgen將txt檔案轉換成.resources檔案:
resgen resource.en-US.txt
執行完上述命令,資料夾中將會多出一個resource.en-US.resources檔案。
然後執行下述命令來生成一個只包含resource的Assembly:
al /out:Free.resources.dll /c:en-US /embed:resource.en-US.resources
這裡由於只是生成包含資原始檔的Assembly而沒有涉及編譯原始碼,所以這裡我們只能使用al而不能使用csc。
完整的過程如下圖所示:
resource檔案生成以及新增到Assembly
編譯程式碼並新增預設資原始檔
跟en-US的一樣,先將resource.txt轉換成resource.resources。
然後,我們生成一個Free.dll的library檔案,這個Assembly包含了Free.cs的原始碼以及預設資原始檔,程式碼如下:
csc /out:Free.dll /t:library /resource:resource.resources Free.cs
最後生成Program.exe,由於Free.Run方法在Free.dll中,所以需要引用Free.dll:
csc /r:Free.dll Program.cs
測試
這個時候,如果我們執行Program.exe(如果使用的是中文系統的話),得到的應該是預設的輸出“(預設)嵌入到Assembly檔案中的文字”。
將系統文字轉換成英文,如下:
設定系統顯示語言為en-US
再次執行Program.exe,得到的輸出將是“(en-US)嵌入到Assembly檔案中的文字”。