Wednesday, 11 July 2018

Get decimal separator of decimal pad keyboard on iOS

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


Edit: 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.


from Get decimal separator of decimal pad keyboard on iOS

No comments:

Post a Comment