Click here to Skip to main content
15,881,882 members
Articles / Programming Languages / Javascript

Detecting User Regional Settings In The Web Browser

Rate me:
Please Sign up or sign in to vote.
4.33/5 (3 votes)
31 May 2010CPOL2 min read 48.7K   7   6
Detecting User Regional Settings In The Web Browser
free hit counters

Recently, a friend of mine asked me something like: “How do I get the user’s regional settings for a request to a web server?”

As far as I know, web browser only sends an Accept-Language HTTP header and nothing more. You can take this and use the default regional settings for that language but, if your user is anything like me, you’ll be wrong.

So, what’s the problem of getting it wrong?

If you are just generating HTML and keep it consistent, nothing’s wrong. But what if your user wants to copy some numeric and/or date values to, say, Excel? Or if you want to export some data as a CSV file?

A solution

Going through the JScript Language Reference, I found that both Number and Date have locale related toString methods and I started playing with them.

Numeric format settings

To the numeric format settings, first we need a number that will behave in a predictable manner in any culture (“any culture” means “any culture I know”) and for all possible settings and convert it to a string using the toLocaleString method:

C++
var number = 111111111.111111111;
var numberString = number.toLocaleString();

(With my regional settings, numberString becomes 111 111 111.11)

To get the decimal separator, all it takes is getting the first non 1 from the end:

C++
var decimalSeparator;
var decimalDigits;
for (var i = numberString.length - 1; i >= 0; i--) {
    var char = numberString.charAt(i);
    if (char != "1") {
        decimalSeparator = char;
        decimalDigits = numberString.length - i - 1;
        break;
    }
}

And if you count how many 1s were skipped, we get the number of decimal digits.

In a similar way, the first non 1 will be the digit grouping separator:

C++
var groupSeparator;
for (var i = 0; i < numberString.length; i++) {
    var char = numberString.charAt(i);
    if (char != "1") {
        groupSeparator = char;
        break;
    }
}

Now that we have the digit grouping separator, we can get the digit groups (these groups might not all have the same size):

C++
var digitGrouping = numberString.substring(0, 
    numberString.length - decimalDigits - 1).split(groupSeparator);
for (g in digitGrouping) {
    digitGrouping[g] = digitGrouping[g].length;
}
Date and time settings

Date and time values are more difficult to parse and you might not need all information. So, I’ll just get the value and let the parsing to you:

C++
var dateTime = new Date(9999, 11, 31, 23, 30, 45);
dateTimeString = dateTime.toLocaleString();
List settings

The last setting is the list separator (very useful for those CSV files):

C++
var list = ["a", "b"];
listSeparator = list.toLocaleString().substring(1, 2);

Test page

Here is a test page that gets all these settings:

HTML
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
    <title>Test Page</title>
    <style type="text/css">
        label  { width: 8em; text-align: right; 
    padding-right: 0.5em; white-space: nowrap; }
        span { border: 1px solid; white-space: nowrap; }
    </style>
    <script type="text/javascript">
        function init() {
            document.all.userLanguage.innerText = window.navigator.userLanguage;
            document.all.systemLanguage.innerText = window.navigator.systemLanguage;

            // Decimal separator and decimal digits
            var number = 111111111.111111111;
            var numberString = (111111111.111111111).toLocaleString();

            var decimalSeparator;
            var decimalDigits;
            for (var i = numberString.length - 1; i >= 0; i--) {
                var char = numberString.charAt(i);
                if (char != "1") {
                    decimalSeparator = char;
                    decimalDigits = numberString.length - i - 1;
                    break;
                }
            }
            document.all.decimalSeparator.innerText = decimalSeparator;
            document.all.decimalDigits.innerText = decimalDigits;

            // Digit grouping separator and digit goups
            var groupSeparator;
            for (var i = 0; i < numberString.length; i++) {
                var char = numberString.charAt(i);
                if (char != "1") {
                    groupSeparator = char;
                    break;
                }
            }
            document.all.groupSeparator.innerText = groupSeparator;

            var digitGrouping = numberString.substring(0, 
        numberString.length - decimalDigits - 1).split(groupSeparator);
            for (g in digitGrouping) {
                digitGrouping[g] = digitGrouping[g].length;
            }
            document.all.digitGrouping.innerText = digitGrouping.toString();

            // Date format
            var dateTime = new Date(9999, 11, 31, 23, 30, 45);
            var dateTimeString = dateTime.toLocaleString();
            document.all.dateTimeFormat.innerText = dateTimeString;

            // List separator
            var list = ["a", "b"];
            var listSeparator = list.toLocaleString().substring(1, 2);
            document.all.listSeparator.innerText = listSeparator;
        }
    </script>
</head>
<body onload="init()">
    <p><label for="userLanguage">User language:</label>
        <span id="userLanguage"></span></p>
    <p><label for="systemLanguage">System language:</label>
        <span id="systemLanguage"></span></p>
    <p><label for="decimalSeparator">Decimal separator:</label>
        <span id="decimalSeparator"></span></p>
    <p><label for="decimalDigits">Decimal digits:</label>
        <span id="decimalDigits"></span></p>
    <p><label for="groupSeparator">Digit separator:</label>
        <span id="groupSeparator"></span></p>
    <p><label for="digitGrouping">Digit grouping:</label>
        <span id="digitGrouping"></span></p>
    <p><label for="dateTimeFormat">Date/Time format:</label>
        <span id="dateTimeFormat"></span></p>
    <p><label for="listSeparator">List separator:</label>
        <span id="listSeparator"></span></p>
</body>
</html>
This article was originally posted at http://feeds.paulomorgado.net/paulomorgado/blogs/en

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior) Paulo Morgado
Portugal Portugal

Comments and Discussions

 
GeneralArray.toLocalString() works only on IE Pin
Ginni Benjamin28-Mar-11 22:47
Ginni Benjamin28-Mar-11 22:47 
GeneralRe: Array.toLocalString() works only on IE Pin
Paulo Morgado29-Mar-11 5:57
professionalPaulo Morgado29-Mar-11 5:57 
Apparently Firefox, Safari, Opera and Chrome have their own idea of locale.

Maybe someone at those product's forums can help you.
Cheers,

Paulo Morgado

Portugal - Europe's West Coast

GeneralinnerText is IE-specific Pin
Daniel Lo Nigro10-May-10 18:24
Daniel Lo Nigro10-May-10 18:24 
GeneralRe: innerText is IE-specific Pin
Paulo Morgado11-May-10 12:36
professionalPaulo Morgado11-May-10 12:36 
GeneralRe: innerText is IE-specific Pin
zpaulo_carraca9-Jun-10 0:12
zpaulo_carraca9-Jun-10 0:12 
GeneralRe: innerText is IE-specific Pin
Paulo Morgado10-Jun-10 14:54
professionalPaulo Morgado10-Jun-10 14:54 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.