更改 Swift 中多种货币的分组分隔符、货币符号和货币符号位置

Changing grouping separator, currency symbol and position of currency symbol for multiple currencies in Swift

我的应用使用多种货币,这些货币使用不同的格式,例如:

卢布的价格显示为:1,101 Руб.

美元的相同金额显示为:1101美元

如何通过为不同的货币定义一组不同的格式来更改分组分隔符、货币符号和货币符号的位置。

我的短代码是这样的

var formatter = NSNumberFormatter()
formatter.numberStyle = .CurrencyStyle
formatter.locale = NSLocale.currentLocale()
formatter.stringFromNumber(4500000)
//Output : ,500,000.00
//Expected : 4,500,000 Руб.

Swift 4 或更高版本

extension Formatter {
    static let belarusianRuble: NumberFormatter = {
        let formatter = NumberFormatter()
        // set the numberStyle to .CurrencyStyle
        formatter.numberStyle = .currency
        // set the desired negative and positive formats grouping, and currency symbol position
        formatter.positiveFormat = "#,##0 ¤"
        formatter.negativeFormat = "-#,##0 ¤"
        // set your custom currency symbol
        formatter.currencySymbol = "Руб"
        return formatter
    }()
}

let stringToDisplay = Formatter.belarusianRuble.string(for: 4500000)  // "4,500,000 Руб"

extension Formatter {
    static let currencyBYR: NumberFormatter = {
        let formatter = NumberFormatter()
        formatter.numberStyle = .currency
        formatter.positiveFormat = "#,##0 ¤"
        formatter.negativeFormat = "-#,##0 ¤"
        formatter.currencySymbol = "Руб"
        return formatter
    }()
    static let currencyEUR: NumberFormatter = {
        let formatter = NumberFormatter()
        formatter.locale = Locale(identifier: "pt_PT")
        formatter.numberStyle = .currency
        return formatter
    }()
    static let currencyUSD: NumberFormatter = {
        let formatter = NumberFormatter()
        formatter.locale = Locale(identifier: "en_US")
        formatter.numberStyle = .currency
        return formatter
    }()
    static let currencyBRL: NumberFormatter = {
        let formatter = NumberFormatter()
        formatter.locale = Locale(identifier: "pt_BR")
        formatter.numberStyle = .currency
        return formatter
    }()
    static let currencyRUB: NumberFormatter = {
        let formatter = NumberFormatter()
        formatter.locale = Locale(identifier: "ru_RU")
        formatter.numberStyle = .currency
        formatter.maximumFractionDigits = 0
        return formatter
    }()
    static let currencyLocale: NumberFormatter = {
        let formatter = NumberFormatter()
        formatter.locale = .current
        formatter.numberStyle = .currency
        return formatter
    }()
}

extension Numeric {
    var currencyLocale: String { return Formatter.currencyLocale.string(for: self) ?? "" }
    var currencyUSD: String { return Formatter.currencyUSD.string(for: self) ?? "" }
    var currencyEUR: String { return Formatter.currencyEUR.string(for: self) ?? "" }
    var currencyBYR: String { return Formatter.currencyBYR.string(for: self) ?? "" }
    var currencyBRL: String { return Formatter.currencyBRL.string(for: self) ?? "" }
    var currencyRUB: String { return Formatter.currencyRUB.string(for: self) ?? "" }
}

用法

let amount = 4500000.0

let stringLocale = amount.currencyLocale   // ",500,000.00"

let stringUSD = amount.currencyUSD         // ",500,000.00"
let stringEUR = amount.currencyEUR         // "4 500 000,00 €"
let stringBRL = amount.currencyBRL         // "R$ 4.500.000,00"
let stringBYR = amount.currencyBYR         // "4,500,000 Руб"
let stringRUB = amount.currencyRUB         // "4 500 000 ₽"

我最终得到了使用当前语言环境 decimal/thousands/grouping 分隔符的货币 class(感谢 @jcaron 在评论中的推荐)

class 提供了很少的定制功能,适合我的任务:

  • 货币符号
  • Minimum/maximum小数位数
  • 定位符号或者left/right

class Currency {
    var formatter = NumberFormatter()
    var symbol: String
    var isRTL: Bool

    init(_ currencySymbol: String, minFractionDigits: Int, maxFractionDigits: Int, isRTL: Bool) {
        self.formatter.currencySymbol = ""
        self.formatter.minimumFractionDigits = minFractionDigits
        self.formatter.maximumFractionDigits = maxFractionDigits
        self.formatter.numberStyle = .currency

        self.symbol = currencySymbol
        self.isRTL = isRTL
    }

    func beautify(_ price: Double) -> String {
        let str = self.formatter.string(from: NSNumber(value: price))!
        if self.isRTL {
            return str + self.symbol
        }
        return self.symbol + str
    }
}

初始化所需的格式化程序

struct CurrencyFormatter {
    static let byr = Currency(" Руб.", minFractionDigits: 2, maxFractionDigits: 2, isRTL: true)
    static let usd = Currency("US $", minFractionDigits: 2, maxFractionDigits: 2, isRTL: false)
    static let rub = Currency("\u{20BD} ", minFractionDigits: 0, maxFractionDigits: 1, isRTL: false)
}

用法

CurrencyFormatter.byr.beautify(12345.67) // Output: 12 345,67 Руб.
CurrencyFormatter.usd.beautify(12345.67) // Output: US  345,67
CurrencyFormatter.rub.beautify(12345.67) // Output: ₽ 12 345,7