ios - 根据选择的货币代码格式化货币而不考虑设备的语言环境 (Swift)

标签 ios swift locale currency numberformatter

我正在尝试根据用户选择的货币来格式化货币。如果未选择货币,则使用设备的当前区域设置进行格式化。但是,我遇到了问题:
我正在使用数字格式化程序将 double 格式设置为货币字符串。

let formatter = NumberFormatter()
    formatter.numberStyle = .currency
    formatter.currencySymbol = ""
        
    if currencyCode != nil {
        formatter.currencyCode = currencyCode
    }
        
    let amount = Double(amt/100) + Double(amt%100)/100
    return formatter.string(from: NSNumber(value: amount))
}
货币代码基本上是用户选择的货币。但是,如果说用户选择 EURO,则格式与 USD 几乎相同,这意味着它不尊重所选货币。我知道我们不可能用货币代码创建语言环境,因为 EUR 在 26 个不同的国家/地区使用,因此不可能得出正确的语言环境。
此外,由于我使用的格式基本上是填充小数位,然后是 ONES、Tenths 等,并且某些货币不支持小数位,例如 PKR(巴基斯坦卢比),那么我该如何满足呢?
所以我的问题是如何正确格式化货币,而不管选择了哪种设备区域设置。
如果我的设备区域设置为 USD 并且我创建了一个 EUR 列表,我希望列表中的所有付款都采用 EUR 格式。
因此,如果以美元计算,以欧元计算的价格为 3,403.23 美元,则应为 3 403,23 欧元。

关于我应该如何格式化的任何建议?谢谢!

最佳答案

简而言之
与货币相关的区域设置有两种:

  • 货币相关 :这些都与有关货币值(value)并且仅取决于货币,并且在您使用该货币的任何地方都保持有效。这只是国际ISO代码和小数位数,定义为ISO 4217 .
  • 文化设置 :这些取决于与 的语言和国家相关的用法和实践。用户 而不是直接到货币。通常,它是货币代码或符号相对于值的位置,以及小数点和千位分隔符。

  • 幸运的是,Swift 可以很好地发挥作用。这里有一些代码,允许您调整货币相关设置,而无需涉及对用户而言重要的文化设置。我还将解释为什么您不应该更改所有本地设置。
    编码
    这是演示代码,带有几种代表性货币:
    let value: Double = 1345.23
    for mycur in ["USD", "TND", "EUR", "JPY" ] {
        let myformatter = NumberFormatter()
        myformatter.numberStyle = .currencyISOCode
        let newLocale = "\(Locale.current.identifier)@currency=\(mycur)" // this is it!
        myformatter.locale = Locale(identifier:newLocale)
        print ("currency:\(mycur): min:\(myformatter.minimumFractionDigits) max:\(myformatter.maximumFractionDigits)" 
        print ("result: \(myformatter.string(from: value as NSNumber) ?? "xxx")")
    }
    
    对于代表性演示,我使用了:
  • 美元和欧元,与大多数货币一样,可以分为 100 个子单位(美分),
  • TND (Tunesian Dinar),与其他一些第纳尔货币一样,可以分为 1000 个子单位(毫米),
  • JPY (日元),过去可以将其划分为值(value)如此小的子单位(sens),以致日本政府决定不再使用它们。这就是日元金额不再有小数的原因。

  • 结果
    对于用户,将受益于principle of least astonishment ,并查看小数点和千位分隔符以及他/她习惯的定位。
    在我当前的语言环境中(在我的语言中,货币代码在右边,小数用逗号分隔,千位用硬空格分隔)结果将是:
    cur:USD: min:2 max:2 result: 1  345,23 USD
    cur:TND: min:3 max:3 result: 1  345,230 TND
    cur:EUR: min:2 max:2 result: 1  345,23 EUR
    cur:JPY: min:0 max:0 result: 1  345 JPY
    
    但是,如果您通常在讲英语的环境中工作,例如在美国文化中,您将获得:
    cur:USD: min:2 max:2 result: USD 1,345.23
    cur:TND: min:3 max:3 result: TND 1,345.230
    cur:EUR: min:2 max:2 result: EUR 1,345.23
    cur:JPY: min:0 max:0 result: JPY 1,345
    
    这个怎么运作:
    代码的诀窍是创建一个新的区域设置,只需更改货币设置,但保留所有其他国家和语言相关参数不变。
        let newLocale = "\(Locale.current.identifier)@currency=\(mycur)" // this is it!
        myformatter.locale = Locale(identifier:newLocale)
    
    为什么你不应该完全实现你想要的
    如果您开始调整定位以采用货币来源国的语言,您可能会激怒用户,他们不再在他们期望的位置看到货币代码。幸运的是,它不会造成真正的困惑。
    示例:欧元是文化差异很大的国家的货币。因此,关于货币或货币符号定位的规则被定义为取决于金额出现的文本的语言。 Official reference
    现在,如果你开始采用 thousand and decimal separators其他语言或国家,因为它是货币的母国,这会造成真正的困惑,特别是对于较小的金额。此外,这并不总是可能的。
    示例:在加拿大,讲法语的加拿大人使用逗号小数分隔符书写相同的货币金额,而讲英语的加拿大人则使用点小数分隔符书写。这清楚地表明,决定使用分隔符的不是货币,而是用户的语言。
    因此,您应该尊重用户在这方面的设置,并且只调整货币特定的设置。

    关于ios - 根据选择的货币代码格式化货币而不考虑设备的语言环境 (Swift),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63298715/

    相关文章:

    xcode - OS X 应用程序在 XCode 外部启动时运行缓慢

    java - 基于插件的程序中的语言环境和 ResourceBundle

    ios - Homekit Accessory Simulator 在 Xcode 6 beta 6 中去了哪里?

    ios - 自定义 UILabel 在 Interface Builder 中显示不正确

    ios - 在 Swift 中获取联系人姓名和电话号码

    ios - 当 "draw"被 UIKit 调用时?

    c++ - 将 from_string 与提升日期一起使用

    python - 导入错误 : cannot import name normalize

    ios - 显示联系人姓名和电话号码。从地址簿中,抛出异常 NSInvalidArgumentException

    ios - 如何在后台开始录制 iOS Audio Session ?