브라우저에서 운영 체제가 사용하는 소수 구분 기호를 어떻게 알 수 있습니까?


82

웹 애플리케이션을 개발 중입니다.

내가 제어 할 수 GUI없는 특정 응용 프로그램에 복사하여 붙여 넣을 수 있도록 소수 데이터를 올바르게 표시해야합니다 .

GUI 응용 프로그램은 로케일에 민감하며 시스템에 설정된 올바른 소수점 구분자 만 허용합니다.

소수점 구분 기호를 Accept-Language추측 할 수 있고 추측은 95 %의 경우 정확하지만 때로는 실패합니다.

서버 측 (가급적이면 통계를 수집 할 수 있도록) 또는 클라이언트 측에서 수행 할 수있는 방법이 있습니까?

최신 정보:

작업의 요점은 자동으로 수행하는 것입니다.

실제로이 웹앱은 양식을 올바르게 채우는 데 도움이되는 레거시 GUI에 대한 일종의 온라인 인터페이스입니다.

그것을 사용하는 종류의 사용자는 대부분 소수점 구분 기호가 무엇인지 알지 못합니다.

Accept-Language솔루션 구현 및 작동하지만, 나는 그것을 개선하고자한다.

업데이트 2 :

매우 구체적인 설정을 검색해야합니다 : Control Panel / Regional and Language Options / Regional Options / Customize.

저는 4 가지 종류의 운영 체제를 다룹니다.

  1. DS로 쉼표가있는 러시아어 Windows (80 %).
  2. 마침표가 DS (15 %) 인 영어 Windows.
  3. 잘못 작성된 영어 응용 프로그램이 작동하도록하는 DS로 기간이있는 러시아어 Windows (4 %).
  4. 잘못 작성된 러시아어 응용 프로그램이 작동하도록 쉼표를 DS로 사용하는 영어 Windows (1 %).

모든 고객은 러시아에 있으며 레거시 애플리케이션은 러시아 정부에서 발급 한 양식을 처리하므로 국가를 요청하면 러시아 연방의 100 %를 산출하고 GeoIP는 러시아 연방의 80 %, 기타의 20 %를 산출합니다 (잘못된). 대답.

답변:


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 Talbert

@Matthew-Chrome에서 저를 위해 일했습니다. @Quassnoi-마지막 댓글의 의미를 이해하지 못합니다. 그가 그 기능이 작동하지 않는다고 말한다면, 그 사람이 아는 것이 무엇이 중요합니까?
Matchu

조심해! Chrome에서 toLocaleString은 숫자에서 직접 호출되는 경우에만 제대로 작동합니다. 내 시스템 : [1.1,1.2] .toLocaleString ()-> "1.1,1.2"| (1.1) .toLocaleString ()-> "1,1"
Tarnay Kálmán 2013-08-23

1
둘 이상의 문자를 사용하는 로케일에서 함수가 실패합니다 DecimalSeparator(예 :) ,,. Windows LOCALE_SDECIMAL에서는 소수점 구분 기호에 최대 3 개의 문자를 포함 할 수 있습니다. (내 PC에서 실패하는 이유). Accept-Language이 경우 브라우저 를 사용하는 것이 좋습니다 . 여전히 자신 지정할 수있는 기능을 고려하지 않는 DecimalSeparator\o/
이안 보이드

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')
" "

현재 이것은 그러한 정보를 얻는 가장 적절한 방법입니다. BTW Intl, 심지어 IE 11에서 지원됩니다 caniuse.com/#feat=internationalization
콘스탄틴 Smolyanin

3
formatToParts가 지원되지 않으므로 IE 11에서는 작동하지 않습니다.
Gajendra Kumar

11

사용자에게 물어보고 추측하지 마십시오. 웹 애플리케이션에 설정이 있습니다.

추가하기 위해 편집 :

95 %의 경우 정상적으로 작동 하는 기본 설정 을 추측하는 것이 좋습니다. 내가 의미하는 것은 사용자가 소프트웨어가 추측 한 모든 것을 무시할 수 있어야한다는 것입니다. 나는 소프트웨어가 너무 똑똑해 지려고 시도하고 수정을 허용하지 않을 때 이미 너무 많이 좌절했습니다.


재미는, 내 첫번째 생각했다, 그러나 나는 배 밖으로 ... 자동으로 작업을 수행하는 방법을 찾고 갔다
PhiLho

1
백업용으로 만 제외하고는 나쁜 생각입니다. 대부분의 사용자는 난처한 문화에 민감하지 않으며 설명없이 "소수 구분 기호"가 무엇인지 이해조차하지 못합니다.
Michael Borgwardt

2
@Iaalto : "데이터베이스 크기 최소화 (권장) 또는 검색 기능 최대화"와 같은 질문이 될 것입니다.
Quassnoi

글쎄, 그것은 너무 어렵지 않을 것입니다. 사용자가 국가를 선택하도록 한 다음 그에 따라 desicmal 구분 기호 및 기타 옵션을 선택하십시오.

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

7

왜 안돼

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


2
이상한 로케일이 선행 0을 건너 뛸 수 있습니까? 차라리 거기에 하나를 갖고 싶습니다.
Juangui Jordán

5

Accept-Language의 소수 구분 기호를 추측 할 수 있으며 추측은 95 %의 경우 정확하지만 때로는 실패합니다.

이것은 IMO가 최선의 조치입니다. 오류를 처리하려면 표시 영역 옆에 수동으로 설정하는 링크를 추가하십시오.


어떻게할까요? 나는이 같은 브라우저 라이브러리를 사용할 수 있습니다 이해 github.com/dansingerman/jQuery-Browser-Language
라임

@William : OP가 말하는 Acccept-Language는 사용자가 선호하는 언어 (일반적으로 브라우저 설치 또는 OS의 언어)를 서버에 알려주는 브라우저에서 보낸 HTTP 헤더입니다.
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) 의 폴리 필로 사용했습니다 .
Marko Bonaci

1
일부 로케일은 10000 미만의 천 단위 구분 기호를 사용하지 않습니다. 예 :(1000).toLocaleString("es-PE") # "1000"
Madacol

1

로케일 설정을 제공하려면 JavaScript에 의존해야한다고 생각합니다.
그러나 분명히 JS는이 정보에 직접 액세스 할 수 없습니다.
내가 볼 도조 툴킷 은 예를 들어, 계정 설정 변경에 걸리지 않을 수도 있지만, 로케일 정보를 찾기 위해 외부 데이터베이스에 의존합니다.
내가 보는 또 다른 해결 방법은 시스템에서이 정보를 쿼리하는 작은 자동 Java 애플릿과 Java에서 가져 오는 JavaScript입니다.
방법을 모르는 경우 더 많은 정보를 제공 할 수 있습니다 (물론이 복잡한 경로를 가고 싶다면).

[편집] 그래서 Java에서 현지화 지원에 대한 지식을 업데이트했습니다.
원래 생각했던 것과는 달리, 줄 구분 기호 나 경로 구분 기호를 사용하는 것처럼 직접 소수점 구분 기호 나 천 구분 문자를 직접 사용하지 않습니다. 대신 Java 제공하는 숫자 또는 날짜의 형식을 지정하는 API를 제공합니다.
어떻게 든 의미가 있습니다. 유럽에서는 숫자 뒤에 통화 기호를 넣는 경우가 많고 일부 국가 (인도?)에는 숫자를 구분하는 더 복잡한 규칙이 있습니다.

또 다른 한 가지 : Java는 시스템에서 현재 로케일을 올바르게 찾지 만 거기에서 정보를 가져 오지 않습니다 (아마 위의 이유로). 대신 자체 규칙 집합을 사용합니다. 따라서 소수점 구분 기호를 느낌표로 대체 한 스페인어 로케일이있는 경우 Java는이를 사용하지 않을 것입니다 (어쨌든 응용 프로그램이 아닐 수도 있습니다 ...).

그래서 저는 서비스 (기능)를 JavaScript에 노출하는 애플릿을 작성하여 숫자를 현재 로케일로 형식화 할 수 있습니다. 브라우저에서 숫자 형식을 지정하기 위해 JavaScript를 사용하여 그대로 사용할 수 있습니다. 또는 샘플 번호를 제공하고 거기에서 기호를 추출하여 로컬에서 사용하거나 서버로 다시 공급할 수 있습니다.

애플릿을 완료하고 테스트 한 후 곧 게시합니다.


@PhiLho : 알고 있으면 좋을 것입니다. 이 웹앱은 일종의 도움말 시스템이므로 추악한 해킹이 가능하므로 IE, Firefox 및 Opera에서 실행되는 한 우아 할 필요가 없습니다.
Quassnoi

1

좋아, 나는 완성품보다 개념 증명에 더 많은 것을 보여줄 것이 있지만, 정확한 사양이 없기 때문에 나는 이것을 그대로 두거나 오버 엔지니어링 할 것이다. 조금 길기 때문에 별도의 메시지로 게시합니다. 나는 조금 더 jQuery를 시도 할 기회를 가졌다.

자바 코드 : 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

이 시스템의 제한 사항에 대한 나의 첫 번째 메시지 업데이트를 읽으십시오. 아마도 네이티브 코드를 사용하는 것 외에는 웹 브라우저에서 더 잘할 수 있는지 모르겠습니다.
PhiLho 2009

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가 어떤 설정을보고 있는지 모를 것입니다. 둘째, 웹 응용 프로그램을 사용하면 이러한 설정 (clientside-> Javacsript)을 확인할 수 없을 것입니다.


@RWC : GUI 앱이 Windows 지역 설정을 찾는 위치를 알고 있습니다.
Quassnoi

-4

또 다른 가능한 해결책 : GeoIP (PHP의 예) 와 같은 것을 사용 하여 사용자의 위치를 ​​확인하고 이러한 정보를 기반으로 결정할 수 있습니다.


1
하지만 사용자가이를 무시하도록 허용해야합니다. 내 친구는 잉글랜드 남부에서 일합니다. 그는 스페인의 프록시 서버를 통해 모든 인터넷 액세스 경로를 위해 일하는 회사이므로 GeoIP는 항상 그를 실제 위치에서 수백 마일 떨어진 것으로 보여줍니다.
NickFitz
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.