493
|
1 /**
|
|
2 * Babel JavaScript Support
|
|
3 *
|
|
4 * Copyright (C) 2008 Edgewall Software
|
|
5 * All rights reserved.
|
|
6 *
|
|
7 * This software is licensed as described in the file COPYING, which
|
|
8 * you should have received as part of this distribution. The terms
|
|
9 * are also available at http://babel.edgewall.org/wiki/License.
|
|
10 *
|
|
11 * This software consists of voluntary contributions made by many
|
|
12 * individuals. For the exact contribution history, see the revision
|
|
13 * history and logs, available at http://babel.edgewall.org/log/.
|
|
14 */
|
|
15
|
|
16 /**
|
|
17 * A simple module that provides a gettext like translation interface.
|
|
18 * The catalog passed to load() must be a object conforming to this
|
|
19 * interface::
|
|
20 *
|
|
21 * {
|
|
22 * messages: an object of {msgid: translations} items where
|
|
23 * translations is an array of messages or a single
|
|
24 * string if the message is not pluralizable.
|
|
25 * plural_expr: the plural expression for the language.
|
|
26 * locale: the identifier for this locale.
|
|
27 * domain: the name of the domain.
|
|
28 * }
|
|
29 *
|
|
30 * Missing elements in the object are ignored.
|
|
31 *
|
|
32 * Typical usage::
|
|
33 *
|
|
34 * var translations = babel.Translations.load(...).install();
|
|
35 */
|
|
36 var babel = new function() {
|
|
37
|
|
38 var defaultPluralExpr = function(n) { return n == 1 ? 0 : 1; };
|
|
39 var formatRegex = /%?%(?:\(([^\)]+)\))?([disr])/g;
|
|
40
|
|
41 /**
|
|
42 * A translations object implementing the gettext interface
|
|
43 */
|
|
44 var Translations = this.Translations = function(locale, domain) {
|
|
45 this.messages = {};
|
|
46 this.locale = locale || 'unknown';
|
|
47 this.domain = domain || 'messages';
|
|
48 this.pluralexpr = defaultPluralExpr;
|
|
49 };
|
|
50
|
|
51 /**
|
|
52 * Create a new translations object from the catalog and return it.
|
|
53 * See the babel-module comment for more details.
|
|
54 */
|
|
55 Translations.load = function(catalog) {
|
|
56 var rv = new Translations();
|
|
57 rv.load(catalog);
|
|
58 return rv;
|
|
59 };
|
|
60
|
|
61 Translations.prototype = {
|
|
62 /**
|
|
63 * translate a single string.
|
|
64 */
|
|
65 gettext: function(string) {
|
|
66 var translated = this.messages[string];
|
|
67 if (typeof translated == 'undefined')
|
|
68 return string;
|
|
69 return (typeof translated == 'string') ? translated : translated[0];
|
|
70 },
|
|
71
|
|
72 /**
|
|
73 * translate a pluralizable string
|
|
74 */
|
|
75 ngettext: function(singular, plural, n) {
|
|
76 var translated = this.messages[singular];
|
|
77 if (typeof translated == 'undefined')
|
|
78 return (n == 1) ? singular : plural;
|
|
79 return translated[this.pluralexpr(n)];
|
|
80 },
|
|
81
|
|
82 /**
|
|
83 * Install this translation document wide. After this call, there are
|
|
84 * three new methods on the window object: _, gettext and ngettext
|
|
85 */
|
|
86 install: function() {
|
|
87 var self = this;
|
|
88 window._ = window.gettext = function(string) {
|
|
89 return self.gettext(string);
|
|
90 };
|
|
91 window.ngettext = function(singular, plural, n) {
|
|
92 return self.ngettext(singular, plural, n);
|
|
93 };
|
|
94 return this;
|
|
95 },
|
|
96
|
|
97 /**
|
|
98 * Works like Translations.load but updates the instance rather
|
|
99 * then creating a new one.
|
|
100 */
|
|
101 load: function(catalog) {
|
|
102 if (catalog.messages)
|
|
103 this.update(catalog.messages)
|
|
104 if (catalog.plural_expr)
|
|
105 this.setPluralExpr(catalog.plural_expr);
|
|
106 if (catalog.locale)
|
|
107 this.locale = catalog.locale;
|
|
108 if (catalog.domain)
|
|
109 this.domain = catalog.domain;
|
|
110 return this;
|
|
111 },
|
|
112
|
|
113 /**
|
|
114 * Updates the translations with the object of messages.
|
|
115 */
|
|
116 update: function(mapping) {
|
|
117 for (var key in mapping)
|
|
118 if (mapping.hasOwnProperty(key))
|
|
119 this.messages[key] = mapping[key];
|
|
120 return this;
|
|
121 },
|
|
122
|
|
123 /**
|
|
124 * Sets the plural expression
|
|
125 */
|
|
126 setPluralExpr: function(expr) {
|
|
127 this.pluralexpr = new Function('n', 'return +(' + expr + ')');
|
|
128 return this;
|
|
129 }
|
|
130 };
|
|
131
|
|
132 /**
|
|
133 * A python inspired string formatting function. Supports named and
|
|
134 * positional placeholders and "s", "d" and "i" as type characters
|
|
135 * without any formatting specifications.
|
|
136 *
|
|
137 * Examples::
|
|
138 *
|
|
139 * babel.format(_('Hello %s'), name)
|
|
140 * babel.format(_('Progress: %(percent)s%%'), {percent: 100})
|
|
141 */
|
|
142 this.format = function() {
|
|
143 var arg, string = arguments[0], idx = 0;
|
|
144 if (arguments.length == 1)
|
|
145 return string;
|
|
146 else if (arguments.length == 2 && typeof arguments[1] == 'object')
|
|
147 arg = arguments[1];
|
|
148 else {
|
|
149 arg = [];
|
|
150 for (var i = 1, n = arguments.length; i != n; ++i)
|
|
151 arg[i - 1] = arguments[i];
|
|
152 }
|
|
153 return string.replace(formatRegex, function(all, name, type) {
|
|
154 if (all[0] == all[1]) return all.substring(1);
|
|
155 var value = arg[name || idx++];
|
|
156 return (type == 'i' || type == 'd') ? +value : value;
|
|
157 });
|
|
158 }
|
|
159
|
|
160 };
|