web-dev-qa-db-fra.com

Obtenir le séparateur décimal du clavier décimal sur iOS

J'essaie de savoir quel séparateur décimal est utilisé par le clavier décimal dans iOS, afin de pouvoir convertir les chaînes entrées par l'utilisateur en nombres avec NumberFormatter et vice-versa.

Comme je veux pré-remplir le champ de texte avec une valeur existante, il me faut un formateur de nombres utilisant le même séparateur décimal que le clavier du pavé décimal.


La langue sur laquelle mon appareil est configuré (allemand, Allemagne) utilise une virgule comme séparateur décimal. J'ai configuré iOS pour avoir le clavier allemand comme clavier principal et actif et l'anglais (US, QWERTY) comme clavier secondaire. 

L'application sur laquelle je travaille n'a qu'une localisation de base, qui est l'anglais. Dans les paramètres du schéma, la région et la langue sont définies sur les valeurs par défaut du système.

Si j'exécute mon application, le séparateur décimal utilisé par le clavier décimal est ".", Qui est le séparateur décimal utilisé par le clavier en-US, mais pas par le clavier de-DE. Le clavier alphabétique normal montre la disposition du clavier allemand.

Si je supprime le clavier en-US sur le périphérique iOS, le séparateur décimal devient ",".


Comment puis-je savoir de manière fiable quel séparateur décimal est utilisé par le clavier décimal?  

Aucune des solutions que j'ai essayées jusqu'à présent ne fonctionne:

  • L'utilisation du paramètre prédéfini decimalSeparator of NumberFormatter donne toujours ",".
  • Utiliser Locale.current.decimalSeparator renvoie toujours "," également.
  • L'utilisation de textField.textInputMode?.primaryLanguage pour déterminer les paramètres régionaux renvoie toujours de-DE.
  • L'utilisation de Bundle.main.preferredLocalizations pour déterminer la localisation utilisée par l'application renvoie toujours en.

Voici comment le formateur de nombres est configuré:

let numberFormatter = NumberFormatter()
numberFormatter.minimumIntegerDigits = 1
numberFormatter.minimumFractionDigits = 0
numberFormatter.maximumFractionDigits = 2

Edit: Il semble être possible de déterminer les paramètres régionaux utilisés par le pavé décimal en recherchant des correspondances entre les modes de saisie de texte actifs et les localisations d'application:

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

Cependant, cette solution présente plusieurs inconvénients:

  1. Je ne sais pas si UIKit sélectionne le séparateur décimal exactement de cette façon. Le comportement peut être différent pour certaines langues
  2. Il doit être calculé à chaque fois qu'un nombre sera formaté, car l'utilisateur peut changer de clavier pendant l'exécution de l'application.
9
Palle

D'après mon expérience, lorsque vous ne supportez que la localisation anglaise, le séparateur décimal dans le type de clavier décimal sera toujours .. Vous devez donc forcer en_US locale dans la NumberFormatter lors de l'analyse d'un nombre à partir d'une chaîne.

Voici un extrait de code qui tente d’analyser d’abord en utilisant en_US, puis d’essayer en utilisant Locale.current.

func parseNumber(_ text:String) -> Double? {

    // since we only support english localization, keyboard always show '.' as decimal separator,
    // hence we need to force en_US locale
    let fmtUS = NumberFormatter()
    fmtUS.locale = Locale(identifier: "en_US")
    if let number = fmtUS.number(from: text)?.doubleValue {
        print("parsed using \(fmtUS.locale)")
        return number
    }

    let fmtCurrent = NumberFormatter()
    fmtCurrent.locale = Locale.current
    if let number = fmtCurrent.number(from: text)?.doubleValue {
        print("parsed using \(fmtCurrent.locale)")
        return number
    }

    print("can't parse number")
    return nil
}

J'apprécierais que Apple ajoute le séparateur décimal Locale.current comme séparateur décimal pour les types de clavier décimaux, sinon nous aurions besoin d'ajouter la localisation pour tous les paramètres régionaux afin d'obtenir ce droit. 

1
Erlend