Với trình duyệt, làm cách nào để biết hệ điều hành sử dụng dấu phân tách thập phân nào?


82

Tôi đang phát triển một ứng dụng web.

Tôi cần hiển thị một số dữ liệu thập phân một cách chính xác để nó có thể được sao chép và dán vào một GUIứng dụng nhất định không nằm trong tầm kiểm soát của tôi.

Ứng dụng GUI nhạy cảm với ngôn ngữ và nó chỉ chấp nhận dấu phân tách thập phân chính xác được đặt trong hệ thống.

Tôi có thể đoán dấu phân tách thập phân từ Accept-Languagevà dự đoán sẽ đúng trong 95% trường hợp, nhưng đôi khi nó không thành công.

Có cách nào để thực hiện việc đó ở phía máy chủ (tốt nhất là để tôi có thể thu thập số liệu thống kê) hoặc phía máy khách không?

Cập nhật:

Toàn bộ điểm của nhiệm vụ được thực hiện tự động.

Trên thực tế, ứng dụng web này là một loại giao diện trực tuyến với GUI cũ giúp điền chính xác các biểu mẫu.

Loại người dùng sử dụng nó hầu hết không biết dấu phân tách thập phân là gì.

Các Accept-Languagegiải pháp được thực hiện và các công trình, nhưng tôi muốn cải thiện nó.

Cập nhật2:

Tôi cần truy xuất một cài đặt rất cụ thể: dấu phân tách thập phân được đặt trong Control Panel / Regional and Language Options / Regional Options / Customize.

Tôi xử lý bốn loại hệ điều hành:

  1. Windows tiếng Nga với dấu phẩy là DS (80%).
  2. Windows tiếng Anh với khoảng thời gian là DS (15%).
  3. Windows tiếng Nga với thời kỳ là DS giúp các ứng dụng tiếng Anh viết kém hoạt động (4%).
  4. Windows tiếng Anh với dấu phẩy làm DS để làm cho các ứng dụng tiếng Nga viết kém hoạt động (1%).

Tất cả 100% khách hàng đều ở Nga và ứng dụng kế thừa xử lý các biểu mẫu do chính phủ Nga ban hành, do đó, yêu cầu một quốc gia sẽ mang lại 100% Liên bang Nga và GeoIP sẽ mang lại 80% Liên bang Nga và 20% khác (không chính xác) các câu trả lời.

Câu trả lời:


127

Đây là một hàm JavaScript đơn giản sẽ trả về thông tin này. Đã thử nghiệm trên Firefox, IE6 và IE7. Tôi đã phải đóng và khởi động lại trình duyệt của mình giữa mỗi lần thay đổi cài đặt trong Bảng điều khiển / Tùy chọn khu vực và ngôn ngữ / Tùy chọn khu vực / Tùy chỉnh. Tuy nhiên, nó không chỉ chọn ra dấu phẩy và dấu chấm, mà còn cả những thứ tùy chỉnh kỳ quặc, chẳng hạn như chữ "a".

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

Không giúp đỡ à?


3
Điều này đã làm việc cho tôi trong Firefox và IE8, nhưng không hiệu quả với Google Chrome. Tôi không có Opera.
Matthew Talbert 20-08-09

@Matthew - đã làm việc cho tôi trong Chrome. @Quassnoi - Tôi không hiểu nhận xét cuối cùng đó có ý nghĩa gì. Nếu anh ta nói rằng chức năng không hoạt động, thì điều đó có quan trọng gì đối với những gì người đó biết?
Matchu

Coi chừng! Trong Chrome, toLocaleString chỉ hoạt động bình thường nếu được gọi trực tiếp trên một Số. Trên hệ thống của tôi: [1.1,1.2] .toLocaleString () -> "1.1,1.2" | (1.1) .toLocaleString () -> "1,1"
Tarnay Kálmán

1
Hàm không thành công trên ngôn ngữ sử dụng nhiều hơn một ký tự cho chúng DecimalSeparator(ví dụ ,,). Windows LOCALE_SDECIMALcho phép một dấu phân tách thập phân chứa tối đa ba ký tự. (Đó là lý do tại sao nó không thành công trên PC của tôi). Tốt hơn nên sử dụng Accept-Languagetrình duyệt trong trường hợp đó. Mà vẫn không chiếm khả năng xác định riêng của họ DecimalSeparatorví dụ\o/
Ian Boyd

4
@IanBoyd nói đúng về các ngôn ngữ có chuỗi nhiều hơn một ký tự làm dấu phân tách thập phân, nhưng n = /^1(.+)1$/.exec(n.toLocaleString())[1]sẽ làm được điều đó và dễ dàng hơn so với việc sử dụng Accept-Languagetiêu đề.
ygormutti

14

Có thể truy xuất dấu phân cách cho hiện tại hoặc một ngôn ngữ nhất định bằng cách sử dụng Intl.NumberFormat#formatToParts.

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

Nó chỉ hoạt động đối với các trình duyệt hỗ trợ Intl API . Nếu không, nó yêu cầu một polyfill Intl

Ví dụ:

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

Tặng kem:

Chúng tôi có thể mở rộng nó để truy xuất dấu phân tách thập phân hoặc nhóm của một ngôn ngữ nhất định:

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

Ví dụ:

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

Hiện tại đây là cách thích hợp nhất để có được thông tin như vậy. BTW Intlđược hỗ trợ ngay cả trong IE 11: caniuse.com/#feat=internationalization
Konstantin Smolyanin

3
Tính năng này sẽ không hoạt động trong IE 11 vì formatToParts không được hỗ trợ.
Gajendra Kumar

11

Hãy hỏi người dùng, đừng đoán. Có cài đặt cho nó trong ứng dụng web của bạn.

Đã chỉnh sửa để thêm:

Tôi nghĩ rằng có thể đoán cài đặt mặc định hoạt động tốt, chẳng hạn như 95% thời gian. Ý tôi muốn nói là người dùng vẫn có thể ghi đè lên bất cứ điều gì phần mềm đoán được. Tôi đã quá nhiều lần thất vọng khi một phần mềm cố gắng trở nên quá thông minh và không cho phép sửa chữa.


Thật buồn cười, đó là ý tưởng đầu tiên của tôi, nhưng tôi đã tìm hiểu quá kỹ về cách thực hiện nó tự động ...
PhiLho

1
Ý tưởng tồi, ngoại trừ có thể là một dự phòng. Hầu hết người dùng không nhạy cảm với văn hóa và thậm chí sẽ không hiểu "dấu phân tách thập phân" là gì nếu không có lời giải thích (và sau đó sẽ rất tức giận khi bị buộc phải đặt thứ gì đó mà "mọi người đều biết").
Michael Borgwardt

2
@Iaalto: điều này sẽ tạo ra một câu hỏi gần như tuyệt vời như "Giảm thiểu kích thước cơ sở dữ liệu (được khuyến nghị) hoặc Tối đa hóa khả năng tìm kiếm?"
Quassnoi

Chà, điều đó không quá khó. Chỉ cần cho phép người dùng chọn quốc gia và sau đó chọn thiết bị tách khô và các tùy chọn khác cho phù hợp.

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
dự phòng cho "." trong trường hợp của một số trình duyệt tối nghĩa ... cách khác, nó là khá nhiều điều tương tự ...
Dr.Oblak


5

Tôi có thể đoán dấu phân tách thập phân từ Chấp nhận-Ngôn ngữ và đoán sẽ đúng trong 95% trường hợp, nhưng đôi khi nó không thành công.

Đây là IMO hành động tốt nhất. Để xử lý các lỗi, hãy thêm một liên kết để đặt nó theo cách thủ công bên cạnh vùng hiển thị.


Làm thế nào điều này sẽ được thực hiện? Tôi hiểu bạn có thể sử dụng một thư viện trình duyệt như thế này github.com/dansingerman/jQuery-Browser-Language
Lime

@William: Ngôn ngữ chấp nhận mà OP nói đến là một tiêu đề HTTP được gửi bởi trình duyệt để cho máy chủ biết người dùng thích ngôn ngữ nào, thường là ngôn ngữ cài đặt trình duyệt hoặc hệ điều hành.
Michael Borgwardt

4

Sử dụng câu trả lời của người khác, tôi đã biên soạn các hàm tiện ích dấu phân cách thập phân và nghìn sau:

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

Thưởng thức!


Có, tôi đã sử dụng phương pháp này như một polyfill cho các trình duyệt không hỗ trợ formatToParts(Safari và IE).
Marko Bonaci

1
Một số ngôn ngữ không sử dụng dấu phân tách nghìn dưới 10000. Ví dụ:(1000).toLocaleString("es-PE") # "1000"
Madacol

1

Tôi nghĩ bạn phải dựa vào JavaScript để cung cấp cho bạn cài đặt ngôn ngữ.
Nhưng dường như JS không có quyền truy cập trực tiếp vào thông tin này.
Tôi thấy Bộ công cụ Dojo dựa vào cơ sở dữ liệu bên ngoài để tìm thông tin ngôn ngữ, mặc dù nó có thể không tính đến các thay đổi cài đặt tài khoản, chẳng hạn.
Một giải pháp khác mà tôi thấy là có một ứng dụng Java nhỏ, im lặng để truy vấn thông tin này từ hệ thống và JavaScript để đưa nó ra khỏi Java.
Tôi có thể cung cấp thêm thông tin nếu bạn không biết cách thực hiện (tất nhiên là nếu bạn muốn đi theo con đường phức tạp này).

[EDIT] Vì vậy, tôi đã cập nhật kiến ​​thức của mình về hỗ trợ bản địa hóa trong Java ...
Không giống như những gì tôi nghĩ ban đầu, bạn sẽ không có trực tiếp dấu phân tách thập phân hoặc nghìn ký tự phân cách, giống như bạn sẽ làm với dấu phân cách dòng hoặc dấu phân cách đường dẫn: thay vào đó là Java cung cấp các API để định dạng số hoặc ngày bạn cung cấp.
Bằng cách nào đó, nó có ý nghĩa: ở Châu Âu bạn thường đặt biểu tượng tiền tệ sau số, một số quốc gia (Ấn Độ?) Có quy tắc phức tạp hơn để phân tách các chữ số, v.v.

Một điều khác: Java tìm chính xác ngôn ngữ hiện tại từ hệ thống, nhưng không lấy thông tin từ đó (có lẽ vì những lý do trên). Thay vào đó, nó sử dụng bộ quy tắc riêng. Vì vậy, nếu bạn có ngôn ngữ Tây Ban Nha nơi bạn thay thế dấu phân tách thập phân bằng dấu chấm than, Java sẽ không sử dụng nó (nhưng có lẽ ứng dụng của bạn cũng không ...).

Vì vậy, tôi đang viết một applet trình bày một dịch vụ (các chức năng) sang JavaScript, cho phép định dạng các số theo ngôn ngữ hiện tại. Bạn có thể sử dụng nó như vậy, sử dụng JavaScript để định dạng số trên trình duyệt. Hoặc bạn có thể cung cấp cho nó một số mẫu và trích xuất các ký hiệu từ đó, sử dụng chúng cục bộ hoặc đưa chúng trở lại máy chủ.

Tôi hoàn thành và kiểm tra applet của mình và đăng nó lên đó sớm.


@PhiLho: rất vui được biết. Ứng dụng web này là một loại hệ thống trợ giúp, vì vậy bất kỳ vụ hack xấu xí nào cũng sẽ làm được, nó không cần phải trang nhã miễn là nó chạy trên IE, Firefox và Opera.
Quassnoi

1

Được rồi, tôi có một cái gì đó để hiển thị, một bằng chứng về khái niệm hơn là một sản phẩm hoàn chỉnh, nhưng vì thiếu thông số kỹ thuật chính xác, tôi để nó theo cách này (hoặc tôi sẽ thiết kế quá mức). Tôi đăng trong một tin nhắn riêng biệt vì nó sẽ hơi dài. Tôi đã nhân cơ hội để thử thêm một chút jQuery ...

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

Ví dụ về trang HTML sử dụng applet ở trên: 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>

Đã thử nghiệm trên Firefox 3.0, IE 6, Safari 3.1 và Opera 9.50, trên Windows XP Pro SP3. Nó hoạt động mà không có vấn đề với hai đầu tiên, trên Safari, tôi gặp lỗi lạ sau khi gọi 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)

nhưng nó vẫn hoạt động.

Tôi không thể làm cho nó hoạt động với Opera: applet tải chính xác, vì tôi có thể thấy dấu vết của lệnh gọi init () trong bảng điều khiển Java, tôi không gặp lỗi khi JavaScript gọi các hàm Java (ngoại trừ nếu tôi thêm và gọi một phương thức nhận được một tham số JSObject, thật kỳ lạ), nhưng các hàm Java không được gọi (tôi đã thêm dấu vết của các lệnh gọi).
Tôi tin rằng Liveconnect hoạt động trong Opera, nhưng tôi chưa biết cách thực hiện. Tôi sẽ nghiên cứu thêm một chút.
[Cập nhật] Tôi đã xóa các tham chiếu đến tệp jar không tồn tại (điều này không ngăn các trình duyệt khác) và tôi nhận được dấu vết của các lệnh gọi, nhưng nó không cập nhật trang.
Mmm, nếu tôi làmalert(applet.GetLocaleInformation()); có thông tin, vì vậy nó có thể là một vấn đề jQuery.


@PhiLho: nó hoạt động, nhưng vẫn không đọc chính xác dấu phân tách khỏi Windows. Khi nó nhìn thấy những thứ sau: Locale for русский (Россия): country=Россия (RU / RUS), lang=русский (ru / rus), variant= ()nó sử dụng dấu phẩy mặc dù thực tế là tôi đã ghi đè nó bằng một dấu chấm trong cài đặt Windows.
Quassnoi 07-07-09

Vui lòng đọc cập nhật thông báo đầu tiên của tôi về những hạn chế của hệ thống này. Tôi không biết liệu chúng ta có thể làm tốt hơn từ trình duyệt Web hay không, ngoại trừ việc sử dụng một số mã gốc.
PhiLho 07-07-09

1

Ngay cả khi bạn biết "Ứng dụng GUI" này đang chạy theo ngôn ngữ nào , bạn vẫn phải tìm ra cách nhận được ngôn ngữ hiện tại và cách xác định dấu phân cách thập phân.

Tôi không biết nó được thực hiện như thế nào trên máy Mac, nhưng trên các ứng dụng Windows được cho là sẽ thẩm vấn các tùy chọn của người dùng được đặt qua Bảng điều khiển. Rất có thể ứng dụng bí ẩn này đang bỏ qua các cài đặt đó và thay vào đó sử dụng thiết lập nội bộ của riêng chúng.

Hoặc có lẽ họ đang sử dụng ngôn ngữ hiện tại và suy ra phần còn lại, thay vì được nói.

Ngay cả khi đó, trong tiếng Anh, các số được đưa ra trong các nhóm có 3 chữ số, với dấu phẩy ngăn cách các nhóm. I E:

5,197,359,078

Trừ khi số là số nguyên có chứa số điện thoại :

519-735-9078

Tất nhiên trừ khi số đó là số nguyên có chứa số tài khoản :

5197359078

Trong trường hợp đó, bạn quay lại logic bị ghi đè được mã hóa cứng.

Chỉnh sửa: Ví dụ về đơn vị tiền tệ đã bị xóa, vì đơn vị tiền tệ có quy tắc định dạng riêng.


0

Tương tự với các câu trả lời khác, nhưng được nén dưới dạng hằng số :

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

Ngoài ra, để lấy dấu phân cách hàng nghìn :

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

Chỉ cần đặt mã ở đầu JS của bạn và sau đó gọi theo yêu cầu để trả về ký hiệu.


Ví dụ: (nơi tôi sống), để xóa dấu phẩy khỏi "1,234,567":

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

-1

"Có cách nào để thực hiện việc đó ở phía máy chủ (tốt nhất là để tôi có thể thu thập số liệu thống kê) hoặc ở phía máy khách không?"

Không, bạn không thể. GUI đó đang xem xét một số cài đặt cụ thể của người dùng hoặc máy. Đầu tiên, bạn có thể không biết giao diện người dùng này đang tìm những cài đặt nào. Thứ hai, với một ứng dụng web, bạn có thể sẽ không thể kiểm tra các cài đặt này (clientide -> Javacsript).


@RWC: Tôi biết ứng dụng GUI đang tìm kiếm ở đâu: cài đặt khu vực Windows.
Quassnoi

-4

Một giải pháp khả thi khác: Bạn có thể sử dụng một cái gì đó như GeoIP (ví dụ trong PHP) để xác định vị trí của người dùng và quyết định dựa trên những thông tin này.


1
Tuy nhiên, cần phải cho phép người dùng ghi đè điều này. Một người bạn của tôi làm việc ở miền Nam nước Anh; công ty mà ông làm việc cho các tuyến đường tất cả truy cập Internet thông qua một máy chủ proxy ở Tây Ban Nha, vì vậy GeoIP luôn cho thấy anh ta như là hàng trăm dặm từ vị trí thực tế của mình.
NickFitz
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.