我如何使Rails 3本地化我的date格式?
我正在一个Rails 3项目中,有一个表单中的dateinput的地方。 带有date的文本字段使用dateselect器,因此不用担心input的date格式错误,但date显示为:db格式(例如2010-01-21)。
(注意:这是特别在表单字段 – 例如<%= f.text_field :publish_date %>
,它应该自动使用:默认格式,而不应该提供一个值)
我已经尝试添加具有以下dateconfiguration的自定义语言环境:
date: formats: # Use the strftime parameters for formats. # When no format has been given, it uses default. # You can provide other formats here if you like! default: "%d/%m/%Y" short: "%b %d" long: "%B %d, %Y"
然后设置我的语言环境( config.i18n.default_locale = "en-AU"
),但是这似乎并没有采取,它变得相当沮丧。
该应用程序最终将支持一些语言环境,所以在应用程序启动时设置一个初始化程序以覆盖date格式并不合适,而且我知道这应该起作用 – 我猜我已经错过了一些东西。
语言环境文件是: config/locales/en-AU.yml
并在我的application.rb我包括:
config.i18n.load_path += Dir[Rails.root.join("config", "locales", "*.yml").to_s] config.i18n.default_locale = "en-AU"
在我的application.rb文件中。
显示date时,可以使用I18n.l
所以你会这样做:
I18n.l @entry.created_at
如果你想改变它的格式:
I18n.l @entry.created_at, :format => :short
国际化轨道指南正在logging。
检查出本地化的gem,它可能会帮助你一些。
https://github.com/clemens/delocalize
http://www.railway.at/articles/2009/05/03/new-plugin-delocalize/
我发现最好的解决办法是:
- 我像你一样在本地化date格式本地化文件
- 在我的表单中,我通过直接设置值来本地化date
<%= f.text_field :publish_date, :value => (@model.publish_date.nil? ? nil : l(@model.publish_date)) %>
这不是完美的悲伤,但至less这样我可以使用我的表格为新的和现有的logging。 此外,与使用初始值设定项更改默认格式相比,该应用程序将保持兼容多个区域设置。 如果你完全想遵守DRY,你总是可以写一个自定义的帮手。
@ damien-mathieu对使用I18n.localize
显示本地化date有一个坚实的回答,他的评论提出了一个重要的警告:这打破了文本input。 从那以后,Rails给了我们一个很好的解决scheme
从Rails 5开始 ,您可以使用Rails属性API自定义用户input如何转换为模型或数据库值。 实际上,它在Rails 4.2中可用 ,但没有完整的文档。
通过Sean Griffin的相当大的努力,所有模型的types现在被定义为ActiveRecord::Type
对象。 这定义了如何处理属性的单一来源。 这个types定义了属性如何序列化(从rubytypes到数据库types),反序列化(从数据库types到rubytypes)和cast(从用户input到rubytypes)。 这是一个大问题,因为搞乱这个曾经是开发者应该避免的特殊情况的雷区。
首先,浏览attribute
文档以了解如何覆盖属性的types。 你可能需要阅读文档来理解这个答案。
Rails如何转换属性
这是一个Rails属性API的快速浏览。 你可以跳过这一节,但是你不知道这个东西是如何工作的。 那有什么好玩的?
了解Rails如何处理属性的用户input将让我们覆盖只有一个方法,而不是一个更完整的自定义types。 它也将帮助你编写更好的代码,因为rails的代码非常好。
由于你没有提到模型, 我假设你有一个Post
:publish_date
属性 (有些人会更喜欢名称:published_on
,但我离题了)。
你的types是什么?
找出什么types:publish_date
是。 我们不关心它是Date
一个实例,我们需要知道type_for_attribute返回的是什么:
此方法是与模型属性types相关的唯一有效信息来源。
$ rails c > post = Post.where.not(publish_date: nil).first > post.publish_date.class => Date > Post.type_for_attribute('publish_date').type => :date
现在我们知道:publish_date
属性是:date
types。 这是由ActiveRecord :: Type :: Date定义的,它扩展了ActiveModel :: Type :: Date ,它扩展了ActiveModel :: Type :: Value 。 我已经链接到5.1.3的轨道,但你会想要阅读你的版本的来源。
用户input如何通过ActiveRecord :: Type :: Date转换?
所以,当你设置:publish_date
,这个值被传递给cast ,它调用cast_value 。 由于表单input是一个string,它会尝试一个fast_string_to_date然后fallback_string_to_date使用Date._parse 。
如果你迷路了,别担心。 你不需要理解rails的代码来定制属性。
定义一个自定义types
现在我们已经了解了Rails如何使用属性API,我们可以轻松地创build自己的属性。 只需创build一个自定义types来覆盖cast_value
以期望本地化的datestring:
class LocalizedDate < ActiveRecord::Type::Date private # Convert localized date string to Date object. This takes I18n formatted date strings # from user input and casts them back to Date objects. def cast_value(value) if value.is_a?(::String) return if value.empty? format = I18n.translate("date.formats.short") Date.strptime(value, format) rescue nil elsif value.respond_to?(:to_date) value.to_date else value end end end
看看我是如何复制rails的代码,并做了一个小小的调整。 简单。 您可能希望通过调用super
来改进,并将:short
格式移至选项或常量。
注册您的types,以便它可以被符号引用:
# config/initializers/types.rb ActiveRecord::Type.register(:localized_date, LocalizedDate)
用您的自定义types覆盖:publish_date
types:
class Post < ApplicationRecord attribute :publish_date, :localized_date end
现在,您可以在表单input中使用本地化值:
# app/views/posts/_form.html.erb <%= form_for(@post) do |f| %> <%= f.label :publish_date %> <%= f.text_field :publish_date, value: (I18n.localize(value, format: :short) if value.present?) %> <% end %>
你可以覆盖你的getters :publish_date
属性。
即在你的模型中:
def date( *format) self[:publish_date].strftime(format.first || default) end
在你看来,你也可以做
@income.date("%d/%m/%Y")
要么
@income.date
这将导致strftime使用传递的格式string,除非它是零,在这种情况下,它会回落到您的默认string。
注意:我使用splat运算符来添加支持获取没有参数的date。 可能有更干净的方法来做到这一点。