Вкратце
Настройки локали, относящиеся к валюте, бывают двух видов:
- Зависит от валюты : они связаны с денежной стоимостью и зависят только от валюты и остаются действительными, где бы вы ни использовали эту валюту. Это только международный код 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 (туннский динар), который, как и несколько других валют-динар, можно разделить на 1000 частей (миллимы),
- JPY (Японская иена), которую в прошлом можно было разделить на субъединицы (сенс) такой небольшой стоимости, что правительство Японии решило больше не использовать их. Вот почему для сумм в JPY больше нет десятичных знаков.
Результаты
Для пользователя будет полезен принцип наименьшего удивления , и вы увидите десятичный разделитель и разделитель тысяч, а также позиционирование, к которому он / она привык.
в моем текущем языковом стандарте (на моем языке код валюты находится справа, десятичные дроби разделяются запятой, а тысячи - с жестким пробелом ) результат будет:
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
Но если вы обычно работаете в среде, говорящей на английском sh, например, в культуре США, вы получите:
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)
Почему вам не следует полностью реализовывать то, что вы хотели
Если вы начнете адаптировать позиционирование, чтобы взять практику языка страны происхождения валюты, вы можете раздражать пользователи, которые больше не видят код валюты там, где они ожидают. К счастью, это не вызовет путаницы.
Пример: евро - валюта стран с очень разными культурами. Поэтому было определено, что правило позиционирования валюты или символа валюты зависит от языка текста, в котором отображается сумма. Официальная ссылка
Теперь, если вы начнете использовать разделители тысяч и десятичные дроби другого языка или страны, потому что это родная страна валюты, это вызовет настоящую путаницу. , особенно для небольших сумм. Более того, это не всегда возможно.
Пример: в Канаде одна и та же сумма в валюте записывается с десятичным разделителем запятой франкоязычными канадцами, а точка десятичного разделителя - англия sh канадцами. Это ясно показывает, что не валюта определяет используемые разделители, а язык пользователя.
Поэтому вы должны уважительно относиться к настройкам пользователя в этом отношении и изменять только настройки c конкретной валюты .