JsWorld

Features

1. Clean separation between formatting logic and locale data

Separation of logic and data

2. Use of POSIX-style locale properties

Care is taken to keep things standard and unsurprising. To describe the formatting conventions of the various locales JsWorld follows the POSIX specification, which is well known to OS and systems programmers.

Formatting POSIX specification
Numeric LC_NUMERIC
Monetary LC_MONETARY
Date/time LC_TIME

If you open a locale definition file from the locales/js/ directory, you'll see a JavaScript object with the various POSIX LC_NUMERIC, LC_MONETARY and LC_TIME properties. Here is the file storing the properties for the French locale:

locales/js/fr_FR.js

if(typeof POSIX_LC == "undefined") var POSIX_LC = {};

POSIX_LC.fr_FR = {
	"decimal_point"      : ",",
	"thousands_sep"      : "\u00a0",
	"grouping"           : "3",
	"abday"              : ["dim.","lun.","mar.",
	                        "mer.","jeu.","ven.",
				"sam."],
	"day"                : ["dimanche","lundi","mardi",
	                        "mercredi","jeudi","vendredi",
				"samedi"],
	"abmon"              : ["janv.","f\u00e9vr.","mars",
	                        "avr.","mai","juin",
				"juil.","ao\u00fbt","sept.",
				"oct.","nov.","d\u00e9c."],
	"mon"                : ["janvier","f\u00e9vrier","mars",
	                        "avril","mai","juin",
				"juillet","ao\u00fbt","septembre",
				"octobre","novembre","d\u00e9cembre"],
	"d_fmt"              : "%d/%m/%y",
	"t_fmt"              : "%H:%M:%S",
	"d_t_fmt"            : "%e %B %Y %H:%M:%S %Z",
	"am_pm"              : ["AM","PM"],
	"int_curr_symbol"    : "EUR ",
	"currency_symbol"    : "\u20ac",
	"mon_decimal_point"  : ",",
	"mon_thousands_sep"  : "\u00a0",
	"mon_grouping"       : "3",
	"positive_sign"      : "",
	"negative_sign"      : "-",
	"int_frac_digits"    : 2,
	"frac_digits"        : 2,
	"p_cs_precedes"      : 0,
	"n_cs_precedes"      : 0,
	"p_sep_by_space"     : 1,
	"n_sep_by_space"     : 1,
	"p_sign_posn"        : 1,
	"n_sign_posn"        : 1,
	"int_p_cs_precedes"  : 0,
	"int_n_cs_precedes"  : 0,
	"int_p_sep_by_space" : 1,
	"int_n_sep_by_space" : 1,
	"int_p_sign_posn"    : 1,
	"int_n_sign_posn"    : 1
};

Note that all non-ASCII characters have been replaced with the appropriate Unicode escape sequences.

The locale definition is used to construct a jsworld.Locale object which is then used to create the corresponding formatting or parsing object.

// Create a new locale object from the fr_FR locale data
var lc = new jsworld.Locale(POSIX.fr_FR);

// Print the current date in French
var formatter = new jsworld.DateTimeFormatter(lc);
document.writeln(formatter.formatDate(new Date()));

// Print the current time in French
document.write(formatter.formatTime(new Date()));

The meaning of the individual locale properties is described in the corresponding POSIX specifications (see LC_NUMERIC, LC_MONETARY and LC_TIME) as well as in JsWorld's API docs.

3. Locale data formats

You can choose between three locale definition formats, depending on the type of your application.

Format File location Suitable for
JavaScript locales/js/ Static inclusion in HTML pages via <script> tag
JSON locales/json/ Dynamic loading via XMLHTTPRequest
Mozilla properties locales/mozilla/ Mozilla XULRunner applications

3.1 JavaScript

For simple web applications you can use the regular JavaScript files in the locales/js/ directory. Use a <script> tag to include them, which places an object "POSIX_LC.<locale_code>" into your JavaScript namespace. The namespacing is done in way which allows you to include multiple locale definitions, without causing clashes.

<!-- Include the JsWorld formatting classes -->
<script type="text/javascript" src="JsWorld.js"></script>

<!-- Include the en_US locale data -->
<script type="text/javascript" src="locales/js/en_US.js"></script>

<!-- Include the de_DE (German) locale data -->
<script type="text/javascript" src="locales/js/de_DE.js"></script>


<script>
// Create formatter for US locale
var usLocale = new jsworld.Locale(POSIX_LC.en_US);
var usNumericFormatter = new jsworld.NumericFormatter(usLocale);

// Create formatter for German locale
var germanLocale = new jsworld.Locale(POSIX_LC.de_DE);
var germanNumericFormatter = new jsworld.NumericFormatter(germanLocale);

// Show number in US locale
alert(usNumericFormatter(25000.10));

// Show number in German locale
alert(germanNumericFormatter(74999.90));
</script>

You also have the option to include the definitions of all available locales (over 300) by pointing to the locales/js/POSIX_LC.js file. This, however, will consume a lot more memory and bandwidth as the aggregate data for all locales takes up about 500KB.

<!-- Include data for all available locales -->
<script type="text/javascript" src="locales/js/POSIX_LC.js"></script>

3.2 JSON

For interactive (Ajax) web applications use the locale definitions in the locales/json/ directory. They are JSON-encoded, making them suitable for dynamic loading with XMLHTTPRequest.

<!-- Include the JsWorld formatting classes -->
<script type="text/javascript" src="JsWorld.js"></script>

<script>
// Example assumes Firefox 3.5!

// The locale data file (e.g. Canadian English) in JSON format
var url = "http://my-site.com/jsworld/locales/json/en_CA.json";

// Make request
var req = new XMLHttpRequest();  
req.open("GET", url, true);  
req.onreadystatechange = function (aEvt) {  
    if (req.readyState == 4) {  
        if(req.status == 200) {
	
	    // Parse response JSON
	    var localeData = JSON.parse(req.responseText);
	    
	    // Create new formatter with received locale properties
	    var lc = new jsworld.Locale(localeData);
	    var dateTimeFormatter = new jsworld.DateTimeFormatter(lc);
	}
        else {
           alert("Error loading locale data");
	}
   }  
};  
req.send(null); 

</script>

3.3 Mozilla property files

The locale definitions are also avilable as property files, a format XULRunner applications and Firefox add-ons. These are located in the locales/mozilla/ directory.

Here is an example how to import all items from a Mozilla property file and pack them into a single JavaScript object:

// XPCOM shorthands
const Cc = Components.classes;
const Ci = Components.interfaces;

// Location of the properties file
var stringBundleURI = "chrome://app/locale/en_US.properties";

// Open properties file
var stringService = Cc["@mozilla.org/intl/stringbundle;1"]
	.getService(Ci.nsIStringBundleService);
var sb = stringService.createBundle(stringBundleURI);

// Retrieve locale data
var localeProps = {};
var propertyList = sb.getSimpleEnumeration();

while (propertyList.hasMoreElements()) {
	var prop = propertyList.getNext().QueryInterface(Ci.nsIPropertyElement);
	localeProps[prop.key] = prop.value;
}

// Create locale object from the raw properties
var lc = new jsworld.Locale(localeProps);

// Create the corresponding formatters
var nf = new jsworld.NumericFormatter(lc);
var mf = new jsworld.MonetaryFormatter(lc);
var dtf = new jsworld.DateTimeFormatter(lc);

4. Exception handling

The formatting / parsing classes will raise an exception if something goes wrong, e.g. on:

You can handle these error conditions by using a try-catch clause:

try {
	var lc = new jsworld.Locale(POSIX_LC.en_GB);
	var mf = new jsworld.MonetaryFormatter(lc);
	
	// attempt to format an invalid amount
	mf.format("abc");
	
} catch (error) {
	alert(error);
}

5. API documentation

Auto-generated API documentation is provided with the package as well as online:

JsWorld [jsdoc]