Локализация текстового поля, содержащего число в Ruby on Rails - PullRequest
14 голосов
/ 16 ноября 2011

В настоящее время я работаю над проектом по интернационализации одного из наших веб-приложений ruby-on-rails, чтобы его можно было использовать в других странах (в данном случае Франция будет первой).

Особая проблема, с которой я еще не разобрался, связана с отображением числовых полей. При отображении чисел только для целей отображения я делаю следующее:

<%= number_to_percentage(tax.rate, :precision => 2)%>

На английском языке это показывает 17.50 , но на французском это показывает 17,50 (с запятой вместо десятичной точки), что является ожидаемым. Проблема возникает в форме редактирования, когда я показываю текстовое поле

<%= f.text_field :rate, :size => 15 %>

Когда на экране отображается текстовое поле, в текстовом поле всегда отображается 17.50 с точкой, а не запятая для французского языка. Я не уверен, что это правильно.

Когда я попытался сделать следующее:

<%= f.text_field :rate, :size => 15, :value => number_with_precision(f.object.rate, :precision => 2) %>

Это действительно показывало 17,50 в текстовом поле для французского, но когда я нажимаю кнопку Обновить, чтобы сохранить форму, проверка Ruby включается и сообщает мне, что 17, 50 - это не число (точнее, оно говорит «n'est pas un nombre»). Я должен ввести 17.50 , чтобы сохранить его.

Честно говоря, я не совсем уверен, что нужно делать здесь правильно. Должны ли все страны вводить числа с точками в текстовых полях или есть ли способ заставить Ruby-on-Rails отображать запятые и правильно их проверять?

Ответы [ 2 ]

19 голосов
/ 21 ноября 2011

TL; DR

Это то, что я ненавижу делать снова и снова (я обслуживаю французских пользователей, их легко спутать с точками в качестве десятичного разделителя).

Я сейчас исключительно использую delocalize gem , который автоматически переводит формат.Вам просто нужно установить драгоценный камень и оставить все как есть, обо всем позаботиться.

Мне нравится читать, дайте длинное объяснение

Базовое преобразование:довольно просто, вам нужно конвертировать туда и обратно между следующими форматами:

  • Бэкэнд, обычно английский, используемый вашим постоянным хранилищем (база данных SQL, хранилище NoSQL, YAML,простой текстовый файл, что бы вам ни показалось, ...).

  • Интерфейс, какой формат предпочитает ваш пользователь.Я собираюсь использовать французский здесь, чтобы придерживаться вопроса *.

* также потому, что я довольно неравнодушен к этому; -)

Это означает, что у вас есть две точки, в которые необходимо выполнить преобразование:

  1. Исходящий : при выводе HTML-кода вы будетенеобходимо преобразовать с английского на французский.

  2. входящий : при обработке результата формы POST вам потребуется преобразовать обратно с французского на английский.

Ручной способ

Допустим, у меня есть следующая модель с полем rate в качестве десятичного числа с точностью до 2 (например, 19.60):

class Tax < ActiveRecord::Base
  # the attr_accessor isn't really necessary here, I just want to show that there's a database field
  attr_accessor :rate
end

Шаг конвертации (английский => французский) может быть выполнен путем переопределения text_field_tag:

ActionView::Helpers::FormTagHelper.class_eval do
  include ActionView::Helpers::NumberHelper

  alias original_text_field_tag text_field_tag
  def text_field_tag(name, value = nil, options = {})
    value = options.delete(:value) if options.key?(:value)
    if value.is_a?(Numeric)
      value = number_with_delimiter(value) # this method uses the current locale to format our value
    end
    original_text_field_tag(name, value, options)
  end
end

входящий шаг преобразования (французский => английский) будет обработан в модели.Мы переопределим средство записи атрибута rate, чтобы заменить каждый французский разделитель на английский:

class Tax < ActiveRecord::Base
  def rate=(rate)
    write_attribute(:rate, rate.gsub(I18n.t('number.format.separator'), '.')
  end
end

Это выглядит хорошо, потому что в примере есть только один атрибут и один тип данных для анализа, но представьте, чтосделать это для каждого поля числа, даты или времени в вашей модели.Это не мое представление о веселье.

Это также наивный * способ делать преобразования, он не обрабатывает:

  • Даты
  • Times
  • Разделители (например, 100,000.84)

* я уже говорил вам, что мне нравится французский?

Введите delocalize

Делокализация работает по тому же принципу, который я изложил выше, но выполняет работу гораздо более всесторонне:

  • Он обрабатывает Date, Time,DateTime и цифры.
  • Вам не нужно ничего делать, просто установите драгоценный камень.Он проверяет ваши столбцы ActiveRecord, чтобы определить, требуется ли преобразование этого типа, и выполняет это автоматически.
  • Преобразования чисел довольно просты, но даты действительно интересны.При анализе результата формы он будет пытаться использовать форматы даты, определенные в вашем файле локали, в порядке убывания и должен понимать дату, отформатированную следующим образом: 15 janvier 2012.
  • Будет выполняться каждое исходящее преобразование.автоматически.
  • Он проверен.
  • Он активен.

Одно предупреждение: он не обрабатывает проверки на стороне клиента.Если вы используете их, вам придется выяснить, как использовать i18n в вашей любимой среде JavaScript.

2 голосов
/ 21 ноября 2011

Это метод gsub:

В вашей модели:

before_validation :prepare_number


def prepare_number
  self.rate.gsub(/,/, '.') if self.rate.match /,\S/
end
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...