web-dev-qa-db-fra.com

Avec un navigateur, comment savoir quel séparateur décimal le système d'exploitation utilise-t-il?

Je développe une application web.

J'ai besoin d'afficher correctement certaines données décimales afin qu'elles puissent être copiées et collées dans une certaine application GUI qui n'est pas sous mon contrôle.

L'application GUI est sensible aux paramètres régionaux et n'accepte que le séparateur décimal correct défini dans le système.

Je peux deviner le séparateur décimal de Accept-Language et la supposition sera correcte dans 95% des cas, mais parfois elle échoue.

Existe-t-il un moyen de le faire côté serveur (de préférence, afin que je puisse collecter des statistiques), ou côté client?

Mise à jour:

Le but de la tâche est de le faire automatiquement.

En fait, cette webapp est une sorte d'interface en ligne avec une ancienne interface graphique qui aide à remplir correctement les formulaires.

Le type d'utilisateurs qui l'utilisent n'ont généralement aucune idée de ce qu'est un séparateur décimal.

Le Accept-Language la solution est implémentée et fonctionne, mais j'aimerais l'améliorer.

pdate2:

Je dois récupérer un paramètre très spécifique: séparateur décimal défini dans Control Panel / Regional and Language Options / Regional Options / Customize.

Je gère quatre types de systèmes d'exploitation:

  1. Windows russe avec une virgule comme DS (80%).
  2. Windows en anglais avec un point comme DS (15%).
  3. Windows russe avec une période comme DS pour faire fonctionner les applications anglaises mal écrites (4%).
  4. Windows anglais avec une virgule comme DS pour faire fonctionner les applications russes mal écrites (1%).

Tous les 100% des clients sont en Russie et l'application héritée traite des formulaires émis par le gouvernement russe, donc demander un pays donnera 100% de la Fédération de Russie, et GeoIP donnera 80% de la Fédération de Russie et 20% des autres (incorrect) réponses.

70
Quassnoi

Voici une fonction JavaScript simple qui renverra ces informations. Testé dans Firefox, IE6 et IE7. J'ai dû fermer et redémarrer mon navigateur entre chaque modification du paramètre sous Panneau de configuration/Options régionales et linguistiques/Options régionales/Personnaliser. Cependant, il a repris non seulement la virgule et la période, mais aussi des choses personnalisées bizarres, comme la lettre "a".

function whatDecimalSeparator() {
    var n = 1.1;
    n = n.toLocaleString().substring(1, 2);
    return n;
}
function whatDecimalSeparator() {
    var n = 1.1;
    n = n.toLocaleString().substring(1, 2);
    return n;
}

console.log('You use "' + whatDecimalSeparator() + '" as Decimal seprator');

Est-ce que cela aide?

115
Chris Nielsen

Demandez à l'utilisateur, ne devinez pas. Ayez un paramètre pour cela dans votre application Web.

Modifié pour ajouter:

Je pense qu'il est correct de deviner le paramètre par défaut qui fonctionne bien, disons, 95% du temps. Ce que je voulais dire, c'est que l'utilisateur devrait toujours être capable de passer outre toutes les suppositions faites par le logiciel. J'ai déjà été trop souvent frustré lorsqu'un logiciel essaie d'être trop intelligent et ne permet pas d'être corrigé.

9
laalto

La récupération des séparateurs pour l'environnement local actuel ou donné est possible en utilisant Intl.NumberFormat#formatToParts.

function getDecimalSeparator(locale) {
    const numberWithDecimalSeparator = 1.1;
    return Intl.NumberFormat(locale)
        .formatToParts(numberWithDecimalSeparator)
        .find(part => part.type === 'decimal')
        .value;
}

Cela ne fonctionne que pour navigateurs prenant en charge l'API Intl . Sinon, cela nécessite un polyfill Intl

Exemples:

> getDecimalSeparator()
"."
> getDecimalSeparator('fr-FR')
","

Bonus:

Nous pourrions l'étendre pour récupérer le séparateur décimal ou groupe d'une locale donnée:

function getSeparator(locale, separatorType) {
        const numberWithGroupAndDecimalSeparator = 1000.1;
        return Intl.NumberFormat(locale)
            .formatToParts(numberWithGroupAndDecimalSeparator)
            .find(part => part.type === separatorType)
            .value;
    }

Exemples:

> getSeparator('en-US', 'decimal')
"."
> getSeparator('en-US', 'group')
","
> getSeparator('fr-FR', 'decimal')
","
> getSeparator('fr-FR', 'group')
" "
8
JBE
function getDecimalSeparator() {
    //fallback  
       var decSep = ".";

        try {
            // this works in FF, Chrome, IE, Safari and Opera
            var sep = parseFloat(3/2).toLocaleString().substring(1,2);
            if (sep === '.' || sep === ',') {
                decSep = sep;
            }
        } catch(e){}

        return decSep;
    }
7
Dr.Oblak

Pourquoi pas

0.1.toLocaleString().replace(/\d/g, '')
7
user3023011

Je peux deviner le séparateur décimal de Accept-Language et la supposition sera correcte dans 95% des cas, mais parfois elle échoue.

C'est l'OMI le meilleur plan d'action. Afin de gérer les échecs, ajoutez un lien pour le définir manuellement à côté de la zone d'affichage.

5
Michael Borgwardt

Même si vous saviez sous quels paramètres régionaux cette "application GUI" s'exécute, vous devez toujours comprendre comment elle obtient les paramètres régionaux actuels et comment il détermine le séparateur décimal.

je ne sais pas comment cela se fait sur un Mac, mais sur Windows, les applications sont censées interroger les préférences de l'utilisateur définies via le panneau de configuration. Il est fort possible que cette application mystère ignore ces paramètres et utilise à la place leur propre configuration interne.

Ou peut-être qu'ils prennent les paramètres régionaux actuels et déduisent le reste, plutôt que de le dire.

Même alors, en anglais, nombres sont donnés en groupes de 3 chiffres, avec une virgule séparant les groupes. c'est à dire.:

5,197,359,078

Sauf si le nombre était un entier contenant un numéro de téléphone:

519-735-9078

Sauf bien sûr, le nombre était un entier qui contient un numéro de compte:

5197359078

Dans ce cas, vous revenez à une logique surchargée codée en dur.

Modifier: exemple de devise supprimée, car la devise a ses propres règles de formatage.

1
Ian Boyd

OK, j'ai quelque chose à montrer, plus une preuve de concept qu'un produit fini, mais faute de spécifications précises, je laisse les choses de cette façon (ou je vais les sur-concevoir). Je poste dans un message séparé car ce sera un peu long. J'en ai profité pour essayer un peu plus jQuery ...

Le code Java: GetLocaleInfo.Java

import Java.applet.*;
import Java.util.Locale;
import Java.text.*;

public class GetLocaleInfo extends Applet
{
  Locale loc;
  NumberFormat nf;
  NumberFormat cnf;
  NumberFormat pnf;

  // For running as plain application
  public static void main(String args[])
  {
    final Applet applet = new GetLocaleInfo();
    applet.init();
    applet.start();
  }

  public void init() // Applet is loaded
  {
    // Use current locale
    loc = Locale.getDefault();
    nf = NumberFormat.getInstance();
    cnf = NumberFormat.getCurrencyInstance();
    pnf = NumberFormat.getPercentInstance();
  }

  public void start() // Applet should start
  {
    // Following output goes to Java console
    System.out.println(GetLocaleInformation());
    System.out.println(nf.format(0.1));
    System.out.println(cnf.format(1.0));
    System.out.println(pnf.format(0.01));
  }

  public String GetLocaleInformation()
  {
    return String.format("Locale for %s: country=%s (%s / %s), lang=%s (%s / %s), variant=%s (%s)",
        loc.getDisplayName(),
        loc.getDisplayCountry(),
        loc.getCountry(),
        loc.getISO3Country(),

        loc.getDisplayLanguage(),
        loc.getLanguage(),
        loc.getISO3Language(),

        loc.getDisplayVariant(),
        loc.getVariant()
    );
  }

  public String FormatNumber(String number)
  {
    double value = 0;
    try
    {
      value = Double.parseDouble(number);
    }
    catch (NumberFormatException nfe)
    {
      return "!";
    }
    return nf.format(value);
  }

  public String FormatCurrency(String number)
  {
    double value = 0;
    try
    {
      value = Double.parseDouble(number);
    }
    catch (NumberFormatException nfe)
    {
      return "!";
    }
    return cnf.format(value);
  }

  public String FormatPercent(String number)
  {
    double value = 0;
    try
    {
      value = Double.parseDouble(number);
    }
    catch (NumberFormatException nfe)
    {
      return "!";
    }
    return pnf.format(value);
  }
}

Un exemple de page HTML utilisant l'applet ci-dessus: GetLocaleInfo.html

<!-- Header skipped for brevity -->
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.2.6/jquery.js"></script>
<script type="text/javascript">
var applet;
$(document).ready(function()
{
  applet = document.getElementById('LocaleInfo');
  $('#Results').text(applet.GetLocaleInformation());
});
</script>
<script type="text/javascript">
function DoFormatting()
{
  $('table.toFormat').each(function()
  {
    var table = $(this);
    $('td', table).each(function(cellId)
    {
      var val = $(this);
      if (val.is('.number'))
      {
        val.text(applet.FormatNumber(val.text()));
      }
      else if (val.is('.currency'))
      {
        val.text(applet.FormatCurrency(val.text()));
      }
      else if (val.is('.percent'))
      {
        val.text(applet.FormatPercent(val.text()));
      }
    });
  });
}
</script>
</head>
<body>
  <div id="Container">
    <p>Page to demonstrate how JavaScript can get locale information from Java</p>
    <div id="AppletContainer">
      <object classid="Java:GetLocaleInfo.class"
          type="application/x-Java-applet" codetype="application/Java"
          name="LocaleInfo" id="LocaleInfo" width="0" height="0">
        <param name="code" value="GetLocaleInfo"/>
        <param name="mayscript" value="true"/>
        <param name="scriptable" value="true"/>
        <p><!-- Displayed if object isn't supported -->
          <strong>This browser does not have Java enabled.</strong>
          <br>
          <a href="http://Java.Sun.com/products/plugin/downloads/index.html" title="Download Java plug-in">
          Get the latest Java plug-in here
          </a> (or enable Java support).
        </p>
      </object>
    </div><!-- AppletContainer -->
    <p>
    Click on the button to format the table content to the locale rules of the user.
    </p>
    <input type="button" name="DoFormatting" id="DoFormatting" value="Format the table" onclick="javascript:DoFormatting()"/>
    <div id="Results">
    </div><!-- Results -->
<table class="toFormat">
<caption>Synthetic View</caption>
<thead><tr>
<th>Name</th><th>Value</th><th>Cost</th><th>Discount</th>
</tr></thead>
<tbody>
<tr><td>Foo</td><td class="number">3.1415926</td><td class="currency">21.36</td><td class="percent">0.196</td></tr>
<tr><td>Bar</td><td class="number">159263.14</td><td class="currency">33</td><td class="percent">0.33</td></tr>
<tr><td>Baz</td><td class="number">15926</td><td class="currency">12.99</td><td class="percent">0.05</td></tr>
<tr><td>Doh</td><td class="number">0.01415926</td><td class="currency">5.1</td><td class="percent">0.1</td></tr>
</tbody>
</table>
  </div><!-- Container -->
</body>
</html>

Testé sur Firefox 3.0, IE 6, Safari 3.1 et Opera 9.50, sur Windows XP Pro SP3. Cela fonctionne sans problème avec les deux premiers, sur Safari j'ai une étrange erreur après l'appel à init ():

Java.net.MalformedURLException: no protocol:
    at Java.net.URL.<init>(Unknown Source)
    at Java.net.URL.<init>(Unknown Source)
    at Java.net.URL.<init>(Unknown Source)
    at Sun.plugin.liveconnect.SecureInvocation.checkLiveConnectCaller(Unknown Source)
    at Sun.plugin.liveconnect.SecureInvocation.access$000(Unknown Source)
    at Sun.plugin.liveconnect.SecureInvocation$2.run(Unknown Source)
    at Java.security.AccessController.doPrivileged(Native Method)
    at Sun.plugin.liveconnect.SecureInvocation.CallMethod(Unknown Source)

mais ça marche toujours.

Je ne peux pas le faire fonctionner avec Opera: l'applet se charge correctement, car je peux voir la trace de l'appel init () dans la console Java, je n'ai aucune erreur lorsque JavaScript appelle le Java fonctions (sauf si j'ajoute et appelle une méthode obtenant un paramètre JSObject, curieusement), mais les fonctions Java ne sont pas appelées (j'ai ajouté la trace des appels).
Je crois que Liveconnect fonctionne dans Opera, mais je ne vois pas encore comment. Je ferai des recherches un peu plus.
[Mise à jour] J'ai supprimé les références à un fichier jar inexistant (ce qui n'arrête pas les autres navigateurs) et j'ai obtenu une trace des appels, mais cela ne met pas à jour la page.
Mmm, si je le fais alert(applet.GetLocaleInformation()); J'ai obtenu les informations, donc ça pourrait être un problème jQuery.

1
PhiLho

En utilisant les réponses d'autres personnes, j'ai compilé les fonctions utilitaires décimales et mille séparateurs suivantes:

var decimalSeparator = function() {
    return (1.1).toLocaleString().substring(1, 2);
};
var thousandSeparator = function() {
    return (1000).toLocaleString().substring(1, 2);
};

Prendre plaisir!

1
Juangui Jordán

Je pense que vous devez vous fier à JavaScript pour vous donner les paramètres régionaux.
Mais apparemment, JS n'a pas directement accès à ces informations.
Je vois Dojo Toolkit s'appuie sur une base de données externe pour trouver les informations locales, bien qu'il ne prenne pas en compte les changements de paramètres de compte, par exemple.
Une autre solution de contournement que je vois est d'avoir une petite Java qui interroge ces informations du système et JavaScript pour les sortir de Java.
Je peux donner plus d'informations si vous ne savez pas comment le faire (si vous voulez emprunter cette route alambiquée, bien sûr).

[EDIT] J'ai donc mis à jour ma connaissance du support de localisation en Java ...
Contrairement à ce que je pensais à l'origine, vous n'aurez pas directement le séparateur décimal ou mille caractères de séparation directement, comme vous le feriez avec le séparateur de ligne ou le séparateur de chemin: à la place Java propose des API pour formater les nombres ou les dates que vous fournissez.
D'une manière ou d'une autre, cela a du sens: en Europe, vous mettez souvent le symbole monétaire après le nombre, certains pays (l'Inde?) Ont une règle plus complexe pour séparer les chiffres, etc.

Une autre chose: Java trouve correctement les paramètres régionaux actuels du système, mais n'en prend pas les informations (peut-être pour les raisons ci-dessus). Au lieu de cela, il utilise son propre ensemble de règles. Donc, si vous avez un paramètre régional espagnol où vous avez remplacé le séparateur décimal par un signe d'exclamation, Java ne l'utilisera pas (mais peut-être pas votre application, de toute façon ...).

J'écris donc une applet exposant un service (fonctions) à JavaScript, permettant de formater les nombres aux paramètres régionaux actuels. Vous pouvez l'utiliser comme tel, en utilisant JavaScript pour formater les nombres sur le navigateur. Ou vous pouvez simplement le nourrir avec un numéro d'échantillon et en extraire les symboles, en les utilisant localement ou en les renvoyant au serveur.

Je termine et teste mon applet et la poste bientôt.

1
PhiLho