Bir tarayıcıyla, işletim sisteminin hangi ondalık ayırıcıyı kullandığını nasıl bilebilirim?


82

Bir web uygulaması geliştiriyorum.

GUIKontrolüm altında olmayan belirli bir uygulamaya kopyalanıp yapıştırılabilmesi için bazı ondalık verileri doğru şekilde görüntülemem gerekiyor .

GUI uygulaması yerel ayara duyarlıdır ve yalnızca sistemde ayarlanan doğru ondalık ayırıcıyı kabul eder.

Ondalık ayırıcıyı tahmin edebilirim Accept-Languageve tahmin% 95 durumlarda doğru olacaktır, ancak bazen başarısız olur.

Bunu sunucu tarafında (tercihen istatistik toplayabilmem için) veya istemci tarafında yapmanın bir yolu var mı?

Güncelleme:

Görevin tüm amacı, bunu otomatik olarak yapmaktır.

Aslında bu web uygulaması, formları doğru bir şekilde doldurmaya yardımcı olan eski bir GUI için bir tür çevrimiçi arayüzdür.

Bunu kullanan türden kullanıcılar, çoğunlukla ondalık ayırıcının ne olduğu konusunda hiçbir fikre sahip değildir.

Accept-LanguageSolüsyon uygulanmış ve çalışır, ama bunu geliştirmek istiyorum edilmektedir.

Güncelleme2:

Çok özel bir ayara geri dönmem gerekiyor: ondalık ayırıcı ayarlanmış Control Panel / Regional and Language Options / Regional Options / Customize.

Dört tür işletim sistemi ile ilgileniyorum:

  1. DS olarak virgül içeren Rusça Windows (% 80).
  2. DS olarak dönemli İngilizce Windows (% 15).
  3. Kötü yazılmış İngilizce uygulamalarını çalıştırmak için bir DS olarak süreye sahip Rusça Windows (% 4).
  4. Kötü yazılmış Rusça uygulamaların çalışması için DS olarak virgül ile İngilizce Windows (% 1).

Müşterilerin% 100'ü Rusya'da ve eski uygulama Rusya hükümeti tarafından verilen formlarla ilgileniyor, bu nedenle bir ülke istemek Rusya Federasyonu'nun% 100'ünü, GeoIP ise Rusya Federasyonu'nun% 80'ini ve diğerlerinin% 20'sini verecek (yanlış) Yanıtlar.

Yanıtlar:


129

İşte bu bilgiyi döndürecek basit bir JavaScript işlevi. Firefox, IE6 ve IE7'de test edilmiştir. Denetim Masası / Bölge ve Dil Seçenekleri / Bölgesel Seçenekler / Özelleştir altındaki ayarda yapılan her değişiklik arasında tarayıcımı kapatıp yeniden başlatmak zorunda kaldım. Ancak, yalnızca virgül ve noktayı değil, aynı zamanda "a" harfi gibi tuhaf özel şeyleri de aldı.

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

Bu yardımcı olur mu?


3
Bu benim için Firefox ve IE8'de çalıştı, ancak Google Chrome'da işe yaramadı. Opera'm yok.
Matthew Talbert

@Matthew - Chrome'da benim için çalıştı. @Quassnoi - Son yorumun ne anlama geldiğini anlamıyorum. İşlevin çalışmadığını söylüyorsa, o zaman kişinin ne bildiği ne fark eder?
Matchu

Dikkat et! Chrome'da toLocaleString yalnızca doğrudan bir Numara üzerinden çağrıldığında düzgün çalışır. Sistemimde: [1.1,1.2] .toLocaleString () -> "1.1,1.2" | (1.1) .toLocaleString () -> "1,1"
Tarnay Kálmán

1
İşlev, DecimalSeparator(örneğin ,,) için birden fazla karakter kullanan yerel ayarlarda başarısız olur . Windows LOCALE_SDECIMAL, ondalık ayırıcının en fazla üç karakter içermesine izin verir. (Bu yüzden bilgisayarımda başarısız oluyor). Daha iyi kullanmak için Accept-Languagebu durumda tarayıcının. Bu da kendi DecimalSeparatorörneğini belirleme yeteneğini hala hesaba \o/
katmıyor

4
@IanBoyd, ondalık ayırıcı olarak birden fazla karakter dizesi olan yerel ayarlar konusunda haklıdır, ancak n = /^1(.+)1$/.exec(n.toLocaleString())[1]bunu yapar ve Accept-Languagebaşlığı kullanmaktan daha kolaydır .
ygormutti

16

Geçerli veya belirli bir yerel ayar için ayırıcıların alınması kullanılarak mümkündür Intl.NumberFormat#formatToParts.

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

Yalnızca Intl API'yi destekleyen tarayıcılarda çalışır . Aksi takdirde, Intl polyfill gerektirir

Örnekler:

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

Bonus:

Belirli bir yerel ayarın ondalık veya grup ayırıcısını almak için genişletebiliriz :

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

Örnekler:

> getSeparator('en-US', 'decimal')
"."
> getSeparator('en-US', 'group')
","
> getSeparator('fr-FR', 'decimal')
","
> getSeparator('fr-FR', 'group')
" "

Şu anda bu tür bilgileri almanın en uygun yolu budur. BTW Intl, IE 11'de bile destekleniyor: caniuse.com/#feat=internationalization
Konstantin Smolyanin

3
FormatToParts desteklenmediğinden, bu IE 11'de çalışmayacaktır.
Gajendra Kumar

11

Kullanıcıya sorun, tahmin etme. Web uygulamanızda bunun için bir ayar bulundurun.

Eklemek için düzenlendi:

Sanırım zamanın% 95'inde sorunsuz çalışan varsayılan ayarı tahmin etmenin uygun olduğunu düşünüyorum . Demek istediğim, kullanıcının yine de yazılımın yaptığı tahminler ne olursa olsun geçersiz kılabilmesi gerektiğiydi. Bir yazılım çok akıllı olmaya çalıştığında ve düzeltilmesine izin vermediğinde zaten birçok kez hayal kırıklığına uğradım.


İlginç, benim ilk fikir, ama denize ... otomatik bunu nasıl aramaya başladı
PhiLho

1
Belki yedek olması dışında kötü fikir. Çoğu kullanıcı utanç verici kültüre duyarsızdır ve açıklama olmadan "ondalık ayırıcının" ne olduğunu anlamaz (ve "herkesin bildiği" bir şeyi ayarlamaya zorlanmaktan kızar).
Michael Borgwardt

2
@Iaalto: Bu, soruyu neredeyse "Veritabanı boyutunu küçült (önerilen) veya Arama yeteneklerini en üst düzeye çıkar?" Kadar harika yapar.
Quassnoi

Bu çok zor olmamalı. Sadece kullanıcının ülkeyi seçmesine izin verin ve ardından desikmal ayırıcı ve diğer seçenekleri buna göre seçin.

7
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;
    }

1
yedek "." bazı belirsiz tarayıcılarda ... diğer yollarla hemen hemen aynı şey ...
Dr.Oblak


5

Accept-Language'den ondalık ayırıcı tahmin edebiliyorum ve tahmin% 95 oranında doğru olacak, ancak bazen başarısız oluyor.

Bu, IMO'nun en iyi eylem şeklidir. Hataların üstesinden gelmek için, görüntüleme alanının yanına manuel olarak ayarlamak üzere bir bağlantı ekleyin.


Bu nasıl halledilebilir? Bunun gibi bir tarayıcı kitaplığı kullanabileceğinizi anlıyorum github.com/dansingerman/jQuery-Browser-Language
Lime

@William: OP'nin bahsettiği Acccept-Language, tarayıcı tarafından gönderilen ve sunucuya kullanıcının hangi dili tercih ettiğini, genellikle tarayıcı kurulumunun veya işletim sisteminin dilini söyleyen bir HTTP başlığıdır.
Michael Borgwardt

4

Diğer kişilerin yanıtlarını kullanarak aşağıdaki ondalık ve binlik ayırıcı yardımcı program işlevlerini derledim:

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

Zevk almak!


Evet, bu yöntemi desteklemeyen tarayıcılar için formatToParts(Safari ve IE) çoklu dolgu olarak kullandım .
Marko Bonaci

1
Bazı yerel ayarlar (1000).toLocaleString("es-PE") # "1000"
10000'in

1

Size yerel ayarları vermek için JavaScript'e güvenmeniz gerektiğini düşünüyorum.
Ancak görünüşe göre JS'nin bu bilgilere doğrudan erişimi yok. Dojo Toolkit'in yerel bilgileri bulmak için harici bir veritabanına dayandığını
görüyorum , ancak örneğin hesap ayarı değişikliklerini almayabilir. Gördüğüm başka bir geçici çözüm, bu bilgiyi sistemden sorgulayan küçük bir sessiz Java uygulamasına ve Java'dan çıkarmak için JavaScript'e sahip olmaktır. Nasıl yapılacağını bilmiyorsanız daha fazla bilgi verebilirim (tabii bu kıvrımlı rotaya gitmek istiyorsanız).

[DÜZENLE] Bu yüzden Java'da yerelleştirme desteğiyle ilgili bilgilerimi güncelledim ...
İlk başta düşündüğümden farklı olarak, doğrudan ondalık ayırıcıya veya bin ayırıcı karakterine sahip olmayacaksınız, tıpkı satır ayırıcı veya yol ayırıcıyla yapacağınız gibi: Java yerine Sağladığınız sayıları veya tarihleri ​​biçimlendirmek için API'ler sunar.
Her nasılsa mantıklı geliyor: Avrupa'da para birimi simgesini sık sık rakamdan sonra koyarsınız, bazı ülkelerde (Hindistan?) Rakamları ayırmak için daha karmaşık bir kural vardır, vb.

Başka bir şey: Java, geçerli yerel ayarı sistemden doğru bir şekilde bulur, ancak oradan bilgi almaz (belki yukarıdaki nedenlerden dolayı). Bunun yerine kendi kurallarını kullanır. Dolayısıyla, ondalık ayırıcıyı ünlem işaretiyle değiştirdiğiniz bir İspanyolca yerel ayarınız varsa, Java bunu kullanmaz (belki de uygulamanızı kullanmaz, en azından ...).

Bu yüzden, bir hizmeti (işlevleri) JavaScript'e sunan, sayıları mevcut yerel ayara göre biçimlendirmeye izin veren bir uygulama yazıyorum. Tarayıcıda sayıları biçimlendirmek için JavaScript kullanarak bu şekilde kullanabilirsiniz. Ya da sadece bir örnek numarayla besleyebilir ve sembolleri buradan çıkarabilir, yerel olarak kullanabilir veya sunucuya geri besleyebilirsiniz.

Uygulamamı bitirip test ediyorum ve yakında oraya gönderiyorum.


@PhiLho: bilmek güzel olurdu. Bu web uygulaması bir tür yardım sistemidir, bu yüzden herhangi bir çirkin hack işe yarar, IE, Firefox ve Opera'da çalıştığı sürece zarif olması gerekmez.
Quassnoi

1

Tamam, gösterecek bir şeyim var, bitmiş bir üründen daha çok bir konsept kanıtı var, ancak kesin spesifikasyonların olmaması nedeniyle, onu bu şekilde bırakıyorum (ya da aşırı mühendislik yapacağım). Biraz uzun olacağı için ayrı bir mesaj gönderiyorum. Biraz daha jQuery denemek için fırsat buldum ...

Java kodu: 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);
  }
}

Yukarıdaki uygulamayı kullanan bir HTML sayfası örneği: 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>

Windows XP Pro SP3'te Firefox 3.0, IE 6, Safari 3.1 ve Opera 9.50'de test edilmiştir. İlk ikisinde sorunsuz çalışıyor, Safari'de init () çağrısından sonra garip bir hatam var:

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)

ama yine de çalışıyor.

Opera ile çalışmasını sağlayamıyorum: Java konsolunda init () çağrısının izini görebildiğim için uygulama doğru şekilde yükleniyor, JavaScript Java işlevlerini çağırdığında hiçbir hatam yok (bir yöntem ekler ve çağırırsam bir JSObject parametresi alıyorum, merakla), ancak Java işlevleri çağrılmıyor (çağrıların izini ekledim).
Liveconnect'in Opera'da çalıştığına inanıyorum, ancak henüz nasıl olduğunu bilmiyorum. Biraz daha araştıracağım.
[Güncelleme] Mevcut olmayan jar dosyasına (diğer tarayıcıları durdurmayan) referansları kaldırdım ve aramaların izini aldım, ancak sayfayı güncellemiyor.
Mmm, eğer yaparsam alert(applet.GetLocaleInformation());bilgiyi aldım, bu yüzden bir jQuery sorunu olabilir.


@PhiLho: çalışıyor, ancak yine de ayırıcıyı Windows'tan doğru okumuyor. Aşağıdakileri gördüğünde: Locale for русский (Россия): country=Россия (RU / RUS), lang=русский (ru / rus), variant= ()Windows ayarlarında bir nokta ile geçersiz kılmama rağmen virgül kullanıyor.
Quassnoi

Lütfen, bu sistemin sınırlamaları hakkındaki ilk mesajımı okuyun. Bir Web tarayıcısından daha iyisini yapabilir miyiz bilmiyorum, belki bazı yerel kodlar kullanmak dışında.
PhiLho

1

Bu "GUI Uygulaması" altında çalışan yereli bilsek bile, yine de anlamaya zorunda o anki yerel elde ettiğini ve nasıl o ondalık ayırıcı belirlemektir.

Mac'te nasıl yapıldığını bilmiyorum, ancak Windows uygulamalarının kullanıcının Kontrol Paneli aracılığıyla ayarladığı tercihleri ​​sorgulaması gerekiyor. Bu gizemli uygulamanın bu ayarları görmezden gelmesi ve bunun yerine kendi dahili kurulumunu kullanması oldukça olasıdır.

Ya da belki mevcut yerel ayarı alıyorlar ve söylenmek yerine geri kalanını çıkarıyorlar.

O zaman bile, İngilizce olarak sayılar , grupları ayıran virgülle 3 basamaklı gruplar halinde verilir. yani:

5,197,359,078

Numara, telefon numarası içeren bir tam sayı olmadığı sürece :

519-735-9078

Elbette sayı, hesap numarasını içeren bir tam sayı olmadığı sürece :

5197359078

Bu durumda, sabit kodlanmış geçersiz kılınmış mantığa geri dönersiniz.

Düzenleme: Para biriminin kendi biçimlendirme kuralları olduğundan kaldırılan para birimi örneği.


0

Diğer yanıtlara benzer, ancak sabit olarak sıkıştırılmıştır :

const decimal=.1.toLocaleString().substr(1,1);      //returns "." in Canada

Ayrıca binlik ayırıcıyı almak için :

const thousands=1234..toLocaleString().substr(1,1);   //returns "," in Canada

Sadece kodu JS'nizin üstüne yerleştirin ve ardından sembolü döndürmek için gerektiği gibi çağırın.


Örneğin (yaşadığım yer), virgül kaldırmak için "1,234,567":

console.log( "1,234,567".replaceAll(thousands,"") ); //prints "1234567" to console.  

-1

"Bunu sunucu tarafında (tercihen istatistik toplayabilmem için) veya istemci tarafında yapmanın bir yolu var mı?"

Hayır yapamazsın. Bu GUI, bazı kullanıcıya veya makineye özel ayarlara bakıyor. İlk olarak, muhtemelen bu kullanıcı arayüzünün hangi ayarlara baktığını bilmiyorsunuz. İkinci olarak, bir web uygulamasıyla bu ayarları kontrol edemezsiniz (istemci tarafı -> Javacsript).


@RWC: GUI uygulamasının nereye baktığını biliyorum: Windows bölgesel ayarları.
Quassnoi

-4

Başka bir olası çözüm: Kullanıcının konumunu belirlemek ve bu bilgilere dayanarak karar vermek için GeoIP gibi bir şey (PHP'de örnek) kullanabilirsiniz.


1
Yine de kullanıcının bunu geçersiz kılmasına izin vermek gerekli olacaktır. Bir arkadaşım İngiltere'nin güneyinde çalışıyor; İspanya'daki bir proxy sunucusu aracılığıyla tüm İnternet erişimini yönlendirmek için çalıştığı şirket, bu nedenle GeoIP onu her zaman gerçek konumundan yüzlerce mil uzakta olarak gösterir.
NickFitz
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.