I am trying to find out which decimal separator is used by the decimal pad keyboard in iOS, so I can convert strings entered by the user to numbers with NumberFormatter and back.
As I want to pre-fill the text field with an existing value, I need to have a number formatter that uses the same decimal separator as the decimal pad keyboard.
The language that my device is set to (German, Germany) uses a comma as the decimal separator. I have configured iOS to have the German keyboard as the primary and active keyboard and English (US, QWERTY) as a secondary keyboard.
The app that I am working on only has a base localization, which is English. In the scheme settings, region and language are set to system default.
If I run my app, the decimal separator used by the decimal pad keyboard is ".", which is the decimal separator used by the en-US keyboard, but not the de-DE keyboard. The normal alphabetic keyboard shows the German keyboard layout.
If I remove the en-US keyboard on the iOS device, the decimal separator changes to ",".
How can I reliably find out, which decimal separator is used by the decimal pad keyboard?
None of the solutions that I have tried so far work:
- Using the preset `decimalSeparator` of `NumberFormatter` always gives ",".
- Using `Locale.current.decimalSeparator` always returns "," as well.
- Using `textField.textInputMode?.primaryLanguage` to figure out the locale always returns `de-DE`.
- Using `Bundle.main.preferredLocalizations` to figure out the localization used by the app always returns `en`.
This is how the number formatter is configured:
let numberFormatter = NumberFormatter()
numberFormatter.minimumIntegerDigits = 1
numberFormatter.minimumFractionDigits = 0
numberFormatter.maximumFractionDigits = 2
It seems to be possible to determine the locale used by the decimal pad by finding matches between the active text input modes and app localizations:
let inputLocales = UITextInputMode.activeInputModes.compactMap {$0.primaryLanguage}.map(Locale.init(identifier:))
let localizations = Bundle.main.preferredLocalizations.map(Locale.init(identifier:))
let locale = inputLocales.flatMap { l in localizations.map {(l, $0)}}
.filter { preferredLanguage, preferredLocalization in
if preferredLocalization.regionCode == nil || preferredLanguage.regionCode == nil {
return preferredLanguage.languageCode == preferredLocalization.languageCode
} else {
return preferredLanguage == preferredLocalization
}
}
.first?.0
?? Locale.current
numberFormatter.locale = locale
However this solution has several disadvantages:
1. I do not know whether UIKit selects the decimal separator exactly this way. The behavior may be different for some languages
2. It has to be computed every time a number will be formatted, as the user may change keyboards while the app is running.