Globalize 1.3.0 announcement

On July 3rd, we released Globalize 1.3.0. It is a special release, because it includes some very useful feature enhancements to support advanced date, time, timezone manipulation, and other long due fixes. We wanted to share more details on these improvements.

IANA/Olson Time Zone Support

This change was contributed by Kandaswamy Manikandan @rajavelmani (PayPal) and Rafael Xavier @rxaviers in #687 and #701.

In previous versions, Globalize had some partial time zone support for a user’s runtime time zone. However specific CLDR patterns (z, v, and V) that display strings such as PDT, Pacific Daylight Time, Pacific Time, and Los Angeles Time could not be displayed. The challenge we had to determine how costly a solution would be to provide full IANA/Olson time zone support due to the additional manipulation code and data (i.e., IANA database). Therefore, in the past, we encouraged users that needed to manipulate date in arbitrary time zones to use a separate library, like moment-timezone. Nevertheless, this solution never closed the gap between internationalization (i18n) implementations leveraging CLDR and having full maneuverability of time zones.

With the latest release 1.3.0, Globalize fully supports time zone. Simply put, by using Globalize 1.3.0, you now have full IANA support with the strength of CLDR for i18n!

Globalize.locale("en");
let date = new Date();

Globalize.formatDate(date, {datetime: "short", timeZone: "America/Los_Angeles"});
// > '3/19/17, 3:19 PM'
Globalize.formatDate(date, {datetime: "short", timeZone: "America/New_York"});
// > '3/19/17, 6:19 PM'
Globalize.formatDate(date, {datetime: "short", timeZone: "America/Sao_Paulo"});
// > '3/19/17, 7:19 PM'
Globalize.formatDate(date, {datetime: "short", timeZone: "Europe/Berlin"});
// > '3/19/17, 11:19 PM'

Globalize.formatDate(date, {datetime: "full", timeZone: "America/Los_Angeles"});
// > 'Sunday, March 19, 2017 at 3:19:22 PM Pacific Daylight Time'
Globalize.formatDate(date, {datetime: "full", timeZone: "America/New_York"});
// > 'Sunday, March 19, 2017 at 6:19:22 PM Eastern Daylight Time'
Globalize.formatDate(date, {datetime: "full", timeZone: "America/Sao_Paulo"});
// > 'Sunday, March 19, 2017 at 7:19:22 PM Brasilia Standard Time'
Globalize.formatDate(date, {datetime: "full", timeZone: "Europe/Berlin"});
// > 'Sunday, March 19, 2017 at 11:19:22 PM Central European Standard Time'

Globalize("pt").formatDate(date, {datetime: "full", timeZone: "America/Sao_Paulo"});
// > 'domingo, 19 de março de 2017 19:19:22 Horário Padrão de Brasília'
Globalize("de").formatDate(date, {datetime: "full", timeZone: "Europe/Berlin"});
// > 'Sonntag, 19. März 2017 um 23:19:22 Mitteleuropäische Normalzeit'
Globalize("zh").formatDate(date, {datetime: "full", timeZone: "Asia/Shanghai"});
// > '2017年3月20日星期一 中国标准时间 上午6:19:22'
Globalize("ar").formatDate(date, {datetime: "full", timeZone: "Africa/Cairo"});
// > 'الاثنين، ٢٠ مارس، ٢٠١٧ ١٢:١٩:٢٢ ص توقيت شرق أوروبا الرسمي'

We have solved this in a low footprint, high performance implementation using zoned-date-time under the hoods, which is a 0.6KB library for the time zone manipulations. We have leveraged the Globalize Compiler for precompling the IANA data base for production. For example, let’s say you are serving content in English (e.g. locale en-US) for America/Los_Angeles time using the following formatter:

var dateWithTimeZoneFormatter = Globalize.dateFormatter({
  datetime: "full",
  timeZone: "America/Los_Angeles"
});

The final size (for production) of this code will be:

filename minified+gzipped size
i18n/en.js (includes CLDR and IANA data) 1.7KB
core, number, and date globalize runtime lib + zoned-date-time 7.0KB

See globalize compiler example or app-npm-webpack example for details.

Format Date To Parts

This change was contributed by Reza Payami @rpayami (PayPal) and Rafael Xavier @rxaviers in #697 and #700.

Modern user interfaces often need to manipulate the date format output, which is impossible via the existing format function that returns an opaque string. Making any attempt to do this can break internationalization support. Ecma-402 has recently added Intl.DateTimeFormat.prototype.formatToParts to fulfill that purpose, which at the time of this post, is at stage 4 and is implemented by latest Firefox and Chrome.

In Globalize, we introduced .dateToPartsFormatter and .formatDateToParts.

Globalize.locale( "en" );
Globalize.formatDateToParts(new Date(2010, 10, 30));
// > [
// { "type": "month", "value": "11" },
// { "type": "literal", "value": "/" },
// { "type": "day", "value": "30" },
// { "type": "literal", "value": "/" },
// { "type": "year", "value": "2010" }
// ]

The data is available separately and it can be formatted and concatenated again in a customized way. For example by using Array.prototype.map(), arrow functions, a switch statement, template literals, and Array.prototype.reduce().

let formatter;

Globalize.locale( "en" );
formatter = Globalize.dateToPartsFormatter({datetime: "short"});

formatter( new Date( 2010, 10, 30, 17, 55 ) ).map(({type, value}) => {
  switch ( type ) {
    case "year": return `<strong>${value}</strong>`;
    default: return value;
  }
}).join( "" );
// > "11/30/<strong>10</strong>, 5:55 PM"

See React Date Input as a demo of a UI component for React optimized for i18n and a11y.

Localized and smart date input Feb 28 in en, es, pt, de, zh, ko, and ar
en en-es-pt-de-zh-ko-ar

Dynamically Augmented Date Skeletons

This change was contributed by Marat Dyatko @vectart and Artur Eshenbrener @Strate in #462 and #604.

The style used to display a date format often varies depending on the application. CLDR offers data for certain presets like short (e.g., short date "7/1/17"), medium (e.g., medium date "Jul 1, 2017"), long (e.g., long date "July 1, 2017"), and full (e.g., full date "Saturday, July 1, 2017"). Although, we could need something different such as "Jul 1". For that CLDR offers data for individual date fields and their combinations, which are used by Globalize to synthesize an open-ended list of custom formats (called skeletons). But, what’s interesting is that it would be prohibitively large if CLDR provided data for every single possible combination. So, there’s an algorithm specified by UTS#35 to deduce missing data from the requested format.

For the "Jul 1" example, we should use {skeleton: "MMMd"}. Internally, Globalize finds a direct match in CLDR for the requested skeleton. This works fine in previous Globalize versions.

For that next example, let’s assume we want "July 1", i.e., {skeleton: "MMMMd"}. Internally, Globalize doesn’t find a direct match in CLDR. For this skeleton, Globalize needs to use the data for MMMd, which maps to "MMM d" in the English case, and then it needs to replace MMM with MMMM dynamically generating "MMMM d". This doesn’t work in previous versions of Globalize, but it works now on latest v1.3.0.

If we wanted "07/01" instead, we should use {skeleton: "MMdd"}. Internally, Globalize doesn’t find a direct match in CLDR for this skeleton and, therefore, it fais in globalize v1.2.3. Globalize needs to use the data for Md, which in the case of English maps to "M/d", and then replace M wtih MM and d with dd dynamically generating "MM/dd".

To make a long story short, the algorithm in globalize v1.3.0 has been significantly improved and it allows using virtually any skeletons.

// A skeleton not directly found in CLDR and that needs to be deduced by globalize.
// In English, globalize needs to use the data for GyMMMEd, and adjust MMM with MMMM,
// and E with EEEE. Then, it needs to find the data for hms and glue them together
// using the appropriate format.
// On globalize v1.2.3, an error is thrown saying this skeleton wasn't found.
let skeleton = "GyMMMMEEEEdhms";
Globalize("en").formatDate(new Date(), {skeleton});
// > 'Saturday, July 1, 2017 AD at 4:58:27 PM'
Globalize("pt").formatDate(new Date(), {skeleton});
// > 'sábado, 1 de julho de 2017 d.C. 5:01:20 PM'
Globalize("de").formatDate(new Date(), {skeleton});
// > 'Samstag, 1. Juli 2017 n. Chr. um 5:01:33 nachm.'
Globalize("zh").formatDate(new Date(), {skeleton});
// > '公元2017年七月月1日星期六 下午5:01:35'
Globalize("ko").formatDate(new Date(), {skeleton});
// > 'AD 2017년 7월 1일 토요일 오후 5:01:38'
Globalize("ar").formatDate(new Date(), {skeleton});
// > 'السبت، ١ يوليو، ٢٠١٧ م ٥:٠١:٤٠ م'
Globalize("ar-MA").formatDate(new Date(), {skeleton});
// > 'السبت، 1 يوليوز، 2017 م 5:04:29 م'
Globalize("it").formatDate(new Date(), {skeleton});
// > 'sabato 1 luglio 2017 d.C. 5:01:52 PM'

Read our getting started and play with it yourself.

Other Enhancements and Bug Fixes

Enhancements

  • Date: Show timezone offset optional minutes for O pattern (e.g., GMT-6:30 note the :30) #339 (via PR #729) (Rafael Xavier)
  • Date: Show timezone offset optional minutes and seconds for x and X patterns (e.g., -06:30 note the :30) #339 (via PR #729) (Rafael Xavier)
  • Date: Assert options.skeleton (PR #726) (Rafael Xavier)
  • Date parser: Make runtime phase lighter #735 (Rafael Xavier)
  • Date parser: Loose Matching PR #730(Rafael Xavier)
    • Allows, among others, parsing arabic dates as user types them (i.e., without control characters)
  • Number formatter: Amend integer and fraction formatter for small numbers like 1e-7 #750 (Rafael Xavier)
  • Number parser: Lenient about trailing decimal separator #744 (Rafael Xavier)
  • Runtime: Use strict #676 (Zack Birkenbuel)

Fixes

  • Date parser: invalid output by mixing numbering systems #696 (via PR #733) (Rafael Xavier)
  • Date parser: fails on Turkish full datetime with Monday or Saturday #690 (via PR #732) (Rafael Xavier)

Others

  • Compiler tests! #721 (via PR #727) (Nikola Kovacs)
  • Documentation style refactor #737 (Rafael Xavier)

Last but not least

Special thanks to other PayPal internationalization team members including Daniel Bruhn, Lucas Welti, Alolita Sharma, Mike McKenna for testing and helping integrate Globalize for PayPal products.

Special thanks to James Bellenger and Nicolas Gallagher for the React and Webpack integration enhancements for Twitter products, which certainly deserves its own blog post.

Many thanks to all of you who participated in this release by testing, reporting bugs, or submitting patches, including Jörn Zaefferer, Frédéric Miserey, Nova Patch, and whole Globalize team.

Source: https://github.com/globalizejs/globalize/blob/master/doc/blog-post/2017-07-xx-1.3.0-announcement.md

TC39: Ecma-402 updates

This Tuesday (March 21), we had a TC39 meeting (the committee responsible for evolving the ECMAScript language, the browsers’ programming language) where several JavaScript topics were discussed, including Ecma-402 (the Internationalization API Specification).

If you are an i18n engineer, this post might interest you…

Basically we had 4 proposals.

  • 3 about new API (Intl.ListFormat, Intl.UnitFormat, Intl.RelativeTimeFormat, Intl.Segmenter), and
  • 1 about an update to Intl.DateTimeFormat: date and time styles, basically what we call presets short|medium|long|full.

Overall, the Ecma-402 updates took a bigger slot than original planned. It seems it has gained enough traction to actually make TC39 intrigued and asking lots of questions. Allen Wirfs-Brock (former Ecma-262 editor) mentioned TC39 needs to invest more time into understanding about i18n and what Ecma-402 is doing.

By the way, below the terms stage 1, 2, 3, and 4 are mentioned. Find details about that at https://tc39.github.io/process-document/.

Intl.ListFormat

Presented by Zibi (Mozilla), this is a new API to allow the creation of localized lists. It’s currently at stage 1 (proposal) and seeks stage 2 (draft). It looks something like this:

new Intl.ListFormat("en").format(["John", "Mary", "Mike"]);
// > "John, Mary, and Mike"

TC39 agreed to advanced it to stage 2 (draft) despite some initial confusion about the use cases.

Intl.UnitFormat

New API to allow simple unit formatting. It’s currently at stage 1 (proposal) and seeks stage 2 (draft). It looks something like this:

new Intl.UnitFormat("en", {category: "duration"}).format(2, "hour");
// > "2 hours"

Remaining at stage 1 (proposal). The agreement was that it needs more experimentation and exploration. It was specially confusing for the TC39 the relationship between this formatter and others like relativeTimeFormat and Duration (this one by the way isn’t even elaborated).

Intl.RelativeTimeFormat

New API to allow simple relative time formatting. It’s currently at stage 1 (proposal) and seeks stage 2 (draft). It looks something like this:

new Intl.RelativeTimeFormat("en").format(-10, "second");
// > "10 seconds ago"

Remaining at stage 1 (proposal) pending more understanding. Similar to the UnitFormat.

Intl.DateTimeFormat dateStyle/timeStyle

Update to existing DateTimeFormat. It’s about the addition of preset styles that looks like the below.

let dtf = new Intl.DateTimeFormat("en", {
    dateStyle: “short”
}); // "3/21/17"

let dtf = new Intl.DateTimeFormat("en", {
    timeStyle: “short”
}); // "1:31 PM"

let dtf = new Intl.DateTimeFormat("en", {
    dateStyle: “short”,
    timeStyle: “long”
}); // "3/21/17, 1:31:47 PM PDT"

Advanced to stage 1 (proposal), which doesn’t necessarily mean the API was in agreement. It was discussed whether to use the current proposal or to follow using a different approach by breaking it down into two explicit steps like the below.

let options = Intl.DateTimeFormat.getOptionsForStyle("date", "short");
let dtf = new Intl.DateTimeFormat("en", options);

Intl.Segmenter

Presented by (Daniel Ehrenberg), It’s currently at stage 2 (draft) and seeking reviewers for stage 3 (candidate). It’s a new API that helps finding localized grapheme, word and sentence breaks (UTS 29) and line breaks (UAX 14). It looks something like this:

let segmenter = new Intl.Segmenter("fr", {type: "word"});
let segmentIterator = segmenter.segment("Ceci n'est pas une pipe");

It remains at stage 2. Stage 3 reviewers identified.

Nick Hanauer controversial yet interesting plutocrats talk

Capitalism does not work by effectively allocating existing resources. It works by effectively creating new solutions to human problems. The genius of capitalism is that it is an evolutionary solution finding system. It rewards people for solving other people’s problems… The more people we include both as entrepreneurs and as customers the best it works.

https://www.ted.com/talks/nick_hanauer_beware_fellow_plutocrats_the_pitchforks_are_coming

A story of jQuery, CLDR JSON and the Community at the Unicode Conf, Santa Clara – CA

On November, I gave a talk at the Internationalization & Unicode Conference #38, Santa Clara – CA. There’s no video this time. But, here are the slides, a picture thanks to John Huân () and its transcription (slightly changed to sound better for a post).

Presenting Globalize at Unicode Conf
jQuery is very popular for its core project create by John Resig that made web development simple and reliable in the dark era of browsers. Developers could use the magical dollar sign and not worry about compatibility anymore.

It happens that we have other projects as well, which are all under the same jQuery foundation umbrella. A really quick intro. UI, which holds a curated set of user interface components and is famous for its calendar widget: datepicker. Mobile, which extends UI with responsiveness and accessibility for smartphone and tablet devices. QUnit, which is a testing framework, we happen to use it ourselves to test our projects. Sizzle, the CSS selector engine inlcuded in jQuery. and Globalize, which is where I am.

My name is Rafael Xavier and I’m Globalize project lead. So, enough introduction, what happened to Globalize?

Everything starts with web developers trying to create a simple web application that needs globalization support. What do we do? Simple. We include libraries that allows us to do so and job’s done.

Everything looks fantastic until we go show our amazing progress to our boss and he says: “this is wrong…”.

When that happens (when we spot a bug) well, we get the chance to know our libraries a little better. Anyway we don’t have much choice other than either (a) figure out what’s wrong and fix it, or (b) file a bug.

On Globalize, we had a bunch of bugs. Interestingly, one third have all the same root cause: i18n content, or more precisely, having wrong or outdated i18n content embedded into our code. For example, a wrong month name or wrong day name. This bug affects all sorts of locales and all sorts of functionalities. The list goes on and on. Reviewing those bugs was really tricky, because we at jQuery know JavaScript. But, very little about the several other languages.

At some point, the reviewing process was to look & use what’s in CLDR. So, we asked ourselves why not to replace our database and use CLDR instead? This is when I got first introduced to Globalize. By that time, this bug was opened for 8 months and it wasn’t one, but two big issues we were trying to solve: (a) we were managing the content ourselves, and (b) the source initially chosen, which was .NET, turned out to have big problems.

When I was first digging into this bug, discovering what CLDR was and how we could change Globalize to use it, my initial concern was how that change would affect our locale coverage and our current functionality. But, for my happiness I figured that by adopting it, we would actually double the locale coverage and we would also fix all the functionality issues we had so far. It was simply
amazing.

Ok! In order to address that whole bunch of bugs at once, we are convinced to rewrite the whole library to conform with CLDR (with TR#35). But, we are also convinced we have a second challange to solve, embedded content. Or tomorrow, we’d end up with unhappy developers again complaining about outdated CLDR or wrong CLDR. We didnt want to simply rename our problem. But, we wanted so solve it.

Before creating something new. Let’s research. What about other libraries? After all, we are not alone in the world. Do they have this problem? If not, how do they solve it?

Let’s start with twitter-cldr. It’s based on CLDR obviously as its name suggests. But, it embeds CLDR data in the code as we unfortunately did as well. Do they get the same sorta bugs we had? Let’s see an example. Developer filed a bug about wrong date formatting in the Italian language, which has been fixed in CLDR 26. But, hasn’t been fixed in twitter-cldr (by the time of this talk). To give a rough idea of the timeline we’re talking about, after 43 days since developer has first reported this bug, it was fixed and published by CLDR. At the day of the talk, it was 91 days and the bug was still opened.

Next, angular.js. It’s based on CLDR. Actually, it pulls data in from Google Closure, which in turn is based on CLDR. Looking its master code (at the day of this talk), it presented the same Italian bug that we just saw.

Here, I’ve picked one existing bug as an example. But, there are more, an easy way to find them is by looking at CLDR changelogs.

Not to mention the bugs that are still open on CLDR. For example, the plural one I used as an example earlier on (shown in my slide). It seems so basic. But, it’s real and it happens today on CLDR 26. But, for the Brazillian Portuguese language.

The surprising fact is that all the mainstream globalization libraries for JavaScript run into the same problems as we, jQuery, have.

What usually happens is that we, again speaking as a developer, cannot wait indefinitely for those bugs to get fixed and land upstream ~~boss yelling~~. Occasionally, we fix them locally. Yay. Is it ideal? Some people may say “it works for me”. Although, keeping a local custom modified library has its drawbacks. As soon as a new update pops up and we download it. We lose our previous fixes. Unless we
keep a list of patches that we can re-apply over and over and, hopefully, not get any conflicts while doing so.

This is definitely not a good maintenance perspective over time. So, what could be done instead? At Globalize, we thought a solution should cover three simple points:

1. It should leverage the official CLDR JSON. Because, (a) processing JSON on
JavaScript is lighter. (b) It’s distributed by Unicode. It’s official. We believe developer should be able to say: “Globalize (or google Closure, format.js), here is my CLDR data, use it”.

2. It should allow developers to load as much or as little data as they need. For example, when formatting numbers, we don’t need the plural rules obviously. We don’t even need lots of the number fields themselves. It depends on a case by case basis.

3. Avoid duplicating data between libraries. If a developer uses two number libraries, one for formatting and another for parsing. For example, ecma-402 polyfil and Globalize. Both should be able to use the same shared number data.

The intriguing question is: if this is so good and obvious, why hasn’t anyone done this yet?

I don’t know the answer to this question. But, there’s one fact I haven’t mentioned yet. The first appearance of a CLDR in the JSON format actually happened on CLDR v23, which happened on 2013. And, by that time all these libraries already existed. So, all have an excuse. But, no more.

Welcome to the new Globalize. It has been rewritten to address all the previous three points. It’s designed to work both in the browser and in Node.js. At jQuery, we systematically test it against desktop and mobile browsers (versions listed in the slide). It supports AMD and CommonJS module loaders.

On the rewrite, we’ve split the former monolithic library into individual modules. On date module, we find date formating/parsing. On number module, we find number formating/parsing. And, so on… All the functional verticals lie onto the Globalize core, which works as a base layer. Note we have no more content embedded into our library. The CLDR content is treated as a peer dependency. Also, note that throughout the Globalize code, we manipulate CLDR: we instantiate locales, we traverse CLDR paths. Some of these operations are not that trivial <likelySubtags example?>. Therefore, we’ve wrapped that code into cldr.js. So, we (a) keep Globalize focused on the i18n functions only, (b) allow other libraries to scaffold and build themselves on top of the same foundation we do. ~~layers topology~~.

Cldr.js is a low level library, whose only purpose is to help to manipulate CLDR. So, it’s really cool to develop your i18n library not needing to worry about that.

Like Globalize, it’s designed to work both in the browser, or in Node.js. It support AMD and CommonJS.

It’s unopiniated on how user should load CLDR data. There are dozen of ways. All we expect is the JSON. So, developer can fetch the data dynamically if he will. He can use AMD plugins. Node.js require. Or any imaginable way.

Globalize uses Cldrjs load method under the hoods, so Globalize works the same way.

It automatically deduces subtags using CLDR algorithms specified by CLDR docs. These variables then are automatically used when traversing the tree to get an item.

Those are the most important features, but there are more.

We’ve talked about the benefits of having CLDR as a separate thing. But, this approach inevitably introduces one extra step for developers: to download the CLDR data themselves. Who likes extra steps?

How can we ease this initial ramp up? More importantly, how does developer know he has the right CLDR version compatible with the libraries he’s using?

Libraries need a way to declare its CLDR peer dependency.

We at jQuery use bower and npm to manage our library dependencies. Can we use this same tools to manage CLDR peer dependency as well?

Yes, we created a package called `cldr-data` for both: npm and bower. It works the lightest possible way we could imagine it. It doesn’t actually mirror any data. But, it manages the zip urls, and as a post-processing step it downloads the right link and unpack it.

If you develop a globalization library, or plan to, consider scaffolding it on top of cldr.js and cldr-data.

Let’s start to see some action. The demo I’m about to show you is going to do three things: (a) fetch globalize, (b) fetch cldr data in the json format and (c) run some Globalize code on Node.js.

We can use npm to install all that. If you are not familiar with npm, it’s the Node.js package manager and is commonly used by Node developers. Installing globalize also installs its both dependencies: cldrjs (the base library) and cldr-data (the node module that pulls in the CLDR data in the json format from the Unicode servers)

We’re all set. Let’s use Globalize. Start using right ahead makes it complain about missing CLDR data.

We developers need to feed Globalize with the proper CLDR JSON files. Here, I’m using cldr-data package. It’s optional. We pass in only the content we need. Oh, but which ones do we need? If you need help figuring it out, see the table in our docs. Then, use it.

Let me show you how easy it is to manage the CLDR content. “User has the power”. Do you remember the italian bug we saw earlier on, which affected twitter-cldr and  angular.js? Let’s reproduce it by using CLDR version 25. Note the problem is the usage of `/` (wrong) instead of ` ` (correct).

Do you want to fix it and move to the next level? Yes. Note that using CLDR version 26 is enough to fix the problem. We don’t need to update our JS library or application code.

Do you remember the Brazillian Portuguese plural bug, which is currently present on CLDR 26? Let’s reproduce and fix it? In Brazillian Portuguese, the plural form of 0.5 is not other, but one.

There’s no CLDR 27 yet. But, let’s set the right rules ourselves and retry. Tchara! Fixed! Note, we were able to fix it dynamically on user code.

The same thing works on browsers as well. We can use bower package manager, which is commonly used on client applications.

Please, find examples using these various environments (bower, AMD or node.js) in Globalize docs.

What about performance? I’m advocating a library that traverses the CLDR tree and parse rules dynamically at runtime, which is totally fine during development. But, what about production? Is there any optimization?

When formatting a number, there’s actually a two step process: (a) setup and (b) execution, where setup takes considerably more time (is a lot more expensive than execution). The runtime difference is an order of magnitude.

Note that the same is also true for date formatting, message formatting, or even parsing all of them.

So, an obvious way to speed up iterations in your code is to generate the formatter outside the loop. The same idea is valid for server applications, we probably want our formatters to be created in advance, so when requests arrive, we can process them quickly by simply executing the formatter. Obviously, this is a simple demonstration. Usually, an ICU Message Format goes here instead in a real world application, a number format would be an input for a templating engine like mustache, handlebars. But, all follows the same idea.

Another distinction between the setup and execution is that all CLDR manipulation happens during setup, which can be really handy. For example, any missing CLDR error will be thrown as soon as the server is started in this example. So, all subsequent client requests are safe from any CLDR manipulation error.

Let’s talk a bit about client application. On client side, performance is also about how fast our page loads. So, size matters. How to get the smallest and leanest bundle for production?

Let’s see an example. Suppose we need a plural function for English. This is what we need. A function that given a number, outputs the plural form. But, in order to get that, we need the English plural rules and the library code to parse that rules in order to generate this simple function. In the end, this tiny thing is what matters. What if we could precompile that at build time and deploy only this tiny function. The good news is that it’s possible. All our formatters/parsers output the precompiled function. So, by managing that at
build time, we can remove the need for most of the library at runtime.

The plural function is an extreme example. But, we often can save bytes formatting or parsing other stuff too.

If you are familiar with templating engines like Handlebars, the idea of deploying precompiled bundles may sound familiar.

You know, what’s most important about this whole story is that we didn’t do it all ourselves. We’ve been systematically collecting feedback on every aspects of our idea and our implemention. Part of the solution is contribution from Wikipedia, part from Alex Sexton, part from people all over the internet.

The jQuery foundation has a mission that goes beyond supporting the development of our products. It’s about supporting three things.

Improve the open web, which means, having open standards publicly available and free to implement. ~~An open web~~

Make web accessible for everyone, it means including people with disabilities and people living in poor conditions. ~~An accessible web~~

And, ~~Collaboration with the development community~~.

“One thing that really struck me during my limited research was how many overlapping libraries there are especially for number and date-time formatting”

Norbert Lindenberg, the creator of ECMA-402 (the standard Internationalization API for JavaScript) said an year ago. It happens this is still true.

We have been in contact with lots of people in different organizations. As an effort of improving the coordination and potentially the collaboration between projects, we’ve created a common channel for communication. Hopefully, with the joint effort of this group, we’ll make this whole farm more productive.

It’s a very recent initiative. But, it’s already been used for annoucements of new accomplishments and we’re collaboratively producing a comparison grid to help clarify the differences, the gaps, the strenghts and weekness of each different projects.

All libraries that I’ve showed are functional. They work. So, feel free to use it. I hope you enjoy it. File bugs if you find any trouble. We really listen to what you say. Help us to design, implement, and test it. Collaborate with us. Join us.

Thank you

jQueryUI 1,000,000 custom downloads every quarter

I’ve been helping jQueryUI to port its DownloadBuilder into node.js. The rewrite is actually live and serving downloads since Oct/2012.

Today, I wrote my very first post in the jQueryUI Blog with insights into what we’ve built, and the trends we’ve noticed so far.

Good reading… (original at http://blog.jqueryui.com/2013/04/1000000-custom-downloads-in-four-months/)

We surpassed the millionth download of jQuery UI using our recent DownloadBuilder and ThemeRoller rewrite back on February. As of today, we have served 1,730,000 downloads and counting. Read on for some insights into what we’ve built, and the trends we’ve noticed so far.

The former server-side code was written in PHP. It’s been rewritten in JavaScript and runs on node.js, and it is much more integrated with jQuery UI release process overall. The client-side has been rewritten as well, although we didn’t make any big changes to the UI/UX.

On the client side, despite the few visual changes, we have some interesting updates. The DownloadBuilder now remembers what user selects and makes it linkable, so it’s easy to share or go back and modify a custom theme. We’re also shortening links automatically if they get too big, by zipping parts of the query string.

The backend in-memory-caches the source files and theme images to speed up the downloads. Since it serves custom downloads, the parts are not simply assembled, but rather modified on build-time and then assembled. The average build & package time is 1.3s.

The download traffic is pretty uniform and constant; we hit an average of 66,000 downloads per week, having more traffic during the weekdays and less traffic during the weekends. When we publish a new release, we see a 10% increase on traffic. Adoption of the new release is really fast, legacy downloads drop virtually immediately. Although, we still have a significant amount of 1.9.x downloads after the 1.10.x release, splitting the total as chart shows below.

Downloads per version

29% of users download the default components with the default theme. Other than that, we have all sorts of custom combinations happening. They choose different components, different themes, or a mix of both.

Among the component customizations (which represent 26% of all total downloads), 15% are only Datepicker (the winner by far), followed by No Components (8.5%), which packages the theme only, Autocomplete (4.5%), Dialog (4.25%), and Tabs (3.75%).

Custom component selection
Datepicker

– Datepicker and its dependencies

– Datepicker, mouse and position

14.95% (4.34% of all downloads)

– 12.72% (3.69% of all downloads)

– 2.23% (0.65% of all downloads)

No components (theme only) 8.55% (2.48% of all downloads)
Autocomplete and its dependencies 4.53% (1.31% of all downloads)
Dialog only 4.25% (1.23% of all downloads)
Tabs only 3.77% (1.09% of all downloads)
Accordion only 2.91% (0.84% of all downloads)
Slider only 2.58% (0.75% of all downloads)
All, but effects 1.87% (0.54% of all downloads)
Core components (no widgets or interactions) 1.60% (0.46% of all downloads)
Sort interaction only 1.37% (0.40% of all downloads)
Interaction and core (no widgets) 1.33% (0.38% of all downloads)
Draggable interaction only 1.22% (0.35% of all downloads)
Effects only 1.05% (0.30% of all downloads)
Tooltip only 1.04% (0.30% of all downloads)
The core component (solely) 1.02% (0.30% of all downloads)
total 100.00% (26.37% of all downloads)

 

Theme customizations (choosing something other than the default UI Lightness theme) represent 57.5% of all downloads. If we skip the base theme Smoothness too, theme customizations are actually 42.35% of all total downloads. 16% of all downloads are user created themes (Custom Themes), followed by the Redmond (4.86%), UI darkness (2.73%), and Start (2.38%) themes.

Within the users that create a Custom Theme, the majority of users (77%) download the full “all components” bundle, 5.5% download it with no components (theme only), and 17.5% do it with a custom component selection.

Themes
(top 11)
Default Component
Selection
Custom Component
Selection
UI lightness (default theme) 38.76% (28.53% of all DLs) 53.20% (14.03% of all DLs)
Custom Theme 17.10% (12.59% of all DLs) 14.11% (3.72% of all DLs)
Smoothness (base theme) 16.34% (12.03% of all DLs) 11.64% (3.07% of all DLs)
Redmond 5.13% (3.77% of all DLs) 4.13% (1.09% of all DLs)
UI darkness 2.80% (2.06% of all DLs) 2.54% (0.67% of all DLs)
Start 2.60% (1.91% of all DLs) 1.78% (0.47% of all DLs)
Cupertino 2.42% (1.78% of all DLs) 1.97% (0.52% of all DLs)
Blitzer 1.58% (1.16% of all DLs) 1.29% (0.34% of all DLs)
Flick 1.44% (1.06% of all DLs) 1.52% (0.40% of all DLs)
Sunny 1.41% (1.04% of all DLs) 0.91% (0.24% of all DLs)
Dark Hive 1.17% (0.86% of all DLs) 0.72% (0.19% of all DLs)
total 100% (73.63% of all DLs) 100% (26.37% of all DLs)

 

Thanks to clark and Splunk for helping us make sense of all this data!

As usual, if you find any bugs or if you have any ideas on how to make the DownloadBuilder or ThemeRoller even more amazing, we’d love to hear from you! But please, don’t use the comments, rather please file an issue here.

I want to become an entrepreneur, where do I start?

Oliver Emberton, Founder of Silktide has been top voted in Quora for his stunning answer. Echoing it below.

You don’t need qualifications, money, a planet-sized-brain or even a particularly good idea. All an entrepreneur ever does is create something that consistently makes money.

Think of a company as a machine you design and build. Here’s McDonalds:

Your ‘machine’ always has certain parts. It sells something to someone, and re-invests some of that to help make more sales in future. What’s left over is profit for the owners. Here’s Google:

If you can design, build, own and care for such a machine, you can become very rich indeed. That doesn’t mean it’s easy, but most of the barriers that you think will stop you won’t. Interested?

Let’s talk about you

Are you young, poor, unqualified – a student, or hating your job? Maybe a touch rebellious? Perfect. You have no bad habits, and will work until your fingernails fall out and your eyeballs roll onto the desk. The world awaits you.

Older, wiser, bit of money saved, experienced with a stable job? Maybe a mortgage and kids? Your job is much harder. It can be done, but it might feel like you’re trying to dance backwards through quicksand.

The most important qualities of a good entrepreneur are energy and determination. It doesn’t hurt to be persuasive, but this can be learned. I started as a shy uber-nerd aged 21; I soon learned how to sell when it was the only way to feed myself.

Enough preamble. Let’s make you a bajillion dollars:

The idea

Please forget all of the terrible deluded nonsense you’ve heard about the value of ideas. Ideas are cheap, fleeting things; by itself a business idea is worth less than a half-eaten sandwich. At least you can eat the sandwich.

You do need an idea of course. But understand that even the most successful companies were not founded on wild or brilliant ideas. Starbucks chose the brazen path of selling coffee in Seattle. Facebook built a better MySpace. Google built a better Yahoo search. Microsoft copied Apple – who copied Xerox.

Original ideas are overrated. What isn’t overrated is timing. Google chose the perfect time to build a better search engine – good luck trying to do that now *cough* Bing *cough*. What you want, therefore, is an astute awareness of a need that is currently underrepresented in the market. You want to spot a product or service that can go places – original or not. It’s usually easier to refine an existing idea that isn’t fully realised than to create a wholly original one.

People fear setting up a business wherever there’s competition, but competition can be a good thing. The best place to setup a new restaurant is right next to another successful restaurant; they’ve kindly done the hard work for you of building an audience. Many a good business has ridden to success on the coattails of another – it is usually better to have some rivals over none. You just need to become 10% better.

I personally recommend trying to deliver something that you and your friends would buy in a heartbeat. You’ll know more about your field, you’ll understand your customers, and you’ll be passionate about what you do. If you can make your company about a why – not a what – you’ll inspire yourself and those around you. And to survive the next step, you need a fair sprinkle of inspiration:

Starting

Starting a company is a bit like parenting; everyone assumes you know what you’re doing, but babies and companies don’t come with instruction manuals. You stumble through it, learning as you go.

It’s at the start where you’re most likely to fail. Your aim is to build that magical money-making machine, but you probably don’t have all the parts and the ones that you need may cost more than you have. Your idea is probably at least half wrong too, but you won’t know which half yet. All of this is normal.

A big part of starting a company is convincing people to believe in you before they probably should. When Steve Jobs founded Apple, he had no money and no customers; what he did next is the hallmark of a great entrepreneur. First he convinced a local computer store to order his non-existent Apple computers, with payment on delivery. He then convinced a parts supplier to sell him the components he needed to build them – using the order he just obtained as proof he would be able to pay them back. Jobs and a small team worked in their garage to build the first computers, delivered them on time and made a tidy profit. Apple was born from nothing.

Most new entrepreneurs play a few gambits early on like this. If it sounds scary, that’s because it is. I once had to pay staff salaries on my heavily burdened credit cards when an early order fell through. You fake it until you make it.

While doing all this you need to juggle between making the perfect company (idealist) and paying your bills (realist) – an absence of either will eventually kill you. I believe it’s one reason why realist / idealist partnerships are so common in business.

Do not scale prematurely. Don’t try to be a big company early on – just aim to be one. Be slow to spend and to hire at first. Don’t waste time writing mission statements and policy documents. You’re small, nimble and on a mission. Make and sell things. There’ll be time for a HR department later.

Don’t be surprised if you change your company entirely. It’s a rare business that survives first contact with its customers. Try to avoid doing this more than once though, it doesn’t pay well.

Survive long enough, reinvest your meagre successes and compound them. Eventually, you can move on to:

Extracting yourself

This is the step most small businesses never accomplish.

Up until now, your magical business machine almost certainly contains one irreplaceable part: you. If your background is accounts, you’re probably the head accountant. If you’re a programmer, you’re probably the best coder. Whatever you do, chances are you’ll feel essential and somewhat overworked.

Here’s the hard part: you need to make yourself redundant. If you dropped dead tomorrow, your business should carry on working just fine. All of your time needs to be spent working on your business, not for your business. The alternative is you’re basically self-employed with assistants.

Some businesses can’t escape this trap. If you’re a brilliant copywriter – say – you’ll struggle. It’s because what makes you a great company is you, and unless you can bottle up you into a business model, you can’t grow.

McDonalds built a business that works even if they hire almost entirely minimum wage workers. Their process makes it work: every burger is efficient and nearly indistinct, and nothing is left to chance. Their brand is so strong people line up worldwide to eat there. Your business may be radically different, but it should be similarly robust.

If you accomplish this, you now own something that is self-sustaining. You should be able to pull a good salary even if you never go into work. Your time is now free to tweak your business endlessly into something better. Now to conquer the world, all you need to do is:

Scale

The final step is a bit like playing Who Wants to Be A Millionaire. Each question you get right doubles your money, or you’re going home.

Do not make the naive mistake of assuming a big company is like a small one but bigger. Oh, nevermind. That’s like telling your kids to listen to you, really, drinking doesn’t make you cool. You’ll learn the hard way.

As a company grows the rules and your culture change completely. You may even find yourself disliking the company you created (many founders feel conflicted like this, eventually). If you’ve made it this far, you have many options: hire help, sell, or double-down and see where the ride takes you.

Remember no business can grow indefinitely. Most industries are more efficient at different sizes – it’s easy to be a two-man plumbing company, but near impossible to build a 1,000 man plumbing corporation. Know the limits of yours well in advance. Software is an example of an industry that scales exceedingly well, which is why it creates so many young billionaires.

And finally

It’s never been easier to start a company. You can create a killer product in your student dorm without even registering any paperwork – that was enough for Facebook.

I think entrepreneurship is a form of enlightened gambling. Skill and tenacity are big factors, but luck plays a big part. However, as long as you can keep picking yourself up when you get knocked down, try different things and keep learning, the odds are in your favour. You just have to dare to chance them.

What is the best way to prepare yourself for entrepreneurship?

The ugly truth… from Balaji Viswanathan, Ex-Developer at Microsoft Redmond at quora.

1 ) Cut your spending to a bare-minimum. Learn how to live frugally (even if you don’t want to start living like that right now). In a startup life, a lot of times you have to figure out ways to cut down spending, to improve your survival rate. Learn how you can do that now. If you have figured how to live 12-18 months without a paycheck, you are on your way.

2 ) Build networks. Keep meeting people on local entrepreneurship meetups & other events. You never know who among those will give you the lifeline at the right time.

3 ) Learn sales & marketing. Your startup’s future depends on it. You have to learn ESPECIALLY if you are an engineer. You just can’t think that you will hire someone who will automagically sell stuff for you.

4 ) Build your savings. The one who has gold in his pockets sets the rules, in a startup.

5 ) Figure out the top 5 things you want to do in your life and do it NOW (if you can). In a startup life, you won’t have time to do them. By doing them before, you will have less regrets starting up on your own. You can always convince yourself that you did those things that many of your peers (who are still making that hefty salary) have not done.

6 ) Watch inspiring movies. I watched the entire list here: http://en.wikipedia.org/wiki/AFI’s_100_Years…100_Cheers When you watch movies such as Stand & Deliver or Life is Beautiful, you get a different perspective in life. This will be really helpful when you are under pain and just want to give up (this situation is more likely than you imagine).

7 ) Do something adventurous (such as hike the Grand canyon from north to south side, a 5-day camping in Central America or volunteering in Africa). You will learn teamwork, withstanding pain and taking the right level of risks. I know many who use their hiking/camping lessons in startups.

8 ) Meet family, friends and attend parties. After you start up, you will get in your bunker and meet people only when they can generate a business lead. You won’t have any time for personal life in the first 2 years.

9 ) Mentally prepare yourself and your spouse (if you are married) to look for the long term gains to overlook the short-term pains. The spouse needs to be strong to enable you to run your business.

10 ) Ask yourself if you are really in it for the money. If yes, you will be disappointed as statistically you will make a lot less than what you could in a big corp. On the other hand, if you are in it for creativity, satisfaction and adventure, you will be able to withstand the long pause without funding.

Finally remember that reading a swimming book is very different from getting on to water. No amount of reading books will actually prepare you for what you are going to face. Ready to embrace the fun and unpredictable turns.

Original: at quora.