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


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.