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

[英]How can I make Rails 3 localize my date formats?


I am working on a Rails 3 project where there is place for date input within a form. The text field with the date uses a date picker so there is no concern about the date being entered in a wrong format, however the date is being displayed in the :db format (e.g. 2010-01-21).

我正在一个Rails 3项目中工作,在这个项目中,表单中有日期输入的位置。带有日期的文本字段使用日期选择器,因此不关心以错误的格式输入的日期,但是日期显示为:db格式(例如2010-01-21)。

(Note: this is specifically in form fields - e.g. <%= f.text_field :publish_date %>, which should automatically use :default format, and shouldn't need to be provided with a value)

(注意:这是特定于表单字段的-例如<%= f。text_field:publish_date %>,应该自动使用:默认格式,不需要提供值)

I have tried adding in a customized locale which has the following date configuration:

我尝试添加一个定制的locale,它有以下日期配置:

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"

And then setting my locale to this (config.i18n.default_locale = "en-AU") however this doesn't seem to take and its becoming quite frustrating.

然后将我的语言环境设置为这个(config.i18n.default_locale = "en-AU"),但这似乎并不是很令人沮丧。

The app will eventually support a number of locales, so setting up an initializer to override the date formats at application startup isn't really suitable, and I know that this should work - I'm guessing I've missed something here.

这个应用程序最终将支持多个地区,所以在应用程序启动时设置一个初始化器来覆盖日期格式并不是很合适,我知道这应该是可行的——我想我在这里漏掉了一些东西。

The locale file is: config/locales/en-AU.yml and in my application.rb I am including:

地区文件是:config/locales/en-AU。在我的申请中。rb我包括:

config.i18n.load_path += Dir[Rails.root.join("config", "locales", "*.yml").to_s]
config.i18n.default_locale = "en-AU"

in my application.rb file.

在我的应用程序。rb文件。

5 个解决方案

#1


85  

When displaying a date, you can use I18n.l

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

So you would do :

你会这样做:

I18n.l @entry.created_at

And if you want to change it's format :

如果你想改变它的格式:

I18n.l @entry.created_at, :format => :short

The internationalization rails guide is documenting that.

国际化rails指南正在记录这一点。

#2


7  

check out the delocalize gem, it might help you out some.

查看delocalize gem,它可能会帮助您解决一些问题。

https://github.com/clemens/delocalize

https://github.com/clemens/delocalize

http://www.railway.at/articles/2009/05/03/new-plugin-delocalize/

http://www.railway.at/articles/2009/05/03/new-plugin-delocalize/

#3


4  

What I found to be the best solution is this:

我发现最好的解决办法是:

  • I localize date formats in my locale file like you do
  • 我像您一样在我的语言环境文件中本地化日期格式
  • In my forms I localize the date by setting the value directly
  • 在我的表单中,我通过直接设置值来本地化日期。

<%= f.text_field :publish_date, :value => (@model.publish_date.nil? ? nil : l(@model.publish_date)) %>

< % = f。text_field:publish_date,:value => (@model.publish_date.nil?)吗?零:l(@model.publish_date))% >

It is not perfect sadly, but at least this way I can use my form for both new and existing records. Also the app will stay compatible with multiple locales compared to changing the default format with initializers. If you fully want to comply with DRY you could always write a custom helper.

遗憾的是,它并不完美,但至少我可以使用我的表单来处理新记录和现有记录。与使用初始化器更改默认格式相比,该应用程序还能与多个locale兼容。如果您完全想要遵从DRY,您可以始终编写一个自定义助手。

#4


4  

@damien-mathieu has a solid answer for displaying localized dates with I18n.localize, and his comment raises an important caveat: this breaks form text inputs. Since then, rails gives us a nice solution.

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

As of Rails 5, you can use the Rails attributes API to customize how user input is transformed into a model or database value. Actually, it was available in Rails 4.2, just not fully documented.

从Rails 5开始,您可以使用Rails属性API定制如何将用户输入转换为模型或数据库值。实际上,它在Rails 4.2中是可用的,只是没有完整的文档说明。

Through Sean Griffin's considerable efforts, all models' types are now defined as ActiveRecord::Type objects. This defines a single source of truth for how an attribute is handled. The type defines how the attribute is serialized (from a ruby type to a database type), deserialized (from a database type to a ruby type) and cast (from user input to a ruby type). This is a big deal, because messing with this used to be a minefield of special cases developers should avoid.

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

First, skim the attribute docs to understand how to override an attribute's type. You probably need to read the docs to understand this answer.

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

How Rails Transforms Attributes

Here's a quick tour of the Rails Attributes API. You can skip this section, but then you won't know how this stuff works. What fun is that?

下面简要介绍一下Rails属性API。你可以跳过这一部分,但是你不会知道这个东西是怎么工作的。那是什么乐趣?

Understanding how Rails handles user input for your attribute will let us override only one method instead of making a more complete custom type. It will also help you write better code, since rails' code is pretty good.

理解Rails如何处理属性的用户输入将使我们只覆盖一个方法,而不创建更完整的自定义类型。它还将帮助您编写更好的代码,因为rails的代码非常好。

Since you didn't mention a model, I'll assume you have a Post with a :publish_date attribute (some would prefer the name :published_on, but I digress).

由于您没有提到一个模型,所以我假定您有一个带有:publish_date属性的帖子(有些人更喜欢这个名称:published_on,但我要退出)。

What is your type?

Find out what type :publish_date is. We don't care that it is an instance of Date, we need to know what type_for_attribute returns:

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

This method is the only valid source of information for anything related to the types of a model's attributes.

此方法是与模型属性类型相关的所有信息的唯一有效来源。

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

Now we know the :publish_date attribute is a :date type. This is defined by ActiveRecord::Type::Date, which extends ActiveModel::Type::Date, which extends ActiveModel::Type::Value. I've linked to rails 5.1.3, but you'll want to read the source for your version.

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

How is user input transformed by ActiveRecord::Type::Date?

So, when you set :publish_date, the value is passed to cast, which calls cast_value. Since form input is a String, it will try a fast_string_to_date then fallback_string_to_date which uses Date._parse.

因此,当您设置:publish_date时,值被传递给cast,它调用cast_value。由于表单输入是一个字符串,它将尝试使用Date._parse的fast_string_to_date然后fallback_string_to_date。

If you're getting lost, don't worry. You don't need to understand rails' code to customize an attribute.

如果你迷路了,别担心。您不需要理解rails的代码来定制属性。

Defining a Custom Type

Now that we understand how Rails uses the attributes API, we can easily make our own. Just create a custom type to override cast_value to expect localized date strings:

现在我们已经了解了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

See how I just copied rails' code and made a small tweak. Easy. You might want to improve on this with a call to super and move the :short format to an option or constant.

看看我如何复制rails的代码并做了一个小小的修改。一件容易的事。您可能希望通过调用super来改进这一点,并将:short格式移动到一个选项或常量。

Register your type so it can be referenced by a symbol:

注册你的类型,以便它可以被一个符号引用:

# config/initializers/types.rb
ActiveRecord::Type.register(:localized_date, LocalizedDate)

Override the :publish_date type with your custom type:

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

class Post < ApplicationRecord
  attribute :publish_date, :localized_date
end

Now you can use localized values in your form inputs:

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

# 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 %>

#5


1  

You could override your getters for the :publish_date attribute.

您可以为:publish_date属性重写getter。

i.e. in your model:

即在你的模型:

def date( *format)
    self[:publish_date].strftime(format.first || default)
end

and in your view you could do either

在你看来,这两种方法都可以

@income.date("%d/%m/%Y")

or

@income.date

This would cause strftime to use the passed format string unless it was nil, in which case it would fall back to your default string.

这将导致strftime使用传递的格式字符串,除非它是nil,在这种情况下,它将返回到默认字符串。

Note: I used the splat operator to add support for getting the date without an argument. There may be a cleaner way to do that.

注意:我使用splat操作符添加了对无参数获取日期的支持。也许有一种更干净的方法。

智能推荐

注意!

本站翻译的文章,版权归属于本站,未经许可禁止转摘,转摘请注明本文地址:http://www.silva-art.net/blog/2010/10/07/353412e0386048ebf655568196e22b8d.html



 
© 2014-2019 ITdaan.com 粤ICP备14056181号  

赞助商广告