处理Ruby on Rails中的国际货币输入

时间:2009-11-03 18:22:09

标签: ruby-on-rails internationalization currency

我有an application来处理货币输入。但是,如果您在美国,则可以输入12,345.67的数字;在法国,它可能是12.345,67

在Rails中,有一种简单的方法可以使货币条目适应区域设置吗?

请注意,我不是在寻找货币的显示(ala number_to_currency),我正在寻找某人输入货币字符串,并将其转换为小数。

5 个答案:

答案 0 :(得分:11)

你可以试一试:

   def string_to_float(string)

      string.gsub!(/[^\d.,]/,'')          # Replace all Currency Symbols, Letters and -- from the string

      if string =~ /^.*[\.,]\d{1}$/       # If string ends in a single digit (e.g. ,2)
        string = string + "0"             # make it ,20 in order for the result to be in "cents"
      end

      unless string =~ /^.*[\.,]\d{2}$/   # If does not end in ,00 / .00 then
        string = string + "00"            # add trailing 00 to turn it into cents
      end

      string.gsub!(/[\.,]/,'')            # Replace all (.) and (,) so the string result becomes in "cents"  
      string.to_f / 100                   # Let to_float do the rest
   end

测试案例:

describe Currency do
  it "should mix and match" do
    Currency.string_to_float("$ 1,000.50").should eql(1000.50)
    Currency.string_to_float("€ 1.000,50").should eql(1000.50)
    Currency.string_to_float("€ 1.000,--").should eql(1000.to_f)
    Currency.string_to_float("$ 1,000.--").should eql(1000.to_f)    
  end     

  it "should strip the € sign" do
    Currency.string_to_float("€1").should eql(1.to_f)
  end

  it "should strip the $ sign" do
    Currency.string_to_float("$1").should eql(1.to_f)
  end

  it "should strip letter characters" do
    Currency.string_to_float("a123bc2").should eql(1232.to_f)
  end

  it "should strip - and --" do
    Currency.string_to_float("100,-").should eql(100.to_f)
    Currency.string_to_float("100,--").should eql(100.to_f)
  end

  it "should convert the , as delimitor to a ." do
    Currency.string_to_float("100,10").should eql(100.10)
  end

  it "should convert ignore , and . as separators" do
    Currency.string_to_float("1.000,10").should eql(1000.10)
    Currency.string_to_float("1,000.10").should eql(1000.10)
  end

  it "should be generous if you make a type in the last '0' digit" do
    Currency.string_to_float("123,2").should eql(123.2)
  end

答案 1 :(得分:5)

我们写了这个:

class String
  def safe_parse
    self.gsub(I18n.t("number.currency.format.unit"), '').gsub(I18n.t("number.currency.format.delimiter"), '').gsub(I18n.t("number.currency.format.separator"), '.').to_f
  end
end

当然,您必须在使用之前设置I18n.locale。它目前只将字符串转换为已设置的语言环境的浮点数。 (在我们的例子中,如果用户在法国网站上,我们希望货币金额文本只包含符合法国语言环境的符号和格式。)

答案 2 :(得分:4)

您需要清理输入,以便用户可以输入他们想要的任何内容,并且您将获得一致的内容以存储在您的数据库中。假设您的模型名为“DoughEntry”,您的属性为“amount”,并将其存储为整数。

这是一个将字符串输入转换为美分的方法(如果字符串以分隔符后面的两位数结尾,则假定为美分)。您可能希望更聪明,但这是概念:

def convert_to_cents(input)
  if input =~ /^.*[\.,]\d{2}$/ 
    input.gsub(/[^\d-]/,'').to_i
  else
    "#{input.gsub(/[^\d-]/,'')}00".to_i
  end
end

>> convert_to_cents "12,345"
=> 1234500
>> convert_to_cents "12.345,67"
=> 1234567
>> convert_to_cents "$12.345,67"
=> 1234567

然后覆盖默认的“金额”访问者,通过该方法传递:

class DoughEntry << ActiveRecord::Base

  def amount=(input)
    write_attribute(:amount, convert_to_cents(input))
  end

protected
  def convert_to_cents(input)
    if input =~ /^.*[\.,]\d{2}$/ 
      input.gsub(/[^\d-]/,'').to_i
    else
      "#{input.gsub(/[^\d-]/,'')}00".to_i
    end
  end
end

现在你将美分存储在数据库中。雷达有正确的想法将它拉回来。

答案 3 :(得分:2)

您可以尝试使用'aggregation' feature,并结合授权类。我会做类似的事情:

class Product
  composed_of :balance, 
         :class_name => "Money", 
         :mapping => %w(amount)
end

class Money < SimpleDelegator.new
   include Comparable
   attr_reader :amount

   def initialize(amount)
     @amount = Money.special_transform(amount)
     super(@amount)
   end

   def self.special_transform(amount)
     # your special convesion function here
   end

   def to_s
     nummber_to_currency @amount
   end
 end

通过这种方式,您可以直接指定:

Product.update_attributes(:price => '12.244,6')

Product.update_attributes(:price => '12,244.6')

优点是您不必在控制器/视图上修改任何

答案 4 :(得分:2)

使用内置I18n中的translations for numbers应该允许您以一种格式(1234.56)输入价格,然后使用I18n将它们带回number_to_currency以自动打印出来正确的语言环境。

当然,您必须使用I18n.locale设置before_filter,请查看I18n guide第2.3节。