準備一個示範的程式
Rails 如要中文化要在每個 Rails 程式裡單獨設定,所以我們來做一個 “花草記錄簿” 當示範程式。 首先,建一個叫 plants_development 的資料庫。 建好了之後到你習慣放程式的檔案夾裡建一個新的 rails 程式:
rails plants cd plants
把 Ruby 的編碼方式改成 UTF-8
Ruby 的編碼方式一開始只用英語。 我們要改用 UTF-8 才能使用中文。 打開檔案 plants/config/environment.rb, 在最後一行 “# Include your application configuration below” 後面加上這兩行:
$KCODE = 'u' require 'jcode'
儲存並關閉檔案。
設定跟資料庫溝通時用的編碼
每種不同的程式,不管是 PHP, Rails, 或 JSP 等等,要跟任何的資料庫溝通時都要先決定溝通時用的編碼。 在 Rails 跟 MySQL 裡頭,溝通的編碼是在 database.yml 裡面設的。 打開 config/database.yml,在每個設定區裡加一個 “encoding: utf8″。 像 development 應該看起來像這樣 (你的 username 跟 password 可能會不同):
development: adapter: mysql database: plants_development username: root password: host: localhost encoding: utf8
這個範例是 development 的設定,”test” 跟 “production” 也要加最後一行的 encoding: utf8。 你用的資料庫如果是 PostgreSQL 的話,把 “encoding: utf8″ 改成 “encoding: unicode”。 SQLite 資料庫不用設這個值,但是要安裝 SQLite 時要啟動 utf8。 例如,在 Linux 系統安裝前要給 ./configure 一個變數 “–enable-utf8″:
./configure --enable-utf8
建立 model
建立一個 model 才有可以修改資料的東西:
ruby script/generate model Plant
這時候 Migration 會建一個叫 db/migrate/001_create_plants.rb 的檔案。 把這個檔案打開,在 def self.up 裡放入:
create_table (:plants,
ptions => 'DEFAULT CHARSET=UTF8') do |t|
t.column "name", :string
t.column "planted_at", :datetime
t.column "flower", :boolean
end
“DEFAULT CHARSET=UTF8″ 是要讓資料庫儲存各國不同的語言。 存檔後回到 plants/ 的目錄裡下這個指令來產生新的 “plants” table:
rake migrate
有了這個 table 之後就可以自動產生 CRUD (Create, Read, Update, Delete) 的架構了:
ruby script/generate scaffold Plant Admin
設定 HTML 的 encoding
雖然我們設定了 Ruby 跟資料庫溝通時用的編碼 , 每一網頁的 <head> </head> 裡頭不要忘了加
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
真的要每頁每頁加嗎? 當然不用啦。直接放在 layout 裡頭就會在每頁上面顯示出來了。 打開 app/views/layouts/admin.rhtml 在這個檔案裡的東西會出現在所有 admin controller 管理的網頁上。 在 <head> 跟 </head> 中間貼上剛剛的那行字串:
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
測試中文讀寫
到現在設定的部份總算完成,但要測試真的會不會跑。
啟動伺服器:
ruby script/server
到 http://localhost:3000/admin/ 增加一些中文名字的植物吧!

到這個步驟你如果還是看到亂碼的話就要看看瀏覽器上設的 encoding 是否為 utf-8。 現在程式已經可以讀/寫中文了。 如果要的功能只有這樣,就不用繼續讀下去。 可是如果想要按一個連結就把整個網頁切換成中/英文的話,就繼續讀吧。
國際化
Rails 有很多別人已寫好的軟體。 我們要用的工具是寫的比較完整的 plugin 叫 Globalize (www.globalize-rails.org)。 這一套軟體把你翻譯過的字串存在資料庫裡。 如果改變語言時,它會把翻譯過的字串叫出來。 除此之外,各國不同的數字,金錢顯示方法也可以存在資料庫裡。 我們邊做邊解釋吧。
安裝 Globalize Plugin
到程式的資料夾裡 (plants/) 下此指令:
ruby script/plugin install svn://svn.globalize-rails.org/globalize/branches/for-1.1
整個指令不要分兩行打入喔。 這會安裝 Globalize 在程式裡。 打開 /vendor/plugins 檔案夾,裡面會看到一個 trunk 的檔案夾。 這裡面放的就是 Globalize 的軟體了。 在 plants/ 的目錄裡再下此指令來準備 Globalize:
ruby script/generate globalize
這個指令會透過 Migration 產生一個檔,叫 db/migrate/002_globalize_migration.rb。 打開來看它是在做啥麼的吧! 裡面喵了一下,它會產生 3 個 table (globalize_countries
globalize_translations, 和 globalize_languages),然後它會做一些看不太懂的東西,然後加了一大堆有關世界各國的資料。 仔細的看看,它有加一些 index,原來加 index 的語法是這樣寫的。 以後自己寫 Migration 檔案時可以拿這個來做參考。 不知道為什麼,這個檔案在新增 table 的時候,並不會自己把 table 的編碼用成 UTF-8。 我們只好自己去修改。 在每一個 create_table 的指令裡多放
ptions => ‘DEFAULT CHARSET=UTF8′ 如下:
create_table (:globalize_countries, :force => true,ptions => 'DEFAULT CHARSET=UTF8') do |t|
檔案裡有三個 create_table, 所以要改三個地方。 改好後就可以執行這個檔案了:
rake migrate
跑了 35.2505 秒之後,去看資料庫,果真多了三個 table.
設定基本語言
在運用這些 table 之前,我們還得設定基本語言。 打開 config/environment.rb,在最後面加這幾行:
include Globalize Locale.set_base_language 'zh-TW' Locale.set 'zh-TW'
第一行就是說此程式需要包含 Globalize plugin 的程式碼。 第二行把基本語言設成 zh-TW, zh-TW 就是中文-台灣。 你的基本語言如要是英語的話,把 zh-TW 改成 en-US (英文-美國)。 第三行把地點設成台灣。
加入翻譯字串
回到 http://localhost:3000/admin/ 的網頁上,你應該看到以前加入的花名。 在每個花名後有三個連結: ‘Show’ ‘Edit’ 跟 ‘Destroy’。 現在的目的就是把這三個連結翻譯成中文。 翻譯的第一步驟是輸入翻譯字串。 要加入翻譯字串最快的方法就是用 script/console 。 在 plants/ 目錄裡下此指令:
ruby script/console
這會把程式裡有用到的 class 載入記憶體裡,讓你方便測試。打一個指令:
Locale.language
它應該會跟你說 “Chinese”。 這是因為我們剛剛把基本語言設成 zh-TW。如果你的不是 Chinese 的話,用此指令讓它變成 Chinese:
Locale.set 'zh-TW'
加入下面幾個翻譯字串。 加的時候你的中文碼在螢幕上可能會變成數字字串: \207\346\226\231 這不用擔心,存入資料庫時它會轉成 UTF-8 碼。 下這些指令來輸入翻譯字串:
Locale.set_translation('Show', '詳細資料')
Locale.set_translation('Edit', '修改')
Locale.set_translation('Destroy', '刪除')
每輸入一行它會回覆類似: [nil, "詳細資料"] 注意大小寫是有差的喔。 Show 跟 show 是兩個不一樣的字串。

設定那些字串可被翻譯
翻譯字串輸入了,可是這並不代表每次程式遇到 “Show” 時會自動換入 “詳細資料”。 必須要在想翻譯的那串字後加一個 .t 才可以。 打開 app/views/admin/list.rhtml 。 這個檔案是 scaffold 自動產生的。 使用者到 http://localhost:3000/admin/ 時其實叫出來的就是 list.rhtml。 檔案裡面,在 ‘Show’ 的後面加個 .t,如下:
<td><%= link_to 'Show'.t, :action => 'show', :id => plant %></td>
‘Edit’ 跟 ‘Destroy’ 後面也要加。 現在瀏覽 http://localhost:3000/admin/ 的話, Show, Edit, 跟 Destroy 應該就是用中文顯示了。

切換中英文
那要怎麼切換中英文呢? 以下三個步驟大致說明一下,再來仔細看看:
1) 在我們的網頁上,我們要放兩個連結。 一個可以把英文改成中文,另一個可以把中文改成英文。 中文的連結裡有個叫 locale 的變數,變數的值是 ‘zh-TW’。 使用者按了連結後,這個變數會透過 params 傳到下一頁去。 2) 在下一頁還沒出現時,把變數裡的值複製到 session 裡一個也是叫做 locale 的變數。 3) 下一頁要出現時,先去檢查 session 裡頭的 locale 變數。 查到了 ‘zh-TW’ 就知道要用中文了。
英文要換成中文也是一樣的原理。 現在一步一步來看:
步驟一: View 裡的連結
我們的連結可以放在 app/views/layouts/admin.rhtml 裡,因為放這裡面的東西會顯示在所有網頁上。
<%= link_to "中文", :action => "change_locale", :locale => "zh-TW"%>
這一段碼會產生一個連結。 連結上會寫 “中文”,按了之後 controller 會把控制權轉給一個叫 “change_locale” 的 method。 同時,’zh-TW’ 也放入了 :locale 的變數裡。 :locale 這個名字是我們自己取的,我們也可以隨便放個名字,像 :booboo => “zh-TW” 也可以。 不管是什麼名字,我們不用事先宣告,直接把值給任何的名字,然後用同樣的名字去 params 裡面找,就能把裡面的值叫出來了。 我們多加一點功能吧。 如果 session[:locale] 裡面已經有了 ‘zh-TW’,就表示我們現在已經在顯示中文了,所以 “中文” 這個連結就不用顯示。 把第一行跟第三行加入:
<% unless session[:locale] == 'zh-TW' %> <%= link_to "中文", :action => "change_locale", :locale => "zh-TW"%> <% end %>
這段讀起來就是: 顯示 “中文” 這連結,除非 session[:locale] 裡已有 ‘zh-TW’。 英文的程式碼也要:
<% unless session[:locale] == 'en-US' %> <%= link_to "English", :action => "change_locale", :locale => "en-US"%> <% end %>
步驟二: 傳 param 的值進去 session 裡
“中文” 跟 “English” 這兩個連結按了之後的 action 是 change_locale。 現在就來寫 change_locale 的內容吧。 這個 method 應放在 app/controllers/application.rb 裡頭:
def change_locale
session[:locale] = params[:locale] unless params[:locale].blank?
redirect_to :back
end
這個 method 的作法就是 “除非 params[:locale] 是空白,把 params[:locale] 裡的變數放入 session[:locale] 裡”。 以我們這個程式來說,裡面放的值不是 ‘zh-TW’ 就是 ‘en-US’。
步驟三: 設定 Locale
每次一有人要瀏覽網頁時,我們就要設 locale。 因為設 locale 的 method 是整個程式都可用到的,所以最適當的地方是放在 app/controllers/application.rb 裡。 我們把這個 method 叫 set_locale。
剛剛看過改 Locale 的方法是用 Locale.set。 要 set 成什麼呢?就是 set 成我們存在 session[:locale] 的變數了。 所以我們改變 locale 的方法如下:
<br />
def set_locale
Locale.set session[:locale] unless session[:locale].blank?
true
end
這個 method 的作法就是 “除非 session[:locale] 是空白,把 Locale 設為 session[:locale]“。 這個 method 要在每次程式要跑之前就要叫,所以要放在 before_filter:
class ApplicationController < ActionController::Base before_filter :set_locale ...
在 set_locale 方法的第二行有一個 “true”,這是為什麼呢? 因為 before_filter 所叫的方法一定要回傳 true, 整個程式才會繼續執行,所以我們就回傳一個 true。
現在來瀏覽 http://localhost:3000/admin/ 吧。 一開始 “中文” 跟 “English” 兩個都會顯現,因為 session 裡面沒有 zh-TW 或 en-US 的參數。 “詳細資料”, “修改”, 跟 “刪除” 也會顯示,因為我們在 “設定基本語言” 裡有把預設值設為 ‘zh-TW’。 按一下 “English” 的連結吧。 “Show”, “Edit”, 跟 “Destroy” 果真出現了! 其他的如果要翻譯的話就照這些方法去翻譯。
中文版

英文版

如果你的程式支持個人客製化(使用者可以 login),你可以在使用者的 table 裡加一個 “locale” 的欄位。 在使用者登入時,把那欄位裡的值叫出來,放入 session[:locale] 裡頭。 使用者在改變語言時要把新的 locale 值寫回資料庫裡,這樣你的程式就會記住每個使用者的愛好了。
May 31st, 2007 at 2:42 am
你好,我來至祖國大陸。非常高興看到有臺灣同胞也在使用ruby on rails。我和你一樣使用ruby on rails做網站,一樣使用Globalize plugin。目前我遇到一個問題,Globalize把zh-cn zh-tw當成一個語言對待,模板文件都是*.rhtml.zh,我再尋找個這個問題的解決方案時路過你的網站。如果你知道解決辦法,請你告訴我。ccwebkey@ccwebkey.com<br/><br/>ps:gblog在中國大陸范圍內不能直接訪問
March 2nd, 2010 at 11:22 am
[...] 國際化使用最新的i18n gem,詳細的變動可以參考 Rails 3 I18n changes。多國語言在ruby 1.8 做得不是很好,而Rails國際化常用的第三方解決方案有Gettext或是Globalize。內建的I18n使用可參考ihower這篇,Globalize可參考國網中心這篇或是英文這篇。Globalize採用資料庫系統儲存翻譯字串,與目前OBW作法一樣,好處就是方便撰寫前端維護介面。國際化與地區化議題很龐大,一般小型應用程式要做到這塊並不容易,就以前開發軟體經驗,為了支援英日語系介面,只好請外面的翻譯公司協助,拿到翻譯搞後仍需反覆校對,若是允許客製修改的系統,客戶可能會挑你翻譯毛病,你還得教他怎麼改(凸顯彈性介面語系字串維護介面的必要性),或是幫他修改。更可怕的還有內容(資料面)的地區化呢! [...]