使用浏览器时,如何知道操作系统使用哪个小数点分隔符?


82

我正在开发一个Web应用程序。

我需要正确显示一些十进制数据,以便可以将其复制并粘贴到GUI不受我控制的某个应用程序中。

GUI应用程序是对语言环境敏感的,并且仅接受系统中设置的正确的十进制分隔符。

我可以从中猜测小数点分隔符,Accept-Language并且在95%的情况下猜测是正确的,但有时会失败。

有什么方法可以在服务器端(最好是我可以收集统计信息)或在客户端吗?

更新:

任务的重点是自动执行。

实际上,此webapp是传统GUI的一种在线界面,有助于正确填写表格。

使用它的用户种类大多不知道十进制分隔符是什么。

Accept-Language解决方案已实现并可以运行,但我想对其进行改进。

更新2:

我需要检索一个非常具体的设置:中的小数点分隔符Control Panel / Regional and Language Options / Regional Options / Customize

我处理四种操作系统:

  1. 俄语Windows,逗号为DS(80%)。
  2. 英文Windows以句点作为DS(15%)。
  3. 带有DS期间的俄语Windows,可以使英文应用程序的书写不佳(4%)。
  4. 英文Windows,以逗号作为DS,以使书写较差的俄语应用程序正常工作(1%)。

所有100%的客户都在俄罗斯,而旧版应用程序处理的是俄罗斯政府发行的表格,因此,要求一个国家将获得100%的俄罗斯联邦,而GeoIP将获得80%的俄罗斯联邦和20%的其他(不正确)答案。

Answers:


127

这是一个简单的JavaScript函数,它将返回此信息。在Firefox,IE6和IE7中进行了测试。在控制面板/区域和语言选项/区域选项/自定义下对设置进行的每次更改之间,我必须关闭并重新启动浏览器。但是,它不仅提取了逗号和句点,而且还提取了一些奇怪的定制事物,例如字母“ a”。

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

这有帮助吗?


3
这对我在Firefox和IE8中有效,但对Google Chrome无效。我没有Opera。
马修·塔尔伯特

@Matthew-在Chrome中为我工作。@Quassnoi-我不明白最后一条评论的意思。如果他说该功能不起作用,那么该人所知道的有什么关系?
Matchu

小心!在Chrome中,只有直接在数字上调用toLocaleString才能正常工作。在我的系统上:[1.1,1.2] .toLocaleString()->“ 1.1,1.2” | (1.1).toLocaleString()->“ 1,1”
TarnayKálmán2013年

1
在使用多个字符的语言环境DecimalSeparator(例如,,)上,功能失败。WindowsLOCALE_SDECIMAL允许小数点分隔符最多包含三个字符。(这就是为什么它在我的PC上失败的原因)。Accept-Language在这种情况下,最好使用浏览器的。哪个仍然不能说明指定自己的能力,DecimalSeparator例如\o/
Ian Boyd

4
@IanBoyd在语言环境上是正确的,它使用一个以上的字符作为小数点分隔符的字符串,但是n = /^1(.+)1$/.exec(n.toLocaleString())[1]可以做到这一点,并且比使用Accept-Language标头更容易。
ygormutti 2014年

14

使用可以检索当前或给定语言环境的分隔符Intl.NumberFormat#formatToParts

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

它仅适用于支持Intl API的浏览器。否则,它需要一个Intl polyfill

例子:

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

奖金:

我们可以扩展它以检索给定语言环境的小数分隔符:

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

例子:

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

当前,这是获取此类信息的最合适方法。Intl甚至在IE 11中也支持BTW :caniuse.com/#feat=internationalization
Konstantin Smolyanin

3
由于不支持formatToParts,因此在IE 11中将无法使用。
Gajendra Kumar

11

询问用户,不要猜测。在您的Web应用程序中为其设置。

编辑添加:

我认为猜测95%的时间可以正常工作的默认设置是可以的。我的意思是,用户仍然应该能够覆盖软件所做的任何猜测。当一个软件试图变得太聪明并且不允许被纠正时,我已经感到沮丧太多了。


有趣,这是我的第一个主意,但我不知所措,想知道如何自动执行它…
PhiLho

1
坏主意,除了可能作为备份。大多数用户对尴尬的文化不敏感,甚至在没有解释的情况下甚至都不了解“小数点分隔符”是什么(然后会因为被迫设置“每个人都知道”而感到生气)。
Michael Borgwardt

2
@Iaalto:这将引起一个几乎与“最小化数据库大小(推荐)或最大化搜索功能?”之类的问题。
Quassnoi

好吧,这应该不太难。只需让用户选择国家,然后相应地选择干燥分隔符和其他选项即可。

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
后退到“。” 在某些晦涩的浏览器的情况下...其他方式几乎是同一件事...
Dr.Oblak 2015年

7

为什么不

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


2
也许有些奇怪的语言环境可能会跳过前导零?为了确保,我宁愿在那里一个。
JuanguiJordán17年

5

我可以从Accept-Language猜测小数点分隔符,并且在95%的情况下猜测是正确的,但有时会失败。

这是IMO的最佳做法。为了处理故障,请在显示区域旁边添加一个链接以手动设置它。


怎么做?我了解您可以使用像github.com/dansingerman/jQuery-Browser-Language
Lime

@William:OP谈论的Acccept-Language是浏览器发送的HTTP标头,它告诉服务器用户喜欢哪种语言,通常是浏览器安装或OS的语言。
Michael Borgwardt

4

使用其他人的答案,我编译了以下十进制和千分隔符实用程序函数:

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

请享用!


是的,我将此方法用作不支持的浏览器formatToParts(Safari和IE)的polyfill 。
Marko Bonaci

1
一些语言环境不使用10000以下的千位分隔符。例如(1000).toLocaleString("es-PE") # "1000"
Madacol

1

我认为您必须依靠JavaScript来提供语言环境设置。
但是显然JS无法直接访问此信息。
我看到Dojo Toolkit依靠外部数据库来查找语言环境信息,尽管例如,它可能不会考虑设置更改。
我看到的另一个解决方法是有一个小型静默Java小程序,该小程序可以从系统中查询此信息,还可以使用JavaScript从Java中获取信息。
如果您不知道该怎么做,我可以提供更多信息(当然,如果您想走这种复杂的路线)。

[编辑]因此,我更新了对Java本地化支持的知识...
与我最初的想法不同,您不会像直接使用行分隔符或路径分隔符那样直接拥有小数分隔符或千位分隔符:提供API以格式化您提供的数字或日期。
不知何故,这是有道理的:在欧洲,您通常将货币符号放在数字之后,某些国家(印度?)使用更复杂的规则来分隔数字,依此类推。

另一件事:Java可以正确地从系统中找到当前语言环境,但不能从那里获取信息(可能是由于上述原因)。相反,它使用自己的规则集。因此,如果您在西班牙语语言环境中用感叹号替换了小数点分隔符,则Java将不会使用它(但是您的应用程序可能无论如何都不会使用它)。

因此,我正在编写一个将服务(函数)暴露给JavaScript的applet,从而允许将数字格式化为当前语言环境。您可以这样使用它,即使用JavaScript在浏览器中格式化数字。或者,您可以只提供一些样本号,然后从那里提取符号,在本地使用它们或将其反馈给服务器。

我完成并测试了我的applet,然后将其发布到那里。


@PhiLho:很高兴知道。这个Web应用程序是一种帮助系统,因此只要是可在IE,Firefox和Opera上运行的丑陋骇客就可以做到,并且不需要优雅。
Quassnoi

1

好的,我有一些要展示的东西,而不是成品,这是概念上的证明,但是由于缺乏精确的规格,我将其保留为这种方式(否则我将对其进行过度设计)。我会在一条单独的消息中发布,因为它会有点长。我借此机会尝试了更多的jQuery ...

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

使用上述小程序的HTML页面示例: 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上的Firefox 3.0,IE 6,Safari 3.1和Opera 9.50上进行了测试。它与前两个没有问题,在Safari上,在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)

但它仍然有效。

我无法在Opera中使用它:小程序正确加载,因为我可以在Java控制台中看到init()调用的踪迹,当JavaScript调用Java函数时,我没有任何错误(除非我添加并调用方法)奇怪的是获取了JSObject参数),但是未调用Java函数(我添加了调用跟踪)。
我相信Liveconnect可以在Opera中工作,但是我还不知道如何工作。我会研究更多。
[更新]我删除了对不存在的jar文件的引用(该文件不会停止其他浏览器),并且获得了调用的痕迹,但是它没有更新页面。
嗯,如果我alert(applet.GetLocaleInformation());知道了信息,那么可能是jQuery问题。


@PhiLho:它可以工作,但是仍然无法从Windows正确读取分隔符。当看到以下内容时:Locale for русский (Россия): country=Россия (RU / RUS), lang=русский (ru / rus), variant= ()尽管我在Windows设置中用句号覆盖了它,但它仍使用逗号。
Quassnoi

请阅读我对有关此系统限制的第一条消息的更新。我不知道是否可以通过Web浏览器做得更好,除非使用某些本机代码。
PhiLho

1

即使你知道哪种语言环境这“GUI应用程序”下运行,你还是要弄清楚如何是获得当前的语言环境,以及如何是确定小数点分隔符。

我不知道如何在Mac上完成此操作,但在Windows上应该通过控制面板询问用户的首选项设置。这个神秘的应用很可能会忽略这些设置,而是使用自己的内部设置。

或者,也许他们是采用当前的语言环境,然后推断其余语言,而不是被告知。

即使这样,在英语中,数字是在3位组给定的,用逗号分隔的组。即:

5,197,359,078

除非数字是包含电话号码的整数:

519-735-9078

当然,除非该数字是包含帐号的整数:

5197359078

在这种情况下,您将返回硬编码的覆盖逻辑。

编辑:删除了货币示例,因为货币具有自己的格式规则。


0

与其他答案类似,但压缩为常量

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

另外,要获取千位分隔符

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

只需将代码放在JS的顶部,然后根据需要调用即可返回符号。


例如(我住的地方),从中删除逗号"1,234,567"

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

-1

“有什么方法可以在服务器端(最好是我可以收集统计信息)或在客户端吗?”

不,你不能。该GUI正在查看某些用户或计算机特定的设置。首先,您可能不知道此UI正在查看什么设置。其次,使用Web应用程序,您可能将无法检查这些设置(客户端-> Javacsript)。


@RWC:我知道GUI应用程序的目标位置:Windows区域设置。
Quassnoi

-4

另一种可能的解决方案:您可以使用GeoIP之类的东西(PHP中的示例)来确定用户的位置并根据这些信息进行决策。


1
但是,有必要允许用户覆盖它。我的一个朋友在英格兰南部工作。他工作的公司通过西班牙的代理服务器路由所有Internet访问,因此GeoIP始终显示他与实际位置相距数百英里。
NickFitz
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.