多國語系及時區

最后更新于:2022-04-01 02:31:27

> It Works on My Machine! - 數以萬計的程式設計師 ## 安裝Rails中文翻譯詞彙檔 Rails預設的語系是英文。要換成繁體中文,可以安裝rails-i18n這個gem有社群幫忙翻譯的繁體中文: * 在`Gemfile`加上`gem "rails-i18n"`,然後執行bundle * 修改 config/application.rb 的預設語系 ~~~ config.i18n.default_locale = "zh-TW" ~~~ 這樣就會使用[http://github.com/svenfuchs/rails-i18n](https://github.com/svenfuchs/rails-i18n/blob/master/rails/locale/zh-TW.yml)的繁體中文翻譯。 ## 自訂翻譯檔案 要讓你的網站可以支援多國語系,必須定義出翻譯的詞彙對應檔案。這些詞彙檔放在config/locales下,使用YAML格式,例如新增一個config/locales/zh-TW.yml的檔案,內容如下: ~~~ "zh-TW": hello_world: 哈囉 admin: event: 活動管理 ~~~ > 注意 YAML 格式的縮排必須使用兩個空隔,Tab是不允許的。直接複製貼上可能會有問題,請小心檢查縮排。 這樣就可以用`I18n.t`這個方法來做翻譯詞彙的替換。如果在View中可以直接使用`t`這個Helper方法。翻譯關鍵字可以用字串或 Symbol,也可以加上 Scope,例如: ~~~ t("admin.event") t(:event, :scope => :admin ) I18n.t(:hello_world) # 如果不在View中,則需要加上 I18n 類別 ~~~ 如果要在詞彙內嵌變數的話,可以使用`%{variable_name}`的語法,修改config/locales/zh-TW.yml: ~~~ "zh-TW" hello: "親愛的%{name}你好!" ~~~ 這樣在template中改成傳入參數即可: ~~~ t(:hello, :name => @user.name) # 親愛的XXX你好 ~~~ > 就算你的網站不需要支援多國語系,這個功能對於團隊協作開發網站仍然非常有幫助,因為寫程式的時候不一定會先確定文案規格,用i18n來處理的話,最後只需要讓PM統一修改翻譯詞彙檔即可。 ## 搭配Model使用 在套用上述的翻譯詞彙檔之後,你可能會注意到Model驗證錯誤訊息會變成如Name 不能是空白字元,如果需要近一步中文化欄位名稱,你可以新增config/locales/events.yml內容如下: ~~~ zh-TW: activerecord: attributes: event: name: "活動名稱" description: "描述" ~~~ 其實,翻譯檔檔名叫events.yml、zh-TW.yml、en.yml什麼都無所謂,重要的是YAML結構中第一層要對應locale的名稱,也就是`zh-TW`,Rails會載入config/locales下所有的YAML詞彙檔案。 ## 如何讓使用者可以切換多語系 在 application_controller.rb 中加入: ~~~ before_action :set_locale def set_locale # 可以將 ["en", "zh-TW"] 設定為 VALID_LANG 放到 config/environment.rb 中 if params[:locale] && I18n.available_locales.include?( params[:locale].to_sym ) session[:locale] = params[:locale] end I18n.locale = session[:locale] || I18n.default_locale end ~~~ 在 View 中可以這樣做: ~~~ <%= link_to "中文版", :controller => controller_name, :action => action_name, :locale => "zh-TW" %> <%= link_to "English", :controller => controller_name, :action => action_name, :locale => "en" %> ~~~ ## 語系樣板 除了上述一個單字一個單字的翻譯詞彙替換之外,如果樣板內大多是屬於較為靜態的內容,Rails也提供了不同語系可以有不同樣板,你只要將樣板命名加上語系附檔名即可,例如: ~~~ app/views/pages/faq.zh-TW.html.erb app/views/pages/faq.en.html.erb ~~~ 如此在英文版的時候就會使用faq.en.html.erb這個樣板,中文版時使用faq.zh-TW.html.erb這個樣板。 ## 時區 TimeZone 首先,資料庫裡面的時間一定都是儲存 UTC 時間。而 Rails 提供的機制是讓你從資料庫拿資料時,自動幫你轉換時區。例如,要設定台北 +8 時區: 首先設定 config/application.rb 中預設時區為 config.time_zone = “Taipei”,如此 ActiveRecord 便會幫你自動轉換時區,也就是拿出來時 +8,存回去時 -8 ### 如何根據使用者切換時區? 首先,你必須找個地方儲存不同使用者的時區,例如 User model 有一個欄位叫做 time_zone:string。然後在編輯設定的地方,可以讓使用者自己選擇時區: ~~~ <%= time_zone_select :user, :time_zone %> ~~~ 接著在 application_controller.rb 中加入: ~~~ before_action :set_timezone def set_timezone if logged_in? && current_user.time_zone Time.zone = current_user.time_zone end end ~~~ ### 時區處理方法 Ruby原生的Time類別對於時區的處理一律是參考唯一的系統環境變數`ENV['TZ']`,這在使用者多時區的應用程式中就顯的見拙。因此在Rails中的時間類別使用的是ActiveSupport::TimeWithZone,我們已經知道可以使用`Time.zone`可以改變時區,其他的用法例如: ~~~ Time.zone = "Taipei" Time.zone.local(2011, 8, 3, 9, 0) # 建立一個Taipei當地時間 => Wed, 03 Aug 2011 09:00:00 CST +08:00 t = Time.zone.now # 目前時間 => Wed, 03 Aug 2011 22:17:54 CST +08:00 t.in_time_zone("Tokyo") # 將這個時間換時區 => Wed, 03 Aug 2011 23:18:34 JST +09:00 Time.utc(2005,2,1,15,15,10).in_time_zone # 將UTC時間換Taipei當地時間 => Tue, 01 Feb 2005 23:15:10 CST +08:00 ~~~ ### 時間的顯示 除了使用Ruby內建的[`Datetime#strftime`](http://www.ruby-doc.org/core-2.1.5/Time.html#method-i-strftime)格式化時間之外,Rails也可以直接呼叫`to_s`轉換輸出格式: ~~~ datetime.to_s(:db) # => "2007-12-04 00:00:00" datetime.to_s(:number) # => "20071204000000" datetime.to_s(:short) # => "04 Dec 00:00" datetime.to_s(:long) # => "December 04, 2007 00:00" datetime.to_s(:long_ordinal) # => "December 4th, 2007 00:00" datetime.to_s(:rfc822) # => "Tue, 04 Dec 2007 00:00:00 +0000" datetime.to_s(:iso8601) # => "2007-12-04T00:00:00+00:00" ~~~ 也可以自行註冊專案常用的格式在config/initializers/time_formats.rb裡: ~~~ Time::DATE_FORMATS[:month_and_year] = '%B %Y' Time::DATE_FORMATS[:short_ordinal] = lambda { |time| time.strftime("%B #{time.day.ordinalize}") } ~~~ 或是透過I18n的機制,在翻譯詞彙檔中編輯格式,然後使用: ~~~ I18n.l( Time.now ) I18n.l( Time.now, :format => :short ) ~~~ ## 更多線上資源 * [Rails Internationalization (I18n) API](http://guides.rubyonrails.org/i18n.html)
';