It Works on My Machine! - 数以万计的程式设计师
Rails默认的语系是英文。要换成繁体中文,可以安装rails-i18n这个gem有社群帮忙翻译的繁体中文:
Gemfile
加上gem "rails-i18n"
,然后执行bundle修改 config/application.rb 的默认语系
config.i18n.default_locale = "zh-TW"
这样就会使用http://github.com/svenfuchs/rails-i18n的繁体中文翻译。
要让你的网站可以支援多国语系,必须定义出翻译的词汇对应档案。这些词汇档放在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验证错误讯息会变成如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这个样板。
首先,数据库里面的时间一定都是储存 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
格式化时间之外,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 )