@@ -14,12 +14,13 @@ public class CurrencyFormatter {
1414 /// Returns a decimal value from a given string.
1515 /// - Parameters:
1616 /// - stringValue: the string received from the API
17+ /// - locale: the locale that the currency string is based on.
1718 ///
18- func convertToDecimal( from stringValue: String ) -> NSDecimalNumber ? {
19+ func convertToDecimal( from stringValue: String , locale : Locale = . current ) -> NSDecimalNumber ? {
1920
2021 // NSDecimalNumber use by default the local decimal separator to evaluate a decimal amount.
2122 // We substitute the current decimal separator with the locale decimal separator.
22- let localeDecimalSeparator = Locale . current . decimalSeparator ?? currencySettings. decimalSeparator
23+ let localeDecimalSeparator = locale . decimalSeparator ?? currencySettings. decimalSeparator
2324 var newStringValue = stringValue. replacingOccurrences ( of: " , " , with: localeDecimalSeparator)
2425 newStringValue = newStringValue. replacingOccurrences ( of: " . " , with: localeDecimalSeparator)
2526
@@ -28,7 +29,7 @@ public class CurrencyFormatter {
2829 let unit = currencySettings. symbol ( from: currencyCode)
2930 newStringValue = newStringValue. replacingOccurrences ( of: unit, with: " " )
3031
31- let decimalValue = NSDecimalNumber ( string: newStringValue, locale: Locale . current )
32+ let decimalValue = NSDecimalNumber ( string: newStringValue, locale: locale )
3233
3334 guard decimalValue != NSDecimalNumber . notANumber else {
3435 DDLogError ( " Error: string input is not a number: \( stringValue) " )
@@ -72,21 +73,22 @@ public class CurrencyFormatter {
7273
7374 /// Returns a string that displays the amount using all of the specified currency settings
7475 /// - Parameters:
75- /// - amount : a formatted string, preferably converted using `localize(_:in:with:including:)`.
76+ /// - stringValue : a formatted string, preferably converted using `localize(_:in:with:including:)`.
7677 /// - position: the currency position enum, either right, left, right_space, or left_space.
7778 /// - symbol: the currency symbol as a string, to be used with the amount.
79+ /// - isNegative: whether the value is negative or not.
80+ /// - locale: the locale that is used to format the currency amount string.
7881 ///
79- func formatCurrency( using stringValue: String , at position: CurrencySettings . CurrencyPosition , with symbol: String , isNegative: Bool ) -> String {
82+ func formatCurrency( using amount: String ,
83+ at position: CurrencySettings . CurrencyPosition ,
84+ with symbol: String ,
85+ isNegative: Bool ,
86+ locale: Locale = . current) -> String {
8087 let space = " \u{00a0} " // unicode equivalent of
8188 let negative = isNegative ? " - " : " "
8289
8390 // We're relying on the phone's Locale to assist with language direction
84- let current = Locale . current as NSLocale
85- let languageCode = current. object ( forKey: NSLocale . Key. languageCode) as? String
86-
87- // Remove all occurences of the minus sign from the string amount.
88- // We want to position the minus sign manually.
89- let amount = stringValue. replacingOccurrences ( of: " - " , with: " " )
91+ let languageCode = locale. languageCode
9092
9193 // Detect the language direction
9294 var languageDirection : Locale . LanguageDirection = . unknown
@@ -126,23 +128,25 @@ public class CurrencyFormatter {
126128 /// - Parameters:
127129 /// - amount: a raw string representation of the amount, from the API, with no formatting applied. e.g. "19.87"
128130 /// - currency: a 3-letter country code for currencies that are supported in the API. e.g. "USD"
131+ /// - locale: the locale that is used to format the currency amount string.
129132 ///
130- func formatAmount( _ stringAmount : String , with currency: String = CurrencySettings . shared . currencyCode . rawValue ) -> String ? {
131- guard let decimalAmount = convertToDecimal ( from: stringAmount ) else {
133+ func formatAmount( _ amount : String , with currency: String ? = nil , locale : Locale = . current ) -> String ? {
134+ guard let decimalAmount = convertToDecimal ( from: amount , locale : locale ) else {
132135 return nil
133136 }
134137
135- return formatAmount ( decimalAmount, with: currency)
138+ return formatAmount ( decimalAmount, with: currency ?? currencySettings . currencyCode . rawValue , locale : locale )
136139 }
137140
138141
139142 /// Formats the provided `amount` param into a human readable value and applies the currency option
140143 /// settings for the given currency.
141144 ///
142145 /// - Parameters:
143- /// - amount : a raw string representation of the amount, from the API, with no formatting applied. e.g. "19.87"
146+ /// - stringAmount : a raw string representation of the amount, from the API, with no formatting applied. e.g. "19.87"
144147 /// - currency: a 3-letter country code for currencies that are supported in the API. e.g. "USD"
145148 /// - roundSmallNumbers: if `true`, small numbers are rounded, if `false`, no rounding occurs (defaults to true)
149+ /// - locale: the locale that is used to format the currency amount string.
146150 /// - Returns: a formatted amount string
147151 ///
148152 /// For our purposes here, a "small number" is anything in-between -1000 and 1000 (exclusive).
@@ -167,17 +171,21 @@ public class CurrencyFormatter {
167171 /// - 5800199.56 becomes "$5.8m"
168172 ///
169173 func formatHumanReadableAmount( _ stringAmount: String ,
170- with currency: String = CurrencySettings . shared. currencyCode. rawValue,
171- roundSmallNumbers: Bool = true ) -> String ? {
172- guard let amount = convertToDecimal ( from: stringAmount) else {
174+ with currency: String ? = nil ,
175+ roundSmallNumbers: Bool = true ,
176+ locale: Locale = . current) -> String ? {
177+ guard let amount = convertToDecimal ( from: stringAmount, locale: locale) else {
178+ assertionFailure ( " Cannot convert the amount \" \( stringAmount) \" to decimal value with locale \( locale. identifier) " )
173179 return nil
174180 }
175181
176- let humanReadableAmount = amount. humanReadableString ( roundSmallNumbers: roundSmallNumbers)
182+ let currency = currency ?? currencySettings. currencyCode. rawValue
183+
184+ let humanReadableAmount = amount. abs ( ) . humanReadableString ( roundSmallNumbers: roundSmallNumbers)
177185 if humanReadableAmount == amount. stringValue, roundSmallNumbers == false {
178186 // The human readable version of amount is the same as the converted param value which means this is a "small"
179187 // number — format it normally *without* rounding.
180- return formatAmount ( amount, with: currency)
188+ return formatAmount ( amount, with: currency, locale : locale )
181189 }
182190
183191 // If we are here, the human readable version of the amount param is a "large" number *OR* a small number but rounding has been requested,
@@ -190,15 +198,18 @@ public class CurrencyFormatter {
190198 return formatCurrency ( using: humanReadableAmount,
191199 at: position,
192200 with: symbol,
193- isNegative: isNegative)
201+ isNegative: isNegative,
202+ locale: locale)
194203 }
195204
196205 /// Applies currency option settings to the amount for the given currency.
197206 /// - Parameters:
198207 /// - amount: a NSDecimalNumber representation of the amount, from the API, with no formatting applied. e.g. "19.87"
199208 /// - currency: a 3-letter country code for currencies that are supported in the API. e.g. "USD"
209+ /// - locale: the locale that is used to format the currency amount string.
200210 ///
201- func formatAmount( _ decimalAmount: NSDecimalNumber , with currency: String = CurrencySettings . shared. currencyCode. rawValue) -> String ? {
211+ func formatAmount( _ amount: NSDecimalNumber , with currency: String ? = nil , locale: Locale = . current) -> String ? {
212+ let currency = currency ?? currencySettings. currencyCode. rawValue
202213 // Get the currency code
203214 let code = CurrencySettings . CurrencyCode ( rawValue: currency) ?? currencySettings. currencyCode
204215 // Grab the read-only currency options. These are set by the user in Site > Settings.
@@ -210,7 +221,7 @@ public class CurrencyFormatter {
210221
211222 // Put all the pieces of user preferences on currency formatting together
212223 // and spit out a string that has the formatted amount.
213- let localized = localize ( decimalAmount ,
224+ let localized = localize ( amount ,
214225 with: separator,
215226 in: numberOfDecimals,
216227 including: thousandSeparator)
@@ -224,7 +235,8 @@ public class CurrencyFormatter {
224235 let formattedAmount = formatCurrency ( using: localizedAmount,
225236 at: position,
226237 with: symbol,
227- isNegative: decimalAmount. isNegative ( ) )
238+ isNegative: amount. isNegative ( ) ,
239+ locale: locale)
228240
229241 return formattedAmount
230242 }
0 commit comments