Files
sure/lib/money/formatting.rb
foXaCe 917101853b fix: Locale-aware currency formatting (#677)
* fix: Locale-aware currency formatting

Add locale-specific formatting for money display:
- French (fr): symbol after number with non-breaking space (1 000,12 €)
- German (de): symbol after number (1.000,12 €)
- Spanish (es): symbol after number (1.000,12 €)
- Italian (it): symbol after number (1.000,12 €)
- Portuguese-Brazil (pt-BR): symbol before with space (R$ 1.000,12)

This follows international conventions where most European languages
place the currency symbol after the number, unlike English.

* fix: Address CodeRabbit review comments

- Use non-breaking spaces (NBSP) for French locale formatting
- Add nil guard in locale_options to prevent NoMethodError
- Add test coverage for Portuguese (Brazil) locale

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-16 23:55:51 +01:00

72 lines
2.1 KiB
Ruby

module Money::Formatting
include ActiveSupport::NumberHelper
def format(options = {})
locale = options[:locale] || I18n.locale
default_opts = format_options(locale)
number_to_currency(amount, default_opts.merge(options))
end
alias_method :to_s, :format
def format_options(locale = nil)
local_option_overrides = locale_options(locale)
{
unit: get_symbol,
precision: currency.default_precision,
delimiter: currency.delimiter,
separator: currency.separator,
format: currency.default_format
}.merge(local_option_overrides)
end
private
def get_symbol
if currency.symbol == "$" && currency.iso_code != "USD"
[ currency.iso_code.first(2), currency.symbol ].join
else
currency.symbol
end
end
def locale_options(locale)
locale_sym = (locale || I18n.locale || :en).to_sym
# French locale: symbol after number with non-breaking space, comma as decimal separator
if locale_sym == :fr
return { delimiter: "\u00A0", separator: ",", format: "%n\u00A0%u" }
end
# German locale: symbol after number with space, comma as decimal separator
if locale_sym == :de
return { delimiter: ".", separator: ",", format: "%n %u" }
end
# Spanish locale: symbol after number with space, comma as decimal separator
if locale_sym == :es
return { delimiter: ".", separator: ",", format: "%n %u" }
end
# Italian locale: symbol after number with space, comma as decimal separator
if locale_sym == :it
return { delimiter: ".", separator: ",", format: "%n %u" }
end
# Portuguese (Brazil) locale: symbol before, comma as decimal separator
if locale_sym == :"pt-BR"
return { delimiter: ".", separator: ",", format: "%u %n" }
end
# Currency-specific overrides for remaining locales
case [ currency.iso_code, locale_sym ]
when [ "EUR", :nl ], [ "EUR", :pt ]
{ delimiter: ".", separator: ",", format: "%u %n" }
when [ "EUR", :en ], [ "EUR", :en_IE ]
{ delimiter: ",", separator: "." }
else
{}
end
end
end