diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index ac7cc3c50..e7457c39a 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -266,7 +266,8 @@ module ApplicationHelper when Integer object.to_s when Float - sprintf "%.2f", object + number_with_delimiter(object, delimiter: '', + separator: ::I18n.t('number.format.separator')) when User, Group html ? link_to_principal(object) : object.to_s when Project diff --git a/lib/redmine/field_format.rb b/lib/redmine/field_format.rb index a27311141..5e81055f1 100644 --- a/lib/redmine/field_format.rb +++ b/lib/redmine/field_format.rb @@ -539,8 +539,9 @@ module Redmine end def validate_single_value(custom_field, value, customized=nil) + value = normalize_float(value) errs = super - errs << ::I18n.t('activerecord.errors.messages.invalid') unless (Kernel.Float(value) rescue nil) + errs << ::I18n.t('activerecord.errors.messages.invalid') unless Kernel.Float(value, exception: false) errs end diff --git a/lib/redmine/i18n.rb b/lib/redmine/i18n.rb index 8434cd9be..dab486893 100644 --- a/lib/redmine/i18n.rb +++ b/lib/redmine/i18n.rb @@ -99,6 +99,18 @@ module Redmine end end + # Will consider language specific separator in user input + # and normalize them to a unified format to be accepted by Kernel.Float(). + # + # @param value [String] A string represenation of a float value. + # + # @note The delimiter cannot be used here if it is a decimal point since it + # will clash with the dot separator. + def normalize_float(value) + separator = ::I18n.t('number.format.separator') + value.gsub(/[#{separator}]/, separator => '.') + end + def day_name(day) ::I18n.t('date.day_names')[day % 7] end diff --git a/test/unit/lib/redmine/field_format/numeric_format_test.rb b/test/unit/lib/redmine/field_format/numeric_format_test.rb index 9ced022fb..7ceb61d2b 100644 --- a/test/unit/lib/redmine/field_format/numeric_format_test.rb +++ b/test/unit/lib/redmine/field_format/numeric_format_test.rb @@ -23,6 +23,10 @@ require 'redmine/field_format' class Redmine::NumericFieldFormatTest < ActionView::TestCase include ApplicationHelper + fixtures :projects, :users, :issue_statuses, :enumerations, + :trackers, :projects_trackers, :roles, :member_roles, + :members, :enabled_modules + def setup User.current = nil end @@ -34,4 +38,25 @@ class Redmine::NumericFieldFormatTest < ActionView::TestCase assert_equal 3, field.format.formatted_custom_value(self, custom_value, false) assert_equal '3', field.format.formatted_custom_value(self, custom_value, true) end + + + def test_float_field_value_should_validate_when_given_with_various_separator + field = IssueCustomField.generate!(field_format: 'float') + issue = Issue.generate!(tracker: Tracker.find(1), status: IssueStatus.find(1), priority: IssuePriority.find(6)) + ::I18n.locale = :de + assert field.format.validate_single_value(field, '3,33', issue) + ::I18n.locale = :en + assert field.format.validate_single_value(field, '3.33', issue) + end + + def test_float_field_should_format_with_various_locale_separator_and_delimiter + field = IssueCustomField.generate!(field_format: 'float') + issue = Issue.generate!(tracker: Tracker.find(1), status: IssueStatus.find(1), priority: IssuePriority.find(6)) + ::I18n.locale = :de + issue.custom_field_values = { field.id => '3333.33' } + issue.save! + assert_equal '3333,33', format_object(issue.reload.custom_field_values.last, false) + ::I18n.locale = :en + assert_equal '3333.33', format_object(issue.reload.custom_field_values.last, false) + end end