如何让Rails 3本地化我的日期格式?

Mat*_*age 41 localization ruby-on-rails internationalization ruby-on-rails-3

我正在开发一个Rails 3项目,在该项目中可以在表单中输入日期.带有日期的文本字段使用日期选择器,因此不会担心以错误的格式输入日期,但是日期以:db格式显示(例如2010-01-21).

(注意:这特别是在表单字段中 - 例如<%= f.text_field :publish_date %>,应该自动使用:默认格式,并且不需要提供值)

我尝试添加具有以下日期配置的自定义区域设置:

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"
Run Code Online (Sandbox Code Playgroud)

然后将我的语言环境设置为this(config.i18n.default_locale = "en-AU")然而这似乎没有采取,它变得非常令人沮丧.

该应用程序最终将支持许多语言环境,因此在应用程序启动时设置初始化程序以覆盖日期格式并不合适,我知道这应该可行 - 我猜这里错过了一些东西.

语言环境文件是: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"
Run Code Online (Sandbox Code Playgroud)

在我的application.rb文件中.

Dam*_*IEU 85

显示日期时,您可以使用 I18n.l

所以你会这样做:

I18n.l @entry.created_at
Run Code Online (Sandbox Code Playgroud)

如果你想改变它的格式:

I18n.l @entry.created_at, :format => :short
Run Code Online (Sandbox Code Playgroud)

国际化的轨道导向是记录这一点.

  • 你不能这样做.TimeTime应该可以解析任何日期字段.因此rails强制格式化. (9认同)

Ans*_*son 7

@ damien-mathieu有一个可靠的答案显示本地化日期I18n.localize,他的评论提出了一个重要的警告:这打破了表单文本输入.从那以后,rails给了我们一个很好的解决方案.

Rails 5开始,您可以使用 Rails属性API来自定义用户输入转换为模型或数据库值的方式.实际上,它在Rails 4.2可用,但没有完整记录.

通过Sean Griffin的努力,所有模型的类型现在被定义为ActiveRecord::Type对象.这定义了如何处理属性的单一事实来源.该类型定义了属性的序列化方式(从ruby类型到数据库类型),反序列化(从数据库类型到ruby类型)和强制转换(从用户输入到ruby类型).这是一个大问题,因为搞乱这个曾经是开发人员应该避免的特殊情况的雷区.

首先,浏览attribute文档以了解如何覆盖属性的类型.您可能需要阅读文档才能理解这个答案.

Rails如何转换属性

这是Rails属性API的快速浏览.你可以跳过这一部分,但是你不会知道这些东西是如何工作的.这有什么乐趣?

了解Rails如何处理属性的用户输入将让我们只覆盖一种方法,而不是制作更完整的自定义类型.它还可以帮助您编写更好的代码,因为rails的代码非常好.

既然你没有提到一个模型,我会假设你有Post一个:publish_date属性(有些人更喜欢这个名字:published_on,但我离题了).

你的类型是什么?

找出什么类型:publish_date.我们不关心它是一个实例Date,我们需要知道type_for_attribute返回什么:

对于与模型属性类型相关的任何事物,此方法是唯一有效的信息源.

$ rails c
> post = Post.where.not(publish_date: nil).first
> post.publish_date.class
=> Date
> Post.type_for_attribute('publish_date').type
=> :date
Run Code Online (Sandbox Code Playgroud)

现在我们知道:publish_date属性是一种:date类型.这是由ActiveRecord :: Type :: Date定义的,它扩展了ActiveModel :: Type :: Date,它扩展了ActiveModel :: Type :: Value.我已经链接到rails 5.1.3,但您需要阅读您的版本的源代码.

如何通过ActiveRecord :: Type :: Date转换用户输入?

因此,当您设置时:publish_date,该值将传递给cast,后者调用cast_value.由于表单输入是一个String,它将尝试使用Date._parsefast_string_to_date然后fallback_string_to_date.

如果你迷路了,别担心.您无需了解rails的代码即可自定义属性.

定义自定义类型

现在我们已经了解了Rails如何使用属性API,我们可以轻松地创建自己的属性.只需创建一个自定义类型来覆盖cast_value以期望本地化的日期字符串

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
Run Code Online (Sandbox Code Playgroud)

看看我是如何复制rails的代码并做了一些小调整.简单.您可能希望通过调用super并将:short格式移动到选项或常量来改进此功能.

注册您的类型,以便它可以用符号引用:

# config/initializers/types.rb
ActiveRecord::Type.register(:localized_date, LocalizedDate)
Run Code Online (Sandbox Code Playgroud)

:publish_date使用您的自定义类型覆盖类型:

class Post < ApplicationRecord
  attribute :publish_date, :localized_date
end
Run Code Online (Sandbox Code Playgroud)

现在,您可以在表单输入中使用本地化值:

# 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 %>
Run Code Online (Sandbox Code Playgroud)