I am not a frontend developer, just stumbled upon this problem helping out my friend to set up a website that is supposed to serve multi-language content based on the language setting of the user. This is actually an interesting problem (maybe already solved and I did not know).
There are several different solutions that I found through after doing some study:
- Server side detection based on Accept-Language request header.
For example, apache mod_negotiation allows you to define a set of html pages in different languages (index.html.en, index.html.zh, etc.) and based on the user preferences from Accept-Language header, apache picks the right index.html language page to return.
You can also use mod_rewrite to perform the similar trick. Just set up the rewrite condition based on the value of the AL header and map to the correct language.
- Client side detection and action using JavaScript and navigator object.
In IE, navigator.userLanguage returns the operating system region and language setting, in Firefox, Opera, Safari and Chrome, navigator.language returns the browser application language setting. So, we can use them to get the user language and decide what language content to return.
For example, this code snippet (borrowed from an example on jsfiddle) defines multi-language content on the same page and use JavaScript to show or hide it based on the detected language.
The drawback of this approach is that a large part of the content is not needed and invisible. It is a waste of time to download.
Another approach is to use JavaScript to redirect to individual language content pages using window.location.href="redirected_page_url" or window.location.replace("redirected_page_url"). See Location object for more details on how to use them. The downside is this approach may not be search engine friendly (spiders may not be able to follow redirection).
One last note how to test multi-lang website. I tried in Firefox, simple change the language ranking in Preferences->Content Tab->Language Choose button and FF will start sending different Accept-Language headers based on the ranking. You can also play with the operating system language settings.
Friday, July 22, 2011
Monday, June 13, 2011
node.js testing frameworks
There are so many testing frameworks for node.js, start to evaluate some most mentioned/used ones. Criteria that I am looking for:
- easy to understand concept and constructs
- nice support for async calls and flow control
- easy integration with CI tools such as Hudson
- code coverage report
- mocks and stubs
- Vows+APIeasy
- Expresso+node-jscoverage: really like its code coverage feature
- YUITest: somehow had issues writing async operations in setUp and tearDown, also had issues using flow control libraries such as async inside each test
- Jasimine: very clean and easy to understand concept and constructs
- Nodeunit: a detailed tutorial from the author
- node-qunit+jscoverage, qunit is used for JQuery testing and has fairly good async support, here is a fairly detailed article for async testing with qunit
- testosterone+gently
- Sinon.JS
Among those, I like Jasimine most, it is easy to understand and has rich feature set. The only feature missing is lack of code coverage report. jasimine-reporters supports output of JUnit format unit test results. jasimine-node brings Jasimine to node.js. You can check out "Testing Backbone applications with Jasimine and Sinon" for a practical example.
Sunday, June 5, 2011
dealing with multiple nesting callbacks in asynchronous code
If you are annoyed that you have to write multiple nesting asynchronous callback functions when you work with Node.js, you are not alone. Getting used to the asynchronous programming style and always keep in mind everything runs in the event loop is a bit tricky at the beginning.
There are many libraries and articles that addresses this nesting callback issue. This should help you to avoid those ugly pyramid shaped code now ;-)
InfoQ: how to survive asynchronous programming in JavaScript (includes a list of libraries with comparisons and Q&A from their developers)
Stackoverflow post about how to deal with the nesting callbacks (also includes a list of libraries)
Isaacs's presentation on the topic and his library Slide (he is the author of npm)
Tim Caswell (creationix)'s series on control flow in Node (II and III can be found on the right column, other articles by the same author)
CommonJS Promises is another way trying to address this issue by defining a standard interface for interacting with the result object of asynchronous actions. Roughly speaking, a promise object is a placeholder for the value for the asynchronous action. And you can treat is as normal object, assign values to another variable, pass it around, etc. Right now, FuturesJS implements this and it is not solely for server-side JS. dojo.Deferred is another similar effort. This SitePen blog post has some easier to understand coverage about the promises.
StratifiedJS extends the JavaScript language to achieve similar goals of allowing asynchronous control flow to be expressed in a synchronous way. Very neat work indeed. This is a short overview presentation about it.
There are many libraries and articles that addresses this nesting callback issue. This should help you to avoid those ugly pyramid shaped code now ;-)
InfoQ: how to survive asynchronous programming in JavaScript (includes a list of libraries with comparisons and Q&A from their developers)
Stackoverflow post about how to deal with the nesting callbacks (also includes a list of libraries)
Isaacs's presentation on the topic and his library Slide (he is the author of npm)
Tim Caswell (creationix)'s series on control flow in Node (II and III can be found on the right column, other articles by the same author)
CommonJS Promises is another way trying to address this issue by defining a standard interface for interacting with the result object of asynchronous actions. Roughly speaking, a promise object is a placeholder for the value for the asynchronous action. And you can treat is as normal object, assign values to another variable, pass it around, etc. Right now, FuturesJS implements this and it is not solely for server-side JS. dojo.Deferred is another similar effort. This SitePen blog post has some easier to understand coverage about the promises.
StratifiedJS extends the JavaScript language to achieve similar goals of allowing asynchronous control flow to be expressed in a synchronous way. Very neat work indeed. This is a short overview presentation about it.
Friday, May 13, 2011
get rid of annoying ._filename working with TextMate on a mounted NFS
Just had this annoying experience of working on an NFS mounted file system with TextMate. Basically, it tries to store metadata such as cursor position, etc. into metadata files. Since these mounted file system does not support extended attributes, so OSX instead writes to ._filename, which is really annoying since the directory is under version control and you see many of these metadata files showing up.
After poking around, I figured out how to turn this metadata feature off, yes, I lost a bit convenience feature, but no more cleanup of these ._filename anymore!
References: TextMate Expert Preferences
After poking around, I figured out how to turn this metadata feature off, yes, I lost a bit convenience feature, but no more cleanup of these ._filename anymore!
defaults write com.macromates.textmate OakDocumentDisableFSMetaData 1
References: TextMate Expert Preferences
Saturday, April 23, 2011
Hello, Cloud Foundry running node.js
Contrary to most people's view on the Amazon cloud outage incident, I believe this actually shows the power and outreach of the cloud computing. The technology needs some time to mature and become reliable, let's just be patient. It is very exciting to see even big sites like reddit, quora was affected, and even the cloud service provider Heroku was one of the victims.
There are many new players in the cloud computing field and Cloud Foundry from VMWare is definitely a very disruptive force to the current market. Currently, it supports Spring for Java apps, Rails and Sinatra for Ruby apps, JVM frameworks like Grails and Node.js! Best of all, the whole platform is open sourced.
CF provides a Micro Cloud for individual developers, for free now ;-) This is how to get a helloworld node.js app running:
1. Preparation
- Sign up for the free Micro Cloud for Cloud Foundry (http://www.cloudfoundry.com/).
- Wait a few days (mine took 9 days) and you will receive an approval email.
- Cloud Foundry uses a CLI tool called vmc for interactions with your Micro Cloud instance. Follow the instructions and use the credentials in the approval email to set up vmc (see "vmc getting started guide", really wish it is available not only in PDF format).
2. Write a helloworld node.js app
As of this writing, CF supports node.js-0.4.5 (use "vmc runtimes" to find out). The only thing that is different in the CF environment is that the system will assign a host and port to your application. CF adds several environment variables accessible through process.env.
For our helloworld, we are interested in VCAP_APP_HOST and VCAP_APP_PORT (there are also VMC_APP_HOST and VMC_APP_PORT, which seems still exist but will be deprecated).
So, you basically create a directory (I use the same appid as the directory name) and create an app.js for hello world like this:
3. Deploy using vmc
The very first time you deploy the app, you run "vmc push <appid>". Note that you need to pick an id that is not being used, otherwise, you will get an error. It would be really nice for CF to provide a Web UI to check what appid is still available. You just follow the instructions and see the output. If everything goes well, you will see your app running at http://<appid>.cloudfoundry.com/.
To update your app, you need to run "vmc update <appid>" instead of "vmc push <appid>". You can also delete your app using "vmc delete <appid>".
vmc CLI provides many operations, "vmc -h" is your best friend to find and try them out.
4. Add npm module dependencies
In most cases, you will need to use dependent NPM modules such as Connect, Express, etc. With the current node.js 0.4.5 supported on CF, it is very straightforward.
- You create a package.json that defines your app/module with dependencies.
- Then you run "npm bundle", which creates a node_modules directory with all the required NPM modules.
- Finally, you do "vmc update <appid>" and you are done.
Here is a quick sample:
package.json
app.js
dir structure:
5. To learn more
I will try to update this helloworld guide and add a bit about bundling dependent npm modules. To learn more about Cloud Foundry, read the CF blog and code, since it is open sourced, you can simply install it from github.
Updated: found a recent post about using MongoDB on cloudfoundry ;-)
There are many new players in the cloud computing field and Cloud Foundry from VMWare is definitely a very disruptive force to the current market. Currently, it supports Spring for Java apps, Rails and Sinatra for Ruby apps, JVM frameworks like Grails and Node.js! Best of all, the whole platform is open sourced.
CF provides a Micro Cloud for individual developers, for free now ;-) This is how to get a helloworld node.js app running:
1. Preparation
- Sign up for the free Micro Cloud for Cloud Foundry (http://www.cloudfoundry.com/).
- Wait a few days (mine took 9 days) and you will receive an approval email.
- Cloud Foundry uses a CLI tool called vmc for interactions with your Micro Cloud instance. Follow the instructions and use the credentials in the approval email to set up vmc (see "vmc getting started guide", really wish it is available not only in PDF format).
2. Write a helloworld node.js app
As of this writing, CF supports node.js-0.4.5 (use "vmc runtimes" to find out). The only thing that is different in the CF environment is that the system will assign a host and port to your application. CF adds several environment variables accessible through process.env.
For our helloworld, we are interested in VCAP_APP_HOST and VCAP_APP_PORT (there are also VMC_APP_HOST and VMC_APP_PORT, which seems still exist but will be deprecated).
So, you basically create a directory (I use the same appid as the directory name) and create an app.js for hello world like this:
var http = require('http'),
port = Number(process.env.VCAP_APP_PORT || 3000),
host = process.env.VCAP_APP_HOST || 'localhost';
http.createServer(function (req, res) {
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end('Welcome to Cloud Foundry!\n' +
host + ':' + port + '\n' +
require('util').inspect(process.env, false, null));
}).listen(port, host);
console.log('Server running at http://' + host + ':' + port + '/');
This simple app just prints out "Welcome to Cloud Foundry!" and a bunch of environment variables ;-) Note that we put localhost and 3000 there so that it is easier to debug the app on a local node.js installation.3. Deploy using vmc
The very first time you deploy the app, you run "vmc push <appid>". Note that you need to pick an id that is not being used, otherwise, you will get an error. It would be really nice for CF to provide a Web UI to check what appid is still available. You just follow the instructions and see the output. If everything goes well, you will see your app running at http://<appid>.cloudfoundry.com/.
To update your app, you need to run "vmc update <appid>" instead of "vmc push <appid>". You can also delete your app using "vmc delete <appid>".
vmc CLI provides many operations, "vmc -h" is your best friend to find and try them out.
4. Add npm module dependencies
In most cases, you will need to use dependent NPM modules such as Connect, Express, etc. With the current node.js 0.4.5 supported on CF, it is very straightforward.
- You create a package.json that defines your app/module with dependencies.
- Then you run "npm bundle", which creates a node_modules directory with all the required NPM modules.
- Finally, you do "vmc update <appid>" and you are done.
Here is a quick sample:
package.json
{
"name": "helloworld-node",
"version": "0.0.1",
"dependencies":
{
"connect": "*"
}
}
app.js
var connect = require('connect');
connect.createServer(function(req, res) {
var body = 'hello, cloud foundry';
res.setHeader('Content-Length', body.length);
res.end(body);
}).listen(process.env.VCAP_APP_PORT || 3000);
console.log('connect server listening...');
dir structure:
app.js, package.json, node_modules
5. To learn more
I will try to update this helloworld guide and add a bit about bundling dependent npm modules. To learn more about Cloud Foundry, read the CF blog and code, since it is open sourced, you can simply install it from github.
Updated: found a recent post about using MongoDB on cloudfoundry ;-)
Tuesday, April 19, 2011
Free ebooks and tutorials for PHP, JavaScript and Ruby Beginners
Thursday, April 14, 2011
interesting node modules
There are so many node modules out there to the point that sometimes you can have several different ones that appear to solve the same problem.
node.js on GitHub has a list of classified node modules, but still it is quite difficult to pick the best one (in terms of node version compatibility, easy to use, still actively developed, good performance, etc.).
It would be really cool to have some sites that actually give reviews and code samples of using these node modules. If performance comparison can be provided, that is even better.
Inspired by "6 Must Have Node.js Modules", I am listing the modules that I found quite interesting and useful to the current work:
HTTP clients:
XML to object conversion:
Image processing:
node.js on GitHub has a list of classified node modules, but still it is quite difficult to pick the best one (in terms of node version compatibility, easy to use, still actively developed, good performance, etc.).
It would be really cool to have some sites that actually give reviews and code samples of using these node modules. If performance comparison can be provided, that is even better.
Inspired by "6 Must Have Node.js Modules", I am listing the modules that I found quite interesting and useful to the current work:
HTTP clients:
XML to object conversion:
- node-xml2js, a fairly lightweight and fast xml to object conversion library
- node-expat, a very high performance SAX lib, native binding to libexpat, it has a fork with object conversion support
Image processing:
- node-canvas: canvas implementation based on Cairo
- node-qrcode: QR code generator
Subscribe to:
Posts (Atom)