Rails 的 i18n
紀錄一下自己處理 i18n 的思考過程,以免我哪天失智又双叒叕忘了。
i18n 是轉換語系用的,全名為「Internationalization」,因為 I 到 n 之間有 18 個英文字母,所以被簡稱為 i18n。
預設值
在 config/application.rb 中加入:
config.i18n.default_locale = "en"
使用者自行切換
在 application_controller.rb 加入:
before_action :set_locale
def set_locale
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" %>
根據 Accept-Language 判斷 1
Accept-Language 是什麼呢?
打開 F12,我們可以看到這個東西:
紅框處就是 Accept-Language
在 rails 中,我們可以使用 request.accept_language,在 application_controller.rb 中加入:
before_action :set_locale def set_locale I18n.locale = request.accept_language.scan(/^[a-zA-Z-]{5}/).first || I18n.default_locale end
這樣取得的就會是「zh-TW」。
如果要配合前面加入使用者自選功能的話,則可以寫成下面這樣:
before_action :set_locale
def set_locale
if params[:locale] && I18n.available_locales.include?( params[:locale].to_sym )
session[:locale] = params[:locale]
end
I18n.locale = session[:locale] || request.accept_language.scan(/^[a-zA-Z-]{5}/).first || I18n.default_locale
end
request.accept_language 也可用 request.env['HTTP_ACCEPT_LANGUAGE'] 代替。
根據 Accept-Language 判斷 2
當然,我們也可以使用 gem(iain/HttpAcceptLanguage)。
為什麼不自己寫而要使用 gem 呢?
這是因為 request.accept_language 的實際內容並不一定可以如上面一樣,能夠透過正規表示法找到,而 iain/HttpAcceptLanguage 便是專門偵測使用者語系的。具體使用方法可以直接看 readme,但下面還是紀錄一下我實作的情形。
一樣是修改 application_controller.rb:
before_action :set_locale
def set_locale
I18n.locale = http_accept_language.compatible_language_from(I18n.available_locales) || I18n.default_locale
end
然後,我們可能會發現這個訊息:
看看 devise 的登入頁面吧:
……(倒吸一口氣)
這跟我要的不太一樣。
排查原因後發現,「http_accept_language.compatible_language_from(I18n.available_locales)」的回傳值是「zh-CN」……嗯,會不會是「zh-TW」不在 18n.available_locales 的範圍裡面?這篇網誌曾提及 rails 在 4.1.0 中「zh-TW」不在 18n.available_locales 裡。
但實際把「I18n.available_locales」的內容印出來:
[:en, :af, :ar, :az, :be, :bg, :bn, :bs, :ca, :cs, :da, :"de-CH", :de, :el, :"en-GB", :"es-CO", :"es-MX", :es, :et, :fa, :fi, :"fr-CA", :fr, :ha, :he, :hi, :hr, :hu, :id, :ig, :is, :it, :ja, :ka, :km, :ko, :"lo-LA", :lt, :lv, :mk, :ms, :nb, :nl, :"nn-NO", :no, :"pap-AW", :"pap-CW", :pl, :"pt-BR", :pt, :ro, :ru, :si, :sk, :sl, :sq, :"sr-RS", :sr, :sv, :th, :tl, :tr, :uk, :ur, :vi, :yo, :"zh-CN", :"zh-HK", :"zh-TW", :"zh-YUE", :cy, :"de-AT", :"de-DE", :"el-CY", :"en-AU", :"en-CA", :"en-CY", :"en-IE", :"en-IN", :"en-NZ", :"en-TT", :"en-US", :"en-ZA", :eo, :"es-419", :"es-AR", :"es-CL", :"es-CR", :"es-EC", :"es-ES", :"es-NI", :"es-PA", :"es-PE", :"es-US", :"es-VE", :eu, :"fr-CH", :"fr-FR", :fy, :gl, :"hi-IN", :"it-CH", :kk, :kn, :lb, :lo, :mg, :ml, :mn, :"mr-IN", :ne, :nn, :oc, :or, :pa, :rm, :st, :"sv-SE", :sw, :ta, :te, :tt, :ug, :uz, :wo]
嗯,好,有在。
好吧,現在我們有三個選擇,一個是修改這個 gem (這個我們未來再寫一篇文來講解 by 老高語氣),一個是將 *.zh-TW.yml 改為 *.zh-CN.yml,另一個則是在 config/application.rb 加入:
config.i18n.enforce_available_locales = false
config.i18n.available_locales = [:"zh-TW", :"en"]
這麼一來,rails 就能讀到 zh-TW 了。以 IP 找國家
可以借助 alexreisner/geocoder 這個 gem。
但在 VPN 橫流、人們可以出國的情況下,用到的機會可能不高。
參考資料
https://ithelp.ithome.com.tw/articles/10304324?sc=iThelpR
https://blog.roachking.net/blog/2014/04/12/rails-4-1-0-invalid-locacle/
https://rails.ruby.tw/i18n.html
留言
張貼留言