根据所选的货币代码设置货币格式,无论设备的区域设置如何 (Swift)

Osa*_*eem 4 locale currency numberformatter ios swift

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

\n

我正在使用数字格式化程序将双精度格式格式化为货币字符串。

\n
let formatter = NumberFormatter()\n    formatter.numberStyle = .currency\n    formatter.currencySymbol = ""\n        \n    if currencyCode != nil {\n        formatter.currencyCode = currencyCode\n    }\n        \n    let amount = Double(amt/100) + Double(amt%100)/100\n    return formatter.string(from: NSNumber(value: amount))\n}\n
Run Code Online (Sandbox Code Playgroud)\n

货币代码基本上是用户选择的货币。但是,如果用户选择欧元,则格式与美元几乎相同,这意味着它不尊重所选的货币。我知道我们不可能用货币代码创建区域设置,因为欧元在 26 个不同的国家/地区使用,因此不可能导出正确的区域设置。

\n

另外,由于我使用的格式基本上填充了小数位,然后是个位、十分位等,而某些货币不支持小数位,例如 PKR(巴基斯坦卢比),那么我该如何满足这一点呢?

\n

所以我的问题是,无论选择哪种设备区域设置,如何正确设置货币格式。\n如果我的设备区域设置是美元并且我创建了一个欧元列表,我希望列表中的所有付款都采用欧元格式。\n所以如果美元价格为欧元 3,403.23 美元,则应为 \xe2\x82\xac 3 403,23。

\n

关于我应该如何格式化有什么建议吗?谢谢!

\n

Chr*_*phe 8

简而言之

\n

与货币相关的区域设置有两种:

\n
    \n
  • 货币相关:这些与货币价值相关,仅取决于货币,并且无论您在何处使用该货币,都仍然有效。这只是ISO 4217定义的国际 ISO 代码和小数位数。
  • \n
  • 文化设置:这些取决于与用户的语言和国家/地区相关的用法和实践,而不是直接与货币相关。通常,它是货币代码或符号相对于值的位置,以及小数点和千位分隔符。
  • \n
\n

幸运的是,Swift 很好地改变了这一点。这里有一些代码,允许您调整货币相关设置,而无需触及对用户重要的文化设置。我还将解释为什么您不应该更改所有本地设置。

\n

代码

\n

这是演示代码,其中包含几种代表性货币:

\n
let value: Double = 1345.23\nfor mycur in ["USD", "TND", "EUR", "JPY" ] {\n    let myformatter = NumberFormatter()\n    myformatter.numberStyle = .currencyISOCode\n    let newLocale = "\\(Locale.current.identifier)@currency=\\(mycur)" // this is it!\n    myformatter.locale = Locale(identifier:newLocale)\n    print ("currency:\\(mycur): min:\\(myformatter.minimumFractionDigits) max:\\(myformatter.maximumFractionDigits)" \n    print ("result: \\(myformatter.string(from: value as NSNumber) ?? "xxx")")\n}\n
Run Code Online (Sandbox Code Playgroud)\n

对于代表性演示,我使用了:

\n
    \n
  • 美元和欧元,与大多数货币一样,可以分为 100 个子单位(美分),
  • \n
  • TND (突尼斯第纳尔),与其他一些第纳尔货币一样,可以分为 1000 个子单位(米林)
  • \n
  • 日元( JPY),过去可以分为价值很小的子单位(sens),以至于日本政府决定不再使用它们。这就是为什么日元金额不再有小数的原因。
  • \n
\n

结果

\n

对于用户来说,将受益于最小惊讶原则,并看到小数点和千位分隔符以及他/她习惯的定位。

\n

在我当前的语言环境中(在我的语言中,货币代码位于右侧,小数点用逗号分隔,千位用硬空格分隔)结果将是:

\n
cur:USD: min:2 max:2 result: 1 \xe2\x80\xaf345,23\xc2\xa0USD\ncur:TND: min:3 max:3 result: 1 \xe2\x80\xaf345,230\xc2\xa0TND\ncur:EUR: min:2 max:2 result: 1 \xe2\x80\xaf345,23\xc2\xa0EUR\ncur:JPY: min:0 max:0 result: 1 \xe2\x80\xaf345\xc2\xa0JPY\n
Run Code Online (Sandbox Code Playgroud)\n

但如果您通常在英语环境中工作,例如在美国文化中,您会得到:

\n
cur:USD: min:2 max:2 result: USD\xc2\xa01,345.23\ncur:TND: min:3 max:3 result: TND\xc2\xa01,345.230\ncur:EUR: min:2 max:2 result: EUR\xc2\xa01,345.23\ncur:JPY: min:0 max:0 result: JPY\xc2\xa01,345\n
Run Code Online (Sandbox Code Playgroud)\n

怎么运行的:

\n

该代码的技巧是创建一个新的区域设置,只需更改货币设置,但保留所有其他国家和语言相关参数不变。

\n
    let newLocale = "\\(Locale.current.identifier)@currency=\\(mycur)" // this is it!\n    myformatter.locale = Locale(identifier:newLocale)\n
Run Code Online (Sandbox Code Playgroud)\n

为什么你不应该完全实现你想要的

\n

如果您开始调整定位以采用货币来源国语言的做法,您可能会激怒用户,他们不再在他们期望的位置看到货币代码。幸运的是,它不会造成真正的混乱。

\n

示例:欧元是文化截然不同的国家的货币。因此,有关货币或货币符号定位的规则被定义为取决于金额出现的文本语言。 官方参考

\n

现在,如果您开始采用另一种语言或国家的千位和小数分隔符,因为它是货币的母国,这会造成真正的混乱,特别是对于较小的金额。而且,这并不总是可能的。

\n

示例:在加拿大,相同的货币金额由讲法语的加拿大人使用逗号小数分隔符书写,但由讲英语的加拿大人使用点小数分隔符书写。这清楚地表明,决定使用分隔符的不是货币,而是用户的语言。

\n

因此,您应该尊重用户在这方面的设置,并且仅调整特定于货币的设置。

\n

  • 很好的答案,我不知道“@currency”技巧。多谢。 (3认同)