From 573d45890f091405ab3286b69468d2f8c8191f75 Mon Sep 17 00:00:00 2001 From: Chandra Sekar S Date: Tue, 27 Jul 2010 17:23:54 +0530 Subject: [PATCH] i18n support. --- examples/i18n/grasshopper | 1 + examples/i18n/index.html | 8 ++++++++ examples/i18n/locales.js | 21 ++++++++++++++++++++ lib/ghp.js | 13 +++++++------ lib/grasshopper.js | 4 +++- lib/i18n.js | 41 +++++++++++++++++++++++++++++++++++++++ lib/renderer.js | 14 ++++++++++--- 7 files changed, 92 insertions(+), 10 deletions(-) create mode 120000 examples/i18n/grasshopper create mode 100644 examples/i18n/index.html create mode 100644 examples/i18n/locales.js create mode 100644 lib/i18n.js diff --git a/examples/i18n/grasshopper b/examples/i18n/grasshopper new file mode 120000 index 0000000..c25bddb --- /dev/null +++ b/examples/i18n/grasshopper @@ -0,0 +1 @@ +../.. \ No newline at end of file diff --git a/examples/i18n/index.html b/examples/i18n/index.html new file mode 100644 index 0000000..c15df63 --- /dev/null +++ b/examples/i18n/index.html @@ -0,0 +1,8 @@ + + + <%= locale['title'] %> + + +

<%= locale['msg'] %>

+ + diff --git a/examples/i18n/locales.js b/examples/i18n/locales.js new file mode 100644 index 0000000..133cf1f --- /dev/null +++ b/examples/i18n/locales.js @@ -0,0 +1,21 @@ +var gh = require('./grasshopper'); + +var locales = {}; +locales['en-us'] = { + title: 'Color Page', + msg: 'Color' +}; +locales['en-gb'] = { + title: 'Colour Page', + msg: 'Colour' +}; + +gh.configure({ + locales: locales +}); + +gh.get('/', function() { + this.render('index'); +}); + +gh.serve(8080); diff --git a/lib/ghp.js b/lib/ghp.js index 3c0c8af..c6395f8 100644 --- a/lib/ghp.js +++ b/lib/ghp.js @@ -21,19 +21,19 @@ var cache = {}; var helpers = [{h: escapeHTML}]; -function fill(templateFile, model, encoding, viewsDir, extn) { +function fill(templateFile, model, encoding, viewsDir, extn, locale) { var template = cache[templateFile]; if(!template) { var content = fs.readFileSync(templateFile, encoding); - cache[templateFile] = template = compile(content, helpers.length + 1); + cache[templateFile] = template = compile(content, helpers.length + 2); } - return template(model, [new IncludeHelper(model, encoding, viewsDir, extn)].concat(helpers)); + return template(model, [new IncludeHelper(model, encoding, viewsDir, extn, locale), {locale: locale}].concat(helpers)); } exports.fill = fill; exports.fillText = function(text, model) { - return compile(text, helpers.length)(model, helpers); + return compile(text, 0)(model); } exports.addHelpers = function(newHelpers) { @@ -76,15 +76,16 @@ function compile(text, helpersCount) { } // Class: IncludeHelper -function IncludeHelper(model, encoding, viewsDir, extn) { +function IncludeHelper(model, encoding, viewsDir, extn, locale) { this.model = model; this.encoding = encoding; this.viewsDir = viewsDir; this.extn = extn; + this.locale = locale; } IncludeHelper.prototype.include = function(templateFile) { - return fill(this.viewsDir + '/' + templateFile + '.' + this.extn , this.model, this.encoding, this.viewsDir, this.extn); + return fill(this.viewsDir + '/' + templateFile + '.' + this.extn , this.model, this.encoding, this.viewsDir, this.extn, this.locale); } function escapeHTML(html) { diff --git a/lib/grasshopper.js b/lib/grasshopper.js index fe22ea8..d52947c 100644 --- a/lib/grasshopper.js +++ b/lib/grasshopper.js @@ -19,7 +19,8 @@ var http = require('http'), querystring = require('querystring'), renderer = require('./renderer'), multipart = require('./multipart'), - session = require('./session'); + session = require('./session'), + i18n = require('./i18n'); var routes = {}; var filters = []; @@ -45,6 +46,7 @@ exports.configure = function(config) { renderer.configure(config); multipart.configure(config); session.configure(config); + i18n.configure(config); }; exports.get = function(path, controller) { diff --git a/lib/i18n.js b/lib/i18n.js new file mode 100644 index 0000000..572c99d --- /dev/null +++ b/lib/i18n.js @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2010 Chandra Sekar S + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +var locales, + defaultLocale = 'en-us'; + +exports.configure = function(config) { + if(config.locales) + locales = config.locales; + if(config.defaultLocale) + defaultLocale = config.defaultLocale; +}; + +exports.init = function(ctx) { + if(locales) { + var acceptLanguage = ctx.request.headers['accept-language']; + if(acceptLanguage) { + var ranges = acceptLanguage.split(','); + for(var i = 0; i < ranges.length; i++) { + var range = ranges[i].split(';', 1)[0].toLowerCase(); + if(locales[range]) { + ctx.locale = locales[range]; + return; + } + } + } + ctx.locale = locales[defaultLocale]; + } +}; diff --git a/lib/renderer.js b/lib/renderer.js index 26fc952..1cad3a7 100644 --- a/lib/renderer.js +++ b/lib/renderer.js @@ -22,12 +22,14 @@ var fs = require('fs'), uuid = require('./uuid'), session = require('./session'), ghp = require('./ghp'), - gh = require('./grasshopper'); + gh = require('./grasshopper'), + i18n = require('./i18n'); var viewsDir = '.', defaultViewExtn = 'html', staticsDir = '.', defaultEncoding = 'utf8', + defaultCharset = 'UTF-8', layout = undefined; exports.handleError = function(err, req, res, params) { @@ -45,6 +47,8 @@ exports.configure = function(config) { defaultViewExtn = config.defaultViewExtn; if(config.staticsDir) staticsDir = config.staticsDir; + if(config.defaultCharset) + defaultCharset = config.defaultCharset; if(config.defaultEncoding) defaultEncoding = config.defaultEncoding; if(config.layout) @@ -82,6 +86,9 @@ function RequestContext(request, response, params) { } } } + + i18n.init(this); + this.charset = defaultCharset; } RequestContext.prototype.getExtn = function() { @@ -130,7 +137,7 @@ RequestContext.prototype.render = function(view, useLayout) { } try { - var content = ghp.fill(viewFile, this.model, this.encoding, viewsDir, this.extn); + var content = ghp.fill(viewFile, this.model, this.encoding, viewsDir, this.extn, this.locale); this.send(content); } catch(e) { this.handleError(e); @@ -151,6 +158,7 @@ RequestContext.prototype.renderText = function(text) { }; RequestContext.prototype.send = function(text) { + this.headers['content-type'] += '; charset=' + this.charset this.response.writeHead(this.status, this.headers); if(this.request.method != 'HEAD') { this.response.write(text, this.encoding); @@ -215,7 +223,7 @@ RequestContext.prototype.renderError = function(status, error) { fs.stat(viewFile, function(err, stats) { if(!err && stats.isFile()) { try { - var content = ghp.fill(viewFile, {error: error}, self.encoding, viewsDir, self.extn); + var content = ghp.fill(viewFile, {error: error}, self.encoding, viewsDir, self.extn, this.locale); self.send(content); } catch(e) { self.handleError(e);