/** * Babel JavaScript Support * * Copyright (C) 2008-2011 Edgewall Software * All rights reserved. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at http://babel.edgewall.org/wiki/License. * * This software consists of voluntary contributions made by many * individuals. For the exact contribution history, see the revision * history and logs, available at http://babel.edgewall.org/log/. */ /** * A simple module that provides a gettext like translation interface. * The catalog passed to load() must be a object conforming to this * interface:: * * { * messages: an object of {msgid: translations} items where * translations is an array of messages or a single * string if the message is not pluralizable. * plural_expr: the plural expression for the language. * locale: the identifier for this locale. * domain: the name of the domain. * } * * Missing elements in the object are ignored. * * Typical usage:: * * var translations = babel.Translations.load(...).install(); */ var babel = new function() { var defaultPluralExpr = function(n) { return n == 1 ? 0 : 1; }; var formatRegex = /%?%(?:\(([^\)]+)\))?([disr])/g; /** * A translations object implementing the gettext interface */ var Translations = this.Translations = function(locale, domain) { this.messages = {}; this.locale = locale || 'unknown'; this.domain = domain || 'messages'; this.pluralexpr = defaultPluralExpr; }; /** * Create a new translations object from the catalog and return it. * See the babel-module comment for more details. */ Translations.load = function(catalog) { var rv = new Translations(); rv.load(catalog); return rv; }; Translations.prototype = { /** * translate a single string. */ gettext: function(string) { var translated = this.messages[string]; if (typeof translated == 'undefined') return string; return (typeof translated == 'string') ? translated : translated[0]; }, /** * translate a pluralizable string */ ngettext: function(singular, plural, n) { var translated = this.messages[singular]; if (typeof translated == 'undefined') return (n == 1) ? singular : plural; return translated[this.pluralexpr(n)]; }, /** * Install this translation document wide. After this call, there are * three new methods on the window object: _, gettext and ngettext */ install: function() { var self = this; window._ = window.gettext = function(string) { return self.gettext(string); }; window.ngettext = function(singular, plural, n) { return self.ngettext(singular, plural, n); }; return this; }, /** * Works like Translations.load but updates the instance rather * then creating a new one. */ load: function(catalog) { if (catalog.messages) this.update(catalog.messages); if (catalog.plural_expr) this.setPluralExpr(catalog.plural_expr); if (catalog.locale) this.locale = catalog.locale; if (catalog.domain) this.domain = catalog.domain; return this; }, /** * Updates the translations with the object of messages. */ update: function(mapping) { for (var key in mapping) if (mapping.hasOwnProperty(key)) this.messages[key] = mapping[key]; return this; }, /** * Sets the plural expression */ setPluralExpr: function(expr) { this.pluralexpr = new Function('n', 'return +(' + expr + ')'); return this; } }; /** * A python inspired string formatting function. Supports named and * positional placeholders and "s", "d" and "i" as type characters * without any formatting specifications. * * Examples:: * * babel.format(_('Hello %s'), name) * babel.format(_('Progress: %(percent)s%%'), {percent: 100}) */ this.format = function() { var arg, string = arguments[0], idx = 0; if (arguments.length == 1) return string; else if (arguments.length == 2 && typeof arguments[1] == 'object') arg = arguments[1]; else { arg = []; for (var i = 1, n = arguments.length; i != n; ++i) arg[i - 1] = arguments[i]; } return string.replace(formatRegex, function(all, name, type) { if (all[0] == all[1]) return all.substring(1); var value = arg[name || idx++]; return (type == 'i' || type == 'd') ? +value : value; }); } };