初探 ASP.NET MVC 多國語系(i18n)|#1: 觀念與基本做法

前言

猶記得第一次聽到 i18n 這個詞是在公司新人訓練 Java 課程的部分,當時聽著影片中講師不時提到的 i18n,我就一直在想這個「艾斯‧巴恩」到底是什麼東西,是一個機制?還是一個第三方套件?或是一個功能?一直到課程結束我也只模模糊糊地知道艾斯巴恩原來是 i18n,而這是個跟網站多國語系化有關的東西。

在新人訓練結束後下到專案將滿一年之際,專案出現了多國語系(嚴格來說是兩國語系:繁體中文跟英文)的需求,而我則被派任處理這個部分,也因此累積了一點心得,就在此與大家分享一番,話不多說了,咱們進入正文吧!

i18n 到底是什麼?

i18n 其實就是 internationalization 的縮寫,也就是國際化/多國語系化,之所以這麼稱呼是因為這個英文單字很長,然後從第一個字母 i 到最後一個字母 n 之間有 18 個字母,故得此名。它是個通用的概念,不僅限於 Java (只是不巧當初的訓練課程只有在 Java 部分提到此詞彙讓早期的我誤會了),因此不論是用任何語言來實作的網站系統都可以進行所謂的 i18n。

要做多國語系化的原因我相信是非常好理解的,就是因為網站的使用情境中,使用者群包含了以網站開發方原生語言以外的外語為母語的族群,為了讓網站更友善一點,才需要進行此工程;換言之,如果網站一開始就確定不會有使用原生語言以外的使用者,那也不用做這件事了,畢竟要做 i18n 還是需要付出一定的額外成本。

i18n 的成本?

在為專案進行 i18n 時,我注意到了比起單一語言網站,多國語系的網站有一些需要額外付出的工作成本,其中至少包含以下三點:

  1. 準備原生語言與外語的詞彙/文句對照表
    會額外對網站進行 i18n 無非是希望網站上各單字、段落短文等文字,能比起在頁面上點右鍵使用 Google 的翻譯功能來得更為精準、到位,因此,一份自備的精確對照表便是最基本不可或缺的資源了。對於使用 Visual Studio (VS) 的開發者來說,這份表格如果剛好是 Excel 檔並且剛好以特定的格式紀錄內容,除了能讓協作的管理人員/翻譯人員一目瞭然,也能大大減少表格轉換為程式資源的成本,這個部分往後會再提。
  1. 設計簡潔有力的取得資源機制
    單一語言的網站,往往會直接把想要呈現的文字 Hard Code (寫死)在程式碼中的不論是 Model, View 或是 Controller 甚至 Dao 的某一處,這是很直覺的作法,維護的人也能一眼就看懂程式碼中那一段寫死的文字想表達的是什麼。但今日如果要讓這些文字隨著網站使用者切換語系而呈現不同的內容,那很顯然地寫死不會是個好選擇(當然,熱愛寫條件判斷者不在此限)。也就是說,一個能夠相對維持住原始寫死作法所提供的「可讀性」但又能兼顧自動抽換文字的「便利性」這樣的方法是必須的,我們要能夠很輕便地就把原本寫死的文字轉變成具備動態的性質。
  1. 與系統設計者(System Analyst, SA/System Designer, SD)協調資源取用方式
    以我們專案來說,某個詞彙或是某段文字對應的外語用字遣詞並不是咱們 Programmer (PG) 可以自行決定的,一般是由上一層的 SA 或是客戶端承辦人來定義。這衍伸出來的問題是:這個翻譯後的資源打算要放在哪裡?是統一放在如 1. 所說的文檔中,還是維護在 Database (DB) 裡的某個欄位(站在 SA 的立場,管理在 DB 對他們來說是較輕便的方案)?光是這兩者的差別就可以造就不同的實作方法,也可能會影響到 SA 們設計 Stored Procedure (SP)、Function 的邏輯,當然也就間接影響到 PG 開發程式的方向,所以這是一開始就必須先決定好的,否則後續會多很多麻煩,也容易造成程式碼風格不一致。
如何開始?

在 ASP.NET MVC 的網站上進行 i18n 的機制其實一點都不難,說穿了就是資源的取得,一張圖就可以說明個大概:
把所有資源想像成一張二維表格,Y 軸為資源的 Key 值,X 軸為資源語系,假設當前語系為英語(en-US),則當我們的程式碼給定一 Key 值向表格取值,就可以得到英文版的內容。

在開始建構語系資源前,強烈建議先安裝一款 VS 的擴充工具:ResX Manager,這比起 VS 本身的資源管理功能使用起來更直覺也更方便,用過的都說讚。要安裝這個擴充也十分簡單,從 VS 功能列的 Tools > Extensions and Updates 功能就可以直接在 VS 內部搜尋並進行安裝了,完全不需要再自行手動下載安裝。Extensions and Updates 搜尋結果如下圖:(選擇有國旗飄揚的那個)
此擴充工具的用法非常單純,其功用簡單來說就是幫助開發者整合方案內的資源檔,羅列在同一個介面並提供新增/刪除/修改資源的功能,從此之後就不用再到個別的資源檔去進行維護。

接著就可以開始新增需要的資源檔了。在此先建立一個極簡專案作為說明之用,直接在目前專案(Project)底下新增一個資料夾統一管理資源,並對該資料夾點右鍵進行 Add > New item 動作(中文版應該類似:新增 > 新項目),在新增項目類型列表中選擇 Resources File 即可得到一個副檔名為 .resx 的全新資源檔。

第一時間找不到 Resources File 項目的話,在左邊的類別選擇 Visual C# items > General 應該就可以找到。

註:資源檔其實並不一定要放在同一專案中,在相同方案(Solution)下另開一個類別庫專案(Class Library)專司資源檔的存放也不失為一個好選擇,這可以讓日後網站已進入上線階段時抽換資源內容更為輕便。但此處為了減少說明範例的複雜度,還是將資源先存放在相同專案之中。

在這裡我們先產生一個 Resource1.resx 來做說明,產生的資源檔如果依 VS 原生的操作介面來看應該會是類似這樣的畫面:

Name 欄位就是前面提到的所謂 Key 值,Value 自然就是對應的文字內容,Comment 是可選填的,不填也沒差,每一個這樣的畫面都對應到一份語系檔。值得一提的是,Name (Key) 欄位有點挑食,有些特殊符號是不能包含在 Key 值裡面的否則會出現紅色驚嘆號圖示,以我的觀察它可接受中文字、英文字母、底線,最簡單的想法就是以一般變數命名的邏輯加上需要的中文字去設定 Key 值。
檢查一下,資源檔的 Build Action 和 Custom Tool 屬性是不是設為如圖片中的值,如果不是的話,可能會在編譯時發生錯誤,或是存取不到資源內容。
此處的差異可參閱 Will 保哥《如何讓 App_GlobalResources 裡的全域資源檔變成公開類別》一文

像是 Resource1.resx 這種格式的檔名,代表的就是原生語言的資源檔,如果我們的系統需要在某些情況下呈現另一種語言,以英語為例,那還必須再重複一次上述動作新增一個名為 Resource1.en-US.resx 的資源檔。en-US 是正規的語系代碼,如果不知道目標語言的代碼,也可以點開剛才安裝的 ResX Manager 介面中位於左下的第四頁籤,即可一覽所有語系應使用的代碼。

註 1:ResX 預設會成為一個檔案頁籤自動出現在已開啟的檔案列表中,如果沒看到,可以手動從功能列的 Tools 裡面點開它。
註 2:在 ResX Manager
介面中的第三頁籤,可以更改要使用的原生語系,預設是英文。
  如果使用傳統的 VS 資源管理介面,當多了一個語系之後,進行維護時就會變成要在兩個語系檔之間不停切換,十分不方便,但使用了 ResX Manager 這項工具以後,管理介面就變得人性化多了。
在使用三種以上的語系情境,更能感受到整合列舉編輯的便利性。

正式應用

既然材料都準備好了,那也是時候來出菜了。在這裡準備了一個下拉選單,扣除掉預設選項,內含三個有值項目對應了三種提供的語言,每個項目的值對應的則是語系代碼,每當選項變更時,就重載此頁面並以語系代碼為 Action 的傳入參數,在呈現 View 前依據傳入的語系代碼取得對應的文字內容顯示到前端畫面。

首先第 13, 14 行對當前語系進行設定的動作是必須的,而眼尖的人可能會注意到,Action 中第 24 行準備預設選項文字的結尾竟然是「.選擇語言」,這樣不合我們一般習慣的寫法可以嗎?事實證明是可以的,而且這就是取得資源最基本的做法。這可能跟 ASP.NET MVC 的資源存取機制有關,每當我們新增了一筆資源在某個資源檔,該資源檔對應的 .Designer.cs 檔中就會出現以該資源 Key 值為名的屬性,如下圖:
所以上述那種怪異的寫法,本質上就是在使用這個以中文字為名的屬性。此外,在前端也可以透過 Razor 寫法以同樣做法取得資源哦。
註:.Designer.cs 檔案是自動產生的,無須做任何動作去維護它,事實上修改了也沒用,因為會在下次程式碼重新產生時就被蓋掉。

也許還是會有人(例如:我)對於非參數又非註解的功能型程式碼中直接竄出中文字感到心裡有疙瘩,好消息是對於這個狀況當然是有解決方案的,壞消息是這部分就先不在這一篇提了,留點東西到下一篇寫吧!迫不及待想知道如何解決這個疙瘩的話,那先給關鍵字就是 C# 的「擴充方法」,網路上不少大神應該都有介紹過了。

結語

此篇文章大致介紹了 i18n 所需的前置作業以及基礎做法,所謂基礎做法,就像免費的手機 App 一樣,可以滿足需求,但總覺得不夠令人滿意。下一篇會說明更優雅地把文字 i18n 化的方法以及搭配 ResX Manager 的 Excel 匯入功能來實現更令人舒心的多國語系工法。

最後附上範例專案的執行結果供參:

參考引用

筆者也是近期才開始探索 i18n 的機制,若此文章有觀念不正確/待加強的地方,或者您有不一樣的看法與建議,都歡迎在留言處留言討論喔!

作者: Leon T.

南部人,水瓶座 AB 型,喜歡旅行攝影,討厭米老鼠還有芹菜跟香菜。 現職於叡揚資訊技術開發中心擔任程式設計師, 但比起寫程式,其實更享受在解決問題與創造的過程。 想要優雅生活,也想要寫出優雅的程式碼, 泅於瞬息萬變的技術海洋,以此為目標,一點一點努力前進。

發表迴響

你的電子郵件位址並不會被公開。 必要欄位標記為 *