Локализация рублей в Swift 5.3, XCode 13 — RUB вместо ₽
Делаю универсальное приложение для iOS, iPadOS, macOS. Приложение работает с кодами валют, приходящими из JSON API: RUB, USD, EUR и другие. Для отображения в приложении я конвертирую их в символы: ₽, $, €. Вроде задача элементарная и частично у меня получилось.
Воспользовался классом Locale.
Теперь внимание: все три символа прекрасно конвертируются в iOS Simulator, но ₽ остаётся как RUB на реальных устройствах — iOS, iPadOS, macOS.
import UIKit
func getSymbol(code: String) -> String? {
let result = Locale
.availableIdentifiers
.map { Locale(identifier: $0) }
.first { $0.currencyCode == code }
return result?.currencySymbol
}
print(getSymbol(code: "RUB")!) // ₽
Этот пример для Playground работает и заменяет RUB на ₽. Этот же код не работает на реальном iPhone, iPad, macOS.
В чём может быть проблема? Выглядит как баг библиотеки локализации.
Ответы (2 шт):
Это не баг, а фича. Если выполнить следующий код
for identifier in Locale.availableIdentifiers {
let locale = Locale(identifier: identifier)
if locale.currencyCode == code {
print("\(identifier)\t\(locale.currencyCode)\t\(locale.currencySymbol)")
}
}
то мы получим
ba_RU Optional("RUB") Optional("RUB")
ru_RU Optional("RUB") Optional("₽")
cv_RU Optional("RUB") Optional("RUB")
sah_RU Optional("RUB") Optional("₽")
ce_RU Optional("RUB") Optional("₽")
myv_RU Optional("RUB") Optional("RUB")
tt_RU Optional("RUB") Optional("₽")
os_RU Optional("RUB") Optional("₽")
en_RU Optional("RUB") Optional("RUB")
То бишь для разных локалей символ разный, и в вашем коде он видимо берется для ba_RU.
Вариант 1 - грязный фикс - это исправить ваш код таким образом, но не факт, что он будет работать для других валют
let result = Locale
.availableIdentifiers
.map { Locale(identifier: $0) }
.first { $0.currencyCode == code && $0.currencySymbol != code } // <--
Вариант 2 - использовать напрямую локаль (например текущую локаль юзера, если мы делаем вывод в интерфейс), а не код валюты, так как символ валюты как мы видим для разных локалей разный, и здесь вопрос, для какой локали вы хотите этот символ получить
func getSymbol(locale: Locale) -> String? {
locale.currencySymbol
}
Решения пробовал разные, решил добавить костыль, что если RUB — то ₽:
let result = Locale
.availableIdentifiers
.map { Locale(identifier: $0) }
.first { $0.currencyCode == currency.rawValue }
return result?.currencySymbol == "RUB" ? "₽" : String(result?.currencySymbol ?? "?")