<commit_before>{{setTitle "Internationalization in the Browser"}}

<h1>Internationalization in the Browser</h1>

<p>
    In the early days of browser development, Internationalization would happen most often on the server,
    since browsers did not have a standard way of formatting things like dates and numbers based on
    the locale of the browser. With more modern browsers we have the benefit of the ECMAScript Internationalization
    API (<a href="http://www.ecma-international.org/ecma-402/1.0/#sec-8">ECMA-402</a>) which provides
    language sensitive string comparison, number formatting, and date and time formatting.
</p>
<p>
    This is of great benefit for developers of websites and single page applications where data is often
    downloaded dynamically without location specific formatting. The
    <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl">{{code "Intl"}}</a> object
    provides constructors for {{code "Collator"}}, {{code "NumberFormat"}}, and {{code "DateTimeFormat"}}
    which give browser developers the basic tools they need for formatting.
</p>
<p>
Here are some examples:
</p>

<h2>Date Formatting</h2>

<p>
    You can format dates easily once you create a {{code "Date"}} object and call
    the {{code "format"}} method on {{code "Intl.DateTimeFormat"}}.
</p>

{{#code "js"}}
var date = new Date(Date.UTC(2012, 11, 20, 3, 0, 0));
new Intl.DateTimeFormat().format(date);
{{/code}}

Returns "{{code "12/19/2012"}}" if run in the {{code "en-US"}} locale with time zone {{code "America/Los-Angeles"}}.
Using {{code "Intl.DateTimeFormat()"}} with no arguments will use the system's locale and time zone.

{{#code "js"}}
new Intl.DateTimeFormat("en-GB").format(date);
{{/code}}

Returns "{{code "19/11/2012"}}" as British English uses day-month-year order.

{{#code "js"}}
new Intl.DateTimeFormat("ko-KR").format(date);
{{/code}}

Returns "{{code "2012년 12월 19일"}}" as Korean uses year-month-day order.

<p>
You can also format dates and times via the {{code "options"}} argument:
</p>

{{#code "js"}}
var options = {weekday: "long", year: "numeric", month: "long", day: "numeric"};
new Intl.DateTimeFormat("de-DE", options).format(date);
{{/code}}

Returns "{{code "Mittwoch, 19. Dezember 2012"}}" as you requested a weekday along with a long date.

<p>
    Note how you have the same date information in {{code "date"}} but specifying a different locale or formatting options
    changes the output. You can find out more about date formatting via the Intl specification
    <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DateTimeFormat">here</a>.
<p>

<h2>Number Formatting</h2>

<p>
    You can also format numbers in a similar fashion using {{code "Intl.NumberFormat"}}.
</p>

{{#code "js"}}
var number = 123456.789;
new Intl.NumberFormat().format(number);
{{/code}}

Returns "{{code "123,456.789"}}" when in the US English locale.

<p>
    As in {{code "Intl.DateTimeFormat"}} you can pass in a specific locale to specify a different language.
</p>


{{#code "js"}}
new Intl.NumberFormat("ar-EG").format(number);
{{/code}}

Returns "{{code "١٢٣٬٤٥٦٫٧٨٩"}}" using real Arabic digits that are used in that language.

<p>
    And just like {{code "Intl.DateTimeFormat"}}, you can use the {{code "options"}} argument to
    customize the formatting.
</p>


{{#code "js"}}
new Intl.NumberFormat("de-DE", {style: "currency", currency: "EUR"}).format(number);
{{/code}}

Returns "{{code "23.456,789 €"}}" using the Euro symbol for currency.

<h2>Browser Compatibility</h2>

For browsers that support {{code "window.Intl"}}, this makes it easy to do basic formatting of numbers
and dates. However, the {{code "window.Intl"}} object is relatively new so not all modern browsers
and devices support it. Here's a breakdown of desktop and mobile browsers support.

<h3>Runtimes</h3>
<table class="pure-table">
    <thead>
        <tr>
            <th>Feature</th>
            <th>Chrome</th>
            <th>Firefox (Gecko)</th>
            <th>Internet Explorer</th>
            <th>Opera</th>
            <th>Safari (WebKit)</th>
            <th>Node.js</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td>Basic support* </td>
            <td>24</td>
            <td>29</td>
            <td>11</td>
            <td>15</td>
            <td><span class="warning">Not supported</span></td>
            <td>Only via <a href="http://stackoverflow.com/questions/20125560/referenceerror-intl-is-not-defined-in-node-js/23255238#23255238">custom compile</a></td>
        </tr>
    </tbody>
</table>
<ul>
    <li><small>* "Basic support" meaning window.Intl + Constructors and Methods</small></li>
    <li><small>Source: <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl#Browser_Compatibility">MDN</a></small></li>
</ul>
<p>
    Mobile devices lag behind quite a bit, with only Chrome for Android (26) offering support. Which means Safari on mobile also does not support {{code "window.Intl"}}.
</p>

<p>
    Lacking {{code "window.Intl"}} support across browsers presents a problem for you as a developer
    since you want to use these features across all browsers and devices. Fortunately, there is a polyfill
    for Intl called <a href="https://github.com/andyearnshaw/Intl.js/">{{code "Intl.js"}}</a> written
    by <NAME>. This polyfill allows you to use the native API's
    for {{code "window.Intl"}} in legacy or unsupported environments.
</p>

<p>
    Since you only want to load this polyfill in browsers that do not support the native {{code "Intl"}} object,
    you may use a conditional loader like <a href="http://yepnopejs.com/">{{code "yepnope.js"}}</a> (available via
    <a href="http://cdnjs.com/libraries/yepnope">cdnjs.com</a>). Here is an example below loading {{code "Intl.js"}}
    from the Yahoo CDN along with the en-US locale information.
</p>


{{#code "js"}}


(function () {
    var locale    = "en-US", //you should obtain this information potentially from the server.
        baseUrl   = 'http://yui.yahooapis.com/combo?platform/intl/0.1.2/Intl.min.js&platform/intl/0.1.2/locale-data/jsonp/',
        comboUrl  = baseUrl + locale + '.js';
    yepnope([{
        test : !!window.Intl,
        nope : comboUrl
    }]);

})();

{{/code}}

Note the test {{code "!!window.Intl"}} which {{code "yepnope"}} uses to to decide whether to load {{code "Intl.js"}} polyfill
and associated locale metadata.

<h2>intl-messageformat</h2>

<p>
    Suppose however you want to construct more complex translations? There is a Yahoo library called
    <a href="https://github.com/yahoo/intl-messageformat">{{code "intl-messageformat"}}</a> that allows you to use JavaScript to create strings with localization support, and it can be used on both the client and the server.
    The constructor looks something like this:
</p>
{{#code "js"}}
var msg = new IntlMessageFormat(pattern, locale, [optFieldFormatters]);
{{/code}}

<p>
    Where the {{code "pattern"}} and {{code "locale"}} are strings and {{code "[optFieldFormatters]"}} is an object.
</p>


<p>
    Let's look at how to load the {{code "intl-messageformat" }} library. In a previous example, we conditionally loaded {{code "Intl.js"}} based off of the existance of the {{code "window.Intl"}} object
    in the browser. We can add additional directives to this code to also load the {{code "intl-messageformat"}} library.
    The most common way to do this is to load the base and all of the locales ({{code "intl-messageformat/build/intl-messageformat.complete.js"}}) in one file. This is a bit larger download but simplifies the need to have multiple locales.
</p>
<p>
    The path used in the example below assumes you have installed {{code "intl-messageformat"}} via bower using:
</p>

{{#code "js"}}
$ bower install intl-messageformat
{{/code}}

<p>
    For this example we've loaded the complete version which has been minified.
</p>

{{#code "js"}}
(function () {
    var locale    = APP.intl.locale,
        baseUrl   = 'http://yui.yahooapis.com/combo?platform/intl/0.1.2/Intl.min.js&platform/intl/0.1.2/locale-data/jsonp/',
        comboUrl  = baseUrl + locale + '.js',
        intlMessageFormatUrl = '/bower_components/intl-messageformat/build/intl-messageformat.complete.min.js';

    yepnope([{
        test : !!window.Intl,
        nope : comboUrl
    }, {
        load     : intlMessageFormatUrl,
        complete : init
    }]);

    function init () {
        // Initialize application here
    }
})();
{{/code}}


<p>
    In fact, this site itself loads {{code "intl-messageformat"}} in this fashion. View source to check it out!
</p>


<p>
    Now let's take a look at some examples.
</p>


<h3>Simple String Example</h3>

{{#code "js"}}
// create the message object
var msg = new IntlMessageFormat("My name is {NAME}.", "en-US");

// now call format on the resulting object and pass in JSON
var myNameIs = msg.format({NAME: "<NAME>"});

// myNameIs == "My name is <NAME>."

{{/code}}

<h3>More Complex Example</h3>

{{#code "js"}}
// create the message object
var msg = new IntlMessageFormat("{firstName} {lastName} has {numBooks, number, integer} {numBooks, plural, one {book} other {books}}" , "en-US");

// create the data object
var user =  {
    firstName: 'John',
    lastName : 'Smith',
    numBooks : 2000
}

// now call format on the resulting object and pass in your data
var books = msg.format({
    firstName: user.firstName,
    lastName:user.lastName,
    numBooks: user.numBooks
    });

// books == "<NAME> has 2,000 books"
{{/code}}
<p>
    You also may have noticed there is a third parameter. This allows you to pass in optional custom formatters.
    This is a very powerful feature which allows you to expand upon the existing built-in formatters for just
    about any sort of formatting such as currency, percents, or relative times. You can read more about user defined formatters in the <a href="https://github.com/yahoo/intl-messageformat#user-defined-formatters">{{code "intl-messageformat"}} documentation</a>.
</p>




<h2>Where To Go From Here?</h2>

<p>
    If you've reached this point then you should have an understanding of how Internationalization works in the
    browser. We touched upon the ECMAScript Internationalization API (<a href="http://www.ecma-international.org/ecma-402/1.0/">ECMA-402</a>), the need for a polyfill for unsupported browsers through <a href="https://github.com/andyearnshaw/Intl.js/">{{code "Intl.js"}}</a>, and how to format strings with placeholders to create localized
    messages through <a href="https://github.com/yahoo/intl-messageformat">{{code "intl-messageformat"}}</a>.
</p>
<p>
    Working with {{code "intl-messageformat"}} is fairly easy, but if you are developing a website or single page application you may already be using a template engine like Dust or Handlebars, or a library like ReactJS. We provide helpers for each of these. For more information check out the documentation for <a href="#">{{code "dust-helper-intl"}}</a> , <a href="#">{{code "handlebars-helper-intl"}}</a>, and <a href="#">{{code "react-intl"}}</a>.
</p>

<commit_msg>Wording changes. Pared down Date examples<commit_after>{{setTitle "Internationalization in the Browser"}}

<h1>Internationalization in the Browser</h1>

<p>
    In the early days of browser development, Internationalization would happen most often on the server,
    since browsers did not have a standard way of formatting things like dates and numbers based on
    the locale of the browser. With more modern browsers we have the benefit of the ECMAScript Internationalization
    API (<a href="http://www.ecma-international.org/ecma-402/1.0/#sec-8">ECMA-402</a>) which provides
    language sensitive string comparison, number formatting, and date and time formatting.
</p>
<p>
    This is of great benefit for developers of websites and single page applications where data is often
    downloaded dynamically without location specific formatting. The
    <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl">{{code "Intl"}}</a> object
    provides constructors for {{code "Collator"}}, {{code "NumberFormat"}}, and {{code "DateTimeFormat"}}
    which give browser developers the basic tools they need for formatting.
</p>
<p>
Here are some examples:
</p>

<h2>Date Formatting</h2>

<p>
    You can format dates easily once you create a {{code "Date"}} object and call
    the {{code "format"}} method on {{code "Intl.DateTimeFormat"}}.
</p>

{{#code "js"}}
var date = new Date(Date.UTC(2012, 11, 20, 3, 0, 0));
new Intl.DateTimeFormat("en-US").format(date);
{{/code}}

Returns "{{code "12/19/2012"}}" if run in the {{code "en-US"}} locale with time zone {{code "America/Los-Angeles"}}.
Using {{code "Intl.DateTimeFormat()"}} with no arguments will use the system's locale and time zone.

<p>
You can also format dates and times via the {{code "options"}} argument:
</p>

{{#code "js"}}
var options = {weekday: "long", year: "numeric", month: "long", day: "numeric"};
new Intl.DateTimeFormat("de-DE", options).format(date);
{{/code}}

Returns "{{code "Mittwoch, 19. Dezember 2012"}}" as you requested a weekday along with a long date.

<p>
    Note how you have the same date information in {{code "date"}} but specifying a different locale or formatting options
    changes the output. You can find out more about date formatting via the Intl specification
    <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DateTimeFormat">here</a>.
<p>

<h2>Number Formatting</h2>

<p>
    You can also format numbers in a similar fashion using {{code "Intl.NumberFormat"}}.
</p>

{{#code "js"}}
var number = 123456.789;
new Intl.NumberFormat().format(number);
{{/code}}

Returns "{{code "123,456.789"}}" when in the US English locale.

<p>
    As in {{code "Intl.DateTimeFormat"}} you can pass in a specific locale to specify a different language.
</p>


{{#code "js"}}
new Intl.NumberFormat("ar-EG").format(number);
{{/code}}

Returns "{{code "١٢٣٬٤٥٦٫٧٨٩"}}" using real Arabic digits that are used in that language.

<p>
    And just like {{code "Intl.DateTimeFormat"}}, you can use the {{code "options"}} argument to
    customize the formatting.
</p>


{{#code "js"}}
new Intl.NumberFormat("de-DE", {style: "currency", currency: "EUR"}).format(number);
{{/code}}

Returns "{{code "23.456,789 €"}}" using the Euro symbol for currency.

<h2>Browser Compatibility</h2>

For browsers that support {{code "window.Intl"}}, this makes it easy to do basic formatting of numbers
and dates. However, the {{code "window.Intl"}} object is relatively new so not all modern browsers
and devices support it. Here's a breakdown of desktop and mobile browsers support.

<h3>Runtimes</h3>
<table class="pure-table">
    <thead>
        <tr>
            <th>Feature</th>
            <th>Chrome</th>
            <th>Firefox (Gecko)</th>
            <th>Internet Explorer</th>
            <th>Opera</th>
            <th>Safari (WebKit)</th>
            <th>Node.js</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td>Basic support* </td>
            <td>24</td>
            <td>29</td>
            <td>11</td>
            <td>15</td>
            <td><span class="warning">Not supported</span></td>
            <td>Only via <a href="http://stackoverflow.com/questions/20125560/referenceerror-intl-is-not-defined-in-node-js/23255238#23255238">custom compile</a></td>
        </tr>
    </tbody>
</table>
<ul>
    <li><small>* "Basic support" meaning window.Intl + Constructors and Methods</small></li>
    <li><small>Source: <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl#Browser_Compatibility">MDN</a></small></li>
</ul>
<p>
    Mobile devices lag behind quite a bit, with only recent versions of Chrome for Android offering support. Which means Safari on mobile also does not support {{code "window.Intl"}}.
</p>

<p>
    Lacking {{code "window.Intl"}} support across browsers presents a problem for you as a developer
    since you want to use these features across all browsers and devices. Fortunately, there is a polyfill
    for Intl called <a href="https://github.com/andyearnshaw/Intl.js/">{{code "Intl.js"}}</a> written
    by <NAME>. This polyfill allows you to use the native API's
    for {{code "window.Intl"}} in legacy or unsupported environments.
</p>

<p>
    Since you only want to load this polyfill in browsers that do not support the native {{code "Intl"}} object,
    you may use a conditional loader like <a href="http://yepnopejs.com/">{{code "yepnope.js"}}</a> (available via
    <a href="http://cdnjs.com/libraries/yepnope">cdnjs.com</a>). Here is an example below loading {{code "Intl.js"}}
    from the Yahoo CDN along with the en-US locale information.
</p>


{{#code "js"}}


(function () {
    var locale    = "en-US", //you should obtain this information potentially from the server.
        baseUrl   = 'http://yui.yahooapis.com/combo?platform/intl/0.1.2/Intl.min.js&platform/intl/0.1.2/locale-data/jsonp/',
        comboUrl  = baseUrl + locale + '.js';
    yepnope([{
        test : !!window.Intl,
        nope : comboUrl
    }]);

})();

{{/code}}

Note the test {{code "!!window.Intl"}} which {{code "yepnope"}} uses to to decide whether to load {{code "Intl.js"}} polyfill
and associated locale metadata.

<h2>intl-messageformat</h2>

<p>
    Suppose however you want to construct more complex translations? There is a Yahoo library called
    <a href="https://github.com/yahoo/intl-messageformat">{{code "intl-messageformat"}}</a> that allows you to use JavaScript to create strings with localization support, and it can be used on both the client and the server.
    The constructor looks something like this:
</p>
{{#code "js"}}
var msg = new IntlMessageFormat(pattern, locale, [optFieldFormatters]);
{{/code}}

<p>
    Where the {{code "pattern"}} and {{code "locale"}} are strings and {{code "[optFieldFormatters]"}} is an object.
</p>


<p>
    Let's look at how to load the {{code "intl-messageformat" }} library. In a previous example, we conditionally loaded {{code "Intl.js"}} based off of the existance of the {{code "window.Intl"}} object
    in the browser. We can add additional directives to this code to also load the {{code "intl-messageformat"}} library.
    The most common way to do this is to load the base and all of the locales ({{code "intl-messageformat/build/intl-messageformat.complete.js"}}) in one file. This is a bit larger download but simplifies the need to have multiple locales.
</p>
<p>
    The path used in the example below assumes you have installed {{code "intl-messageformat"}} via bower using:
</p>

{{#code "js"}}
$ bower install intl-messageformat
{{/code}}

<p>
    For this example we've loaded the complete version which has been minified.
</p>

{{#code "js"}}
(function () {
    var locale    = APP.intl.locale,
        baseUrl   = 'http://yui.yahooapis.com/combo?platform/intl/0.1.2/Intl.min.js&platform/intl/0.1.2/locale-data/jsonp/',
        comboUrl  = baseUrl + locale + '.js',
        intlMessageFormatUrl = '/bower_components/intl-messageformat/build/intl-messageformat.complete.min.js';

    yepnope([{
        test : !!window.Intl,
        nope : comboUrl
    }, {
        load     : intlMessageFormatUrl,
        complete : init
    }]);

    function init () {
        // Initialize application here
    }
})();
{{/code}}


<p>
    In fact, this site itself loads {{code "intl-messageformat"}} in this fashion. View source to check it out!
</p>


<p>
    Now let's take a look at some examples.
</p>


<h3>Simple String Example</h3>

{{#code "js"}}
// create the message object
var msg = new IntlMessageFormat("My name is {NAME}.", "en-US");

// now call format on the resulting object and pass in JSON
var myNameIs = msg.format({NAME: "<NAME>"});

// myNameIs == "My name is <NAME>."

{{/code}}

<h3>More Complex Example</h3>

{{#code "js"}}
// create the message object
var msg = new IntlMessageFormat("{firstName} {lastName} has {numBooks, number, integer} {numBooks, plural, one {book} other {books}}" , "en-US");

// create the data object
var user =  {
    firstName: 'John',
    lastName : 'Smith',
    numBooks : 2000
}

// now call format on the resulting object and pass in your data
var books = msg.format({
    firstName: user.firstName,
    lastName:user.lastName,
    numBooks: user.numBooks
    });

// books == "<NAME> has 2,000 books"
{{/code}}
<p>
    You also may have noticed there is a third parameter. This allows you to pass in optional custom formatters.
    This is a very powerful feature which allows you to expand upon the existing built-in formatters for just
    about any sort of formatting such as currency, percents, or relative times. You can read more about user defined formatters in the <a href="https://github.com/yahoo/intl-messageformat#user-defined-formatters">{{code "intl-messageformat"}} documentation</a>.
</p>




<h2>Where To Go From Here?</h2>

<p>
    If you've reached this point then you should have an understanding of how Internationalization works in the
    browser. We touched upon the ECMAScript Internationalization API (<a href="http://www.ecma-international.org/ecma-402/1.0/">ECMA-402</a>), the need for a polyfill for unsupported browsers through <a href="https://github.com/andyearnshaw/Intl.js/">{{code "Intl.js"}}</a>, and how to format strings with placeholders to create localized
    messages through <a href="https://github.com/yahoo/intl-messageformat">{{code "intl-messageformat"}}</a>.
</p>
<p>
    Working with {{code "intl-messageformat"}} is fairly easy, but if you are developing a website or single page application you may already be using a template engine like Dust or Handlebars, or a library like ReactJS. We provide helpers for each of these. For more information check out the documentation for <a href="#">{{code "dust-helper-intl"}}</a> , <a href="#">{{code "handlebars-helper-intl"}}</a>, and <a href="#">{{code "react-intl"}}</a>.
</p>


{'fraction_non_alphanumeric': 0.14127636511449349, 'fraction_numerical': 0.01409150444876022, 'mean_word_length': 3.6881219563836543, 'pattern_counts': {'":': 0, '<': 299, '<?xml version=': 0, '>': 299, 'https://': 16, 'lorem ipsum': 0, 'www.': 4, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6941119', 'n_tokens_mistral': 7251, 'n_tokens_neox': 6854, 'n_words': 2482}