Merge lp:~tsabi/openerp-web/trunk-properi18nmark into lp:openerp-web

Proposed by Csaba TOTH
Status: Merged
Approved by: Xavier (Open ERP)
Approved revision: 3524
Merged at revision: 3531
Proposed branch: lp:~tsabi/openerp-web/trunk-properi18nmark
Merge into: lp:openerp-web
Diff against target: 702 lines (+88/-82)
12 files modified
addons/web/controllers/main.py (+11/-10)
addons/web/static/src/js/chrome.js (+17/-17)
addons/web/static/src/js/dates.js (+7/-6)
addons/web/static/src/js/formats.js (+7/-7)
addons/web/static/src/js/pyeval.js (+10/-8)
addons/web/static/src/js/view_form.js (+12/-12)
addons/web/static/src/js/view_list.js (+7/-7)
addons/web/static/src/js/view_list_editable.js (+3/-1)
addons/web/static/src/js/views.js (+6/-6)
addons/web_calendar/static/src/js/calendar.js (+2/-2)
addons/web_kanban/static/src/js/kanban.js (+1/-1)
addons/web_view_editor/static/src/js/view_editor.js (+5/-5)
To merge this branch: bzr merge lp:~tsabi/openerp-web/trunk-properi18nmark
Reviewer Review Type Date Requested Status
Xavier (Open ERP) (community) Needs Fixing
Stefan Rijnhart (Opener) (community) Needs Fixing
Review via email: mp+136875@code.launchpad.net

Description of the change

Marked every (missed some only technical error message) string as translatable. See bug report 1084306

To post a comment you must log in.
Revision history for this message
Stefan Rijnhart (Opener) (stefan-opener) wrote :

Hi Csaba,

great work! Two issues that should be easy to solve:

Please merge the latest revisions of lp:openerp-web and resolve the conflict in your branch.

Spacing around line 546 in the patch looks dubious. Do you perhaps use tabs instead of spaces?

Thanks,
Stefan.

review: Needs Fixing
Revision history for this message
Xavier (Open ERP) (xmo-deactivatedaccount) wrote :

Nothing to add to Stefan's review, if these two points are fixed there should be no problem with merging this proposal.

3521. By Csaba TOTH

[MERGE] trunk

3522. By Csaba TOTH

[MERGE] trunk

3523. By Csaba TOTH

fix tab problem

3524. By Csaba TOTH

some more change in the new pyeval.js file

Revision history for this message
Csaba TOTH (tsabi) wrote :

Ok, updated to trunk, and fixed the tab problem.

Revision history for this message
Xavier (Open ERP) (xmo-deactivatedaccount) wrote :

I fear you'll have to revert part of the last change (to pyeval), it accesses _t using the full dotted path because it is loaded before _t being made available. Thus the base aliasing `var _t = instance.web._t;` will result in _t always being `undefined`.

review: Needs Fixing
Revision history for this message
Xavier (Open ERP) (xmo-deactivatedaccount) wrote :

Furthermore the untranslated strings were actually the strings taken directly from the corresponding Python exceptions and messages, and untranslated on purpose.

Revision history for this message
Xavier (Open ERP) (xmo-deactivatedaccount) wrote :

(nm, I'll just revert it locally while merging)

Revision history for this message
Csaba TOTH (tsabi) wrote :

wow, that was quick :) Thanks!

yes you right, in pyeval.js there is not too much real end user message, except pyeval.js:344:348 lines, and it has hardcoded english language specific code. Please look how i resolved that conflict, i feel that needs to fixed too.

Revision history for this message
Xavier (Open ERP) (xmo-deactivatedaccount) wrote :

> yes you right, in pyeval.js there is not too much real end user message, except pyeval.js:344:348 lines, and it has hardcoded english language specific code.

Well I don't know, it's the string representation of a Python timedelta object, which I don't know to be translated. If you have an OS in a non-english language, try creating a timedelta object and see what it prints to:

    > python -c 'import datetime; print datetime.timedelta(1, 1)'
    1 day, 0:00:01

if it returns some sort of localized string localizing it in pyeval could be considered, but if it does not I'd rather stick to the original behavior in the translation to javascript.

Revision history for this message
Csaba TOTH (tsabi) wrote :

Ok, i am not a big javascript tumbler, as i getted out it includes text to translate, but didn't getted out the real meaning of the code. Now i understand, if this will piped to a python evaluation process, than this is in good format.

from my python windows console with hungarian local:

import datetime; print datetime.timedelta(1, 4)
1 day, 0:00:04
import datetime; print datetime.timedelta(1, 78798768)
913 days, 0:32:48

The same result under linux with hu_HU.UTF-8 locale.

Revision history for this message
Xavier (Open ERP) (xmo-deactivatedaccount) wrote :

> Ok, i am not a big javascript tumbler, as i getted out it includes text to translate, but didn't getted out the real meaning of the code.

No problem.

> Now i understand, if this will piped to a python evaluation process

Yeah technically it *is* a python evaluation process (partial), to avoid doing the evaluation on the server.

> The same result under linux with hu_HU.UTF-8 locale.

OK, I'll leave the current output then. But thanks a lot for having wondered about it and checked.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'addons/web/controllers/main.py'
2--- addons/web/controllers/main.py 2012-11-29 09:10:38 +0000
3+++ addons/web/controllers/main.py 2012-11-29 11:56:19 +0000
4@@ -28,6 +28,7 @@
5 xlwt = None
6
7 import openerp
8+from openerp.tools.translate import _
9
10 from .. import http
11 openerpweb = http
12@@ -762,7 +763,7 @@
13 except xmlrpclib.Fault, e:
14 if e.faultCode and e.faultCode.split(':')[0] == 'AccessDenied':
15 return {'error': e.faultCode, 'title': 'Drop Database'}
16- return {'error': 'Could not drop database !', 'title': 'Drop Database'}
17+ return {'error': _('Could not drop database !'), 'title': _('Drop Database')}
18
19 @openerpweb.httprequest
20 def backup(self, req, backup_db, backup_pwd, token):
21@@ -780,7 +781,7 @@
22 {'fileToken': int(token)}
23 )
24 except xmlrpclib.Fault, e:
25- return simplejson.dumps([[],[{'error': e.faultCode, 'title': 'backup Database'}]])
26+ return simplejson.dumps([[],[{'error': e.faultCode, 'title': _('Backup Database')}]])
27
28 @openerpweb.httprequest
29 def restore(self, req, db_file, restore_pwd, new_db):
30@@ -801,8 +802,8 @@
31 return req.session.proxy("db").change_admin_password(old_password, new_password)
32 except xmlrpclib.Fault, e:
33 if e.faultCode and e.faultCode.split(':')[0] == 'AccessDenied':
34- return {'error': e.faultCode, 'title': 'Change Password'}
35- return {'error': 'Error, password not changed !', 'title': 'Change Password'}
36+ return {'error': e.faultCode, 'title': _('Change Password')}
37+ return {'error': _('Error, password not changed !'), 'title': _('Change Password')}
38
39 class Session(openerpweb.Controller):
40 _cp_path = "/web/session"
41@@ -838,16 +839,16 @@
42 old_password, new_password,confirm_password = operator.itemgetter('old_pwd', 'new_password','confirm_pwd')(
43 dict(map(operator.itemgetter('name', 'value'), fields)))
44 if not (old_password.strip() and new_password.strip() and confirm_password.strip()):
45- return {'error':'You cannot leave any password empty.','title': 'Change Password'}
46+ return {'error':_('You cannot leave any password empty.'),'title': _('Change Password')}
47 if new_password != confirm_password:
48- return {'error': 'The new password and its confirmation must be identical.','title': 'Change Password'}
49+ return {'error': _('The new password and its confirmation must be identical.'),'title': _('Change Password')}
50 try:
51 if req.session.model('res.users').change_password(
52 old_password, new_password):
53 return {'new_password':new_password}
54 except Exception:
55- return {'error': 'The old password you provided is incorrect, your password was not changed.', 'title': 'Change Password'}
56- return {'error': 'Error, password not changed !', 'title': 'Change Password'}
57+ return {'error': _('The old password you provided is incorrect, your password was not changed.'), 'title': _('Change Password')}
58+ return {'error': _('Error, password not changed !'), 'title': _('Change Password')}
59
60 @openerpweb.jsonrequest
61 def sc_list(self, req):
62@@ -859,7 +860,7 @@
63 try:
64 return req.session.proxy("db").list_lang() or []
65 except Exception, e:
66- return {"error": e, "title": "Languages"}
67+ return {"error": e, "title": _("Languages")}
68
69 @openerpweb.jsonrequest
70 def modules(self, req):
71@@ -1302,7 +1303,7 @@
72 res = Model.default_get(fields, context)
73 filecontent = base64.b64decode(res.get(field, ''))
74 if not filecontent:
75- raise ValueError("No content found for field '%s' on '%s:%s'" %
76+ raise ValueError(_("No content found for field '%s' on '%s:%s'") %
77 (field, model, id))
78 else:
79 filename = '%s_%s' % (model.replace('.', '_'), id)
80
81=== modified file 'addons/web/static/src/js/chrome.js'
82--- addons/web/static/src/js/chrome.js 2012-11-29 09:10:38 +0000
83+++ addons/web/static/src/js/chrome.js 2012-11-29 11:56:19 +0000
84@@ -289,7 +289,7 @@
85 });
86
87 instance.web.Loading = instance.web.Widget.extend({
88- template: 'Loading',
89+ template: _t("Loading"),
90 init: function(parent) {
91 this._super(parent);
92 this.count = 0;
93@@ -390,11 +390,11 @@
94 self.$el.find("form[name=restore_db_form]").validate({ submitHandler: self.do_restore });
95 self.$el.find("form[name=change_pwd_form]").validate({
96 messages: {
97- old_pwd: "Please enter your previous password",
98- new_pwd: "Please enter your new password",
99+ old_pwd: _t("Please enter your previous password"),
100+ new_pwd: _t("Please enter your new password"),
101 confirm_pwd: {
102- required: "Please confirm your new password",
103- equalTo: "The confirmation does not match the password"
104+ required: _t("Please confirm your new password"),
105+ equalTo: _t("The confirmation does not match the password")
106 }
107 },
108 submitHandler: self.do_change_password
109@@ -478,7 +478,7 @@
110 self.display_error(result);
111 return;
112 }
113- self.do_notify("Duplicating database", "The database has been duplicated.");
114+ self.do_notify(_t("Duplicating database"), _t("The database has been duplicated."));
115 self.start();
116 });
117 },
118@@ -488,7 +488,7 @@
119 fields = $form.serializeArray(),
120 $db_list = $form.find('[name=drop_db]'),
121 db = $db_list.val();
122- if (!db || !confirm("Do you really want to delete the database: " + db + " ?")) {
123+ if (!db || !confirm(_.str.sprintf(_t("Do you really want to delete the database: %s ?"), db))) {
124 return;
125 }
126 self.rpc("/web/database/drop", {'fields': fields}).done(function(result) {
127@@ -496,7 +496,7 @@
128 self.display_error(result);
129 return;
130 }
131- self.do_notify("Dropping database", "The database '" + db + "' has been dropped");
132+ self.do_notify(_t("Dropping database"), _.str.sprintf(_t("The database %s has been dropped"), db));
133 self.start();
134 });
135 },
136@@ -511,7 +511,7 @@
137 error: function(error){
138 if(error){
139 self.display_error({
140- title: 'Backup Database',
141+ title: _t("Backup Database"),
142 error: 'AccessDenied'
143 });
144 }
145@@ -534,13 +534,13 @@
146
147 if (body.indexOf('403 Forbidden') !== -1) {
148 self.display_error({
149- title: 'Access Denied',
150- error: 'Incorrect super-administrator password'
151+ title: _t("Access Denied"),
152+ error: _t("Incorrect super-administrator password")
153 });
154 } else {
155 self.display_error({
156- title: 'Restore Database',
157- error: 'Could not restore the database'
158+ title: _t("Restore Database"),
159+ error: _t("Could not restore the database")
160 });
161 }
162 },
163@@ -560,7 +560,7 @@
164 return;
165 }
166 self.unblockUI();
167- self.do_notify("Changed Password", "Password has been changed successfully");
168+ self.do_notify(_t("Changed Password"), _t("Password has been changed successfully"));
169 });
170 },
171 do_exit: function () {
172@@ -642,7 +642,7 @@
173 }
174 var db = this.$("form [name=db]").val();
175 if (!db) {
176- this.do_warn("Login", "No database selected !");
177+ this.do_warn(_t("Login"), _t("No database selected !"));
178 return false;
179 }
180 var login = this.$("form input[name=login]").val();
181@@ -678,7 +678,7 @@
182 self.trigger('login_successful');
183 }, function () {
184 self.$(".oe_login_pane").fadeIn("fast", function() {
185- self.show_error("Invalid username or password");
186+ self.show_error(_t("Invalid username or password"));
187 });
188 });
189 },
190@@ -765,7 +765,7 @@
191 template: "ChangePassword",
192 start: function() {
193 var self = this;
194- this.getParent().dialog_title = "Change Password";
195+ this.getParent().dialog_title = _t("Change Password");
196 var $button = self.$el.find('.oe_form_button');
197 $button.appendTo(this.getParent().$buttons);
198 $button.eq(2).click(function(){
199
200=== modified file 'addons/web/static/src/js/dates.js'
201--- addons/web/static/src/js/dates.js 2012-04-17 11:58:05 +0000
202+++ addons/web/static/src/js/dates.js 2012-11-29 11:56:19 +0000
203@@ -1,5 +1,6 @@
204
205 openerp.web.dates = function(instance) {
206+var _t = instance.web._t;
207
208 /**
209 * Converts a string to a Date javascript object using OpenERP's
210@@ -18,11 +19,11 @@
211 var regex = /^(\d\d\d\d-\d\d-\d\d \d\d:\d\d:\d\d)(?:\.\d+)?$/;
212 var res = regex.exec(str);
213 if ( !res ) {
214- throw new Error("'" + str + "' is not a valid datetime");
215+ throw new Error(_.str.sprintf(_t("'%s' is not a valid datetime"), str));
216 }
217 var obj = Date.parseExact(res[1] + " UTC", 'yyyy-MM-dd HH:mm:ss zzz');
218 if (! obj) {
219- throw new Error("'" + str + "' is not a valid datetime");
220+ throw new Error(_.str.sprintf(_t("'%s' is not a valid datetime"), str));
221 }
222 return obj;
223 };
224@@ -45,11 +46,11 @@
225 var regex = /^\d\d\d\d-\d\d-\d\d$/;
226 var res = regex.exec(str);
227 if ( !res ) {
228- throw new Error("'" + str + "' is not a valid date");
229+ throw new Error(_.str.sprintf(_t("'%s' is not a valid date"), str));
230 }
231 var obj = Date.parseExact(str, 'yyyy-MM-dd');
232 if (! obj) {
233- throw new Error("'" + str + "' is not a valid date");
234+ throw new Error(_.str.sprintf(_t("'%s' is not a valid date"), str));
235 }
236 return obj;
237 };
238@@ -72,11 +73,11 @@
239 var regex = /^(\d\d:\d\d:\d\d)(?:\.\d+)?$/;
240 var res = regex.exec(str);
241 if ( !res ) {
242- throw new Error("'" + str + "' is not a valid time");
243+ throw new Error(_.str.sprintf(_t("'%s' is not a valid time"), str));
244 }
245 var obj = Date.parseExact("1970-01-01 " + res[1], 'yyyy-MM-dd HH:mm:ss');
246 if (! obj) {
247- throw new Error("'" + str + "' is not a valid time");
248+ throw new Error(_.str.sprintf(_t("'%s' is not a valid time"), str));
249 }
250 return obj;
251 };
252
253=== modified file 'addons/web/static/src/js/formats.js'
254--- addons/web/static/src/js/formats.js 2012-11-12 17:11:28 +0000
255+++ addons/web/static/src/js/formats.js 2012-11-29 11:56:19 +0000
256@@ -224,7 +224,7 @@
257 } while(tmp !== value);
258 tmp = Number(value);
259 if (isNaN(tmp))
260- throw new Error(value + " is not a correct integer");
261+ throw new Error(_.str.sprintf(_t("'%s' is not a correct integer"), value));
262 return tmp;
263 case 'float':
264 var tmp = Number(value);
265@@ -239,7 +239,7 @@
266 var reformatted_value = tmp.replace(instance.web._t.database.parameters.decimal_point, ".");
267 var parsed = Number(reformatted_value);
268 if (isNaN(parsed))
269- throw new Error(value + " is not a correct float");
270+ throw new Error(_.str.sprintf(_t("'%s' is not a correct float"), value));
271 return parsed;
272 case 'float_time':
273 var factor = 1;
274@@ -263,7 +263,7 @@
275 datetime = Date.parse(value);
276 if (datetime !== null)
277 return instance.web.datetime_to_str(datetime);
278- throw new Error(value + " is not a valid datetime");
279+ throw new Error(_.str.sprintf(_t("'%s' is not a correct datetime"), value));
280 case 'date':
281 var date = Date.parseExact(value, date_pattern);
282 if (date !== null)
283@@ -271,7 +271,7 @@
284 date = Date.parse(value);
285 if (date !== null)
286 return instance.web.date_to_str(date);
287- throw new Error(value + " is not a valid date");
288+ throw new Error(_.str.sprintf(_t("'%s' is not a correct date"), value));
289 case 'time':
290 var time = Date.parseExact(value, time_pattern);
291 if (time !== null)
292@@ -279,7 +279,7 @@
293 time = Date.parse(value);
294 if (time !== null)
295 return instance.web.time_to_str(time);
296- throw new Error(value + " is not a valid time");
297+ throw new Error(_.str.sprintf(_t("'%s' is not a correct time"), value));
298 }
299 return value;
300 };
301@@ -294,7 +294,7 @@
302 try {
303 return instance.web.str_to_time(value);
304 } catch(e) {}
305- throw new Error("'" + value + "' is not a valid date, datetime nor time");
306+ throw new Error(_.str.sprintf(_t("'%s' is not a correct date, datetime nor time"), value));
307 };
308
309 instance.web.auto_date_to_str = function(value, type) {
310@@ -306,7 +306,7 @@
311 case 'time':
312 return instance.web.time_to_str(value);
313 default:
314- throw new Error(type + " is not convertible to date, datetime nor time");
315+ throw new Error(_.str.sprintf(_t("'%s' is not convertible to date, datetime nor time"), type));
316 }
317 };
318
319
320=== modified file 'addons/web/static/src/js/pyeval.js'
321--- addons/web/static/src/js/pyeval.js 2012-11-28 11:05:42 +0000
322+++ addons/web/static/src/js/pyeval.js 2012-11-29 11:56:19 +0000
323@@ -2,6 +2,7 @@
324 * py.js helpers and setup
325 */
326 openerp.web.pyeval = function (instance) {
327+ var _t = instance.web._t;
328 instance.web.pyeval = {};
329
330 var obj = function () {};
331@@ -71,7 +72,7 @@
332 var ymd2ord = function (year, month, day) {
333 var dim = days_in_month(year, month);
334 if (!(1 <= day && day <= dim)) {
335- throw new Error("ValueError: day must be in 1.." + dim);
336+ throw new Error(_.str.sprintf(_t("ValueError: day must be in 1..%d"), dim));
337 }
338 return days_before_year(year)
339 + days_before_month(year, month)
340@@ -277,10 +278,11 @@
341 });
342 var s = _.str.sprintf("%d:%02d:%02d", hh, mm, ss);
343 if (this.days) {
344- s = _.str.sprintf("%d day%s, %s",
345- this.days,
346- (this.days != 1 && this.days != -1) ? 's' : '',
347- s);
348+ if (this.days != 1 && this.days != -1) {
349+ s = _.str.sprintf(_t("%d days, %s"), this.days, s);
350+ } else {
351+ s = _.str.sprintf(_t("%d day, %s"), this.days, s);
352+ };
353 }
354 if (this.microseconds) {
355 s = _.str.sprintf("%s.%06d", s, this.microseconds);
356@@ -726,7 +728,7 @@
357 case 'context': case 'compound_context':
358 return instance.web.pyeval.eval('contexts', [arg]);
359 default:
360- throw new Error(instance.web._t("Unknown nonliteral type " + arg.__ref));
361+ throw new Error(_t("Unknown nonliteral type ") + arg.__ref);
362 }
363 };
364 /**
365@@ -760,11 +762,11 @@
366 } catch (e) {
367 d.resolve({ error: {
368 code: 400,
369- message: instance.web._t("Evaluation Error"),
370+ message: _t("Evaluation Error"),
371 data: {
372 type: 'local_exception',
373 debug: _.str.sprintf(
374- instance.web._t("Local evaluation failure\n%s\n\n%s"),
375+ _t("Local evaluation failure\n%s\n\n%s"),
376 e.message, JSON.stringify(source))
377 }
378 }});
379
380=== modified file 'addons/web/static/src/js/view_form.js'
381--- addons/web/static/src/js/view_form.js 2012-11-29 09:10:38 +0000
382+++ addons/web/static/src/js/view_form.js 2012-11-29 11:56:19 +0000
383@@ -148,7 +148,7 @@
384 load_form: function(data) {
385 var self = this;
386 if (!data) {
387- throw new Error("No data provided.");
388+ throw new Error(_t("No data provided."));
389 }
390 if (this.arch) {
391 throw "Form view does not support multiple calls to load_form";
392@@ -316,12 +316,12 @@
393 var self = this, set_values = [];
394 if (!record) {
395 this.set({ 'title' : undefined });
396- this.do_warn("Form", "The record could not be found in the database.", true);
397+ this.do_warn(_t("Form"), _t("The record could not be found in the database."), true);
398 return $.Deferred().reject();
399 }
400 this.datarecord = record;
401 this._actualize_mode();
402- this.set({ 'title' : record.id ? record.display_name : "New" });
403+ this.set({ 'title' : record.id ? record.display_name : _t("New") });
404
405 _(this.fields).each(function (field, f) {
406 field._dirty_flag = false;
407@@ -431,7 +431,7 @@
408 var onchange = _.str.trim(on_change);
409 var call = onchange.match(/^\s?(.*?)\((.*?)\)\s?$/);
410 if (!call) {
411- throw new Error("Wrong on change format: " + onchange);
412+ throw new Error(_.str.sprintf( _t("Wrong on change format: %s"), onchange ));
413 }
414
415 var method = call[1];
416@@ -866,7 +866,7 @@
417 }).value();
418 warnings.unshift('<ul>');
419 warnings.push('</ul>');
420- this.do_warn("The following fields are invalid :", warnings.join(''));
421+ this.do_warn(_t("The following fields are invalid:"), warnings.join(''));
422 },
423 /**
424 * Reload the form after saving
425@@ -1235,11 +1235,11 @@
426 _.each(this.fields_to_init, function($elem) {
427 var name = $elem.attr("name");
428 if (!self.fvg.fields[name]) {
429- throw new Error("Field '" + name + "' specified in view could not be found.");
430+ throw new Error(_.str.sprintf(_t("Field '%s' specified in view could not be found."), name));
431 }
432 var obj = self.fields_registry.get_any([$elem.attr('widget'), self.fvg.fields[name].type]);
433 if (!obj) {
434- throw new Error("Widget type '"+ $elem.attr('widget') + "' is not implemented");
435+ throw new Error(_.str.sprintf(_t("Widget type '%s' is not implemented"), $elem.attr('widget')));
436 }
437 var w = new (obj)(self.view, instance.web.xml_to_json($elem[0]));
438 var $label = self.labels[$elem.attr("name")];
439@@ -2313,7 +2313,7 @@
440 },
441 on_button_clicked: function() {
442 if (!this.get('value') || !this.is_syntax_valid()) {
443- this.do_warn("E-mail error", "Can't send email to invalid e-mail address");
444+ this.do_warn(_t("E-mail error"), _t("Can't send email to invalid e-mail address"));
445 } else {
446 location.href = 'mailto:' + this.get('value');
447 }
448@@ -2342,7 +2342,7 @@
449 },
450 on_button_clicked: function() {
451 if (!this.get('value')) {
452- this.do_warn("Resource error", "This resource is empty");
453+ this.do_warn(_t("Resource error"), _t("This resource is empty"));
454 } else {
455 var url = $.trim(this.get('value'));
456 if(/^www\./i.test(url))
457@@ -3379,7 +3379,7 @@
458 var views = [];
459 _.each(modes, function(mode) {
460 if (! _.include(["list", "tree", "graph", "kanban"], mode)) {
461- throw new Error(_.str.sprintf("View type '%s' is not supported in One2Many.", mode));
462+ throw new Error(_.str.sprintf(_t("View type '%s' is not supported in One2Many."), mode));
463 }
464 var view = {
465 view_id: false,
466@@ -4834,7 +4834,7 @@
467 },
468 on_file_uploaded: function(size, name, content_type, file_base64) {
469 if (size === false) {
470- this.do_warn("File Upload", "There was a problem while uploading your file");
471+ this.do_warn(_t("File Upload"), _t("There was a problem while uploading your file"));
472 // TODO: use openerp web crashmanager
473 console.warn("Error while uploading file : ", name);
474 } else {
475@@ -5003,7 +5003,7 @@
476 this.field_manager = field_manager;
477 this.node = node;
478 if(this.field.type != "many2many" || this.field.relation != 'ir.attachment') {
479- throw "The type of the field '"+this.field.string+"' must be a many2many field with a relation to 'ir.attachment' model.";
480+ throw _.str.sprintf(_t("The type of the field '%s' must be a many2many field with a relation to 'ir.attachment' model."), this.field.string);
481 }
482 this.ds_file = new instance.web.DataSetSearch(this, 'ir.attachment');
483 this.fileupload_id = _.uniqueId('oe_fileupload_temp');
484
485=== modified file 'addons/web/static/src/js/view_list.js'
486--- addons/web/static/src/js/view_list.js 2012-11-29 09:10:38 +0000
487+++ addons/web/static/src/js/view_list.js 2012-11-29 11:56:19 +0000
488@@ -389,7 +389,7 @@
489 if (range_stop > total) {
490 range_stop = total;
491 }
492- spager = _.str.sprintf('%d-%d of %d', range_start, range_stop, total);
493+ spager = _.str.sprintf(_t("%d-%d of %d"), range_start, range_stop, total);
494 }
495
496 this.$pager.find('.oe_list_pager_state').text(spager);
497@@ -887,8 +887,8 @@
498 var $row;
499 if (attribute === 'id') {
500 if (old_value) {
501- throw new Error("Setting 'id' attribute on existing record "
502- + JSON.stringify(record.attributes));
503+ throw new Error(_.str.sprintf( _t("Setting 'id' attribute on existing record %s"),
504+ JSON.stringify(record.attributes) ));
505 }
506 if (!_.contains(self.dataset.ids, value)) {
507 // add record to dataset if not already in (added by
508@@ -956,7 +956,7 @@
509 if (row_id) {
510 e.stopPropagation();
511 if (!self.dataset.select_id(row_id)) {
512- throw new Error("Could not find id in dataset");
513+ throw new Error(_t("Could not find id in dataset"));
514 }
515 self.row_clicked(e);
516 }
517@@ -1016,7 +1016,7 @@
518 var command = value[0];
519 // 1. an array of m2m commands (usually (6, false, ids))
520 if (command[0] !== 6) {
521- throw new Error(_t("Unknown m2m command ") + command[0]);
522+ throw new Error(_.str.sprintf( _t("Unknown m2m command %s"), command[0]));
523 }
524 ids = command[2];
525 } else {
526@@ -1324,7 +1324,7 @@
527 }
528 // group_label is html-clean (through format or explicit
529 // escaping if format failed), can inject straight into HTML
530- $group_column.html(_.str.sprintf("%s (%d)",
531+ $group_column.html(_.str.sprintf(_t("%s (%d)"),
532 group_label, group.length));
533
534 if (group.length && group.openable) {
535@@ -1743,7 +1743,7 @@
536 } else if (val instanceof Array) {
537 output[k] = val[0];
538 } else {
539- throw new Error("Can't convert value " + val + " to context");
540+ throw new Error(_.str.sprintf(_t("Can't convert value %s to context"), val));
541 }
542 }
543 return output;
544
545=== modified file 'addons/web/static/src/js/view_list_editable.js'
546--- addons/web/static/src/js/view_list_editable.js 2012-11-29 09:10:38 +0000
547+++ addons/web/static/src/js/view_list_editable.js 2012-11-29 11:56:19 +0000
548@@ -3,6 +3,8 @@
549 * @namespace
550 */
551 openerp.web.list_editable = function (instance) {
552+ var _t = instance.web._t;
553+
554 // editability status of list rows
555 instance.web.ListView.prototype.defaults.editable = null;
556
557@@ -775,7 +777,7 @@
558 cancel: function (force) {
559 if (!(force || this.form.can_be_discarded())) {
560 return $.Deferred().reject({
561- message: "The form's data can not be discarded"}).promise();
562+ message: _t("The form's data can not be discarded")}).promise();
563 }
564 var record = this.record;
565 this.record = null;
566
567=== modified file 'addons/web/static/src/js/views.js'
568--- addons/web/static/src/js/views.js 2012-11-29 10:11:37 +0000
569+++ addons/web/static/src/js/views.js 2012-11-29 11:56:19 +0000
570@@ -807,7 +807,7 @@
571 break;
572 case 'tests':
573 this.do_action({
574- name: "JS Tests",
575+ name: _t("JS Tests"),
576 target: 'new',
577 type : 'ir.actions.act_url',
578 url: '/web/tests?mod=*'
579@@ -835,7 +835,7 @@
580 break;
581 case 'translate':
582 this.do_action({
583- name: "Technical Translation",
584+ name: _t("Technical Translation"),
585 res_model : 'ir.translation',
586 domain : [['type', '!=', 'object'], '|', ['name', '=', this.dataset.model], ['name', 'ilike', this.dataset.model + ',']],
587 views: [[false, 'list'], [false, 'form']],
588@@ -1418,7 +1418,7 @@
589 return sindent + node;
590 } else if (typeof(node.tag) !== 'string' || !node.children instanceof Array || !node.attrs instanceof Object) {
591 throw new Error(
592- _.str.sprintf("Node [%s] is not a JSONified XML node",
593+ _.str.sprintf(_t("Node [%s] is not a JSONified XML node"),
594 JSON.stringify(node)));
595 }
596 for (var attr in node.attrs) {
597@@ -1452,7 +1452,7 @@
598 } else if (window.ActiveXObject) {
599 return node.xml;
600 } else {
601- throw new Error("Could not serialize XML");
602+ throw new Error(_t("Could not serialize XML"));
603 }
604 };
605 instance.web.str_to_xml = function(s) {
606@@ -1460,7 +1460,7 @@
607 var dp = new DOMParser();
608 var r = dp.parseFromString(s, "text/xml");
609 if (r.body && r.body.firstChild && r.body.firstChild.nodeName == 'parsererror') {
610- throw new Error("Could not parse string to xml");
611+ throw new Error(_t("Could not parse string to xml"));
612 }
613 return r;
614 }
615@@ -1468,7 +1468,7 @@
616 try {
617 xDoc = new ActiveXObject("MSXML2.DOMDocument");
618 } catch (e) {
619- throw new Error("Could not find a DOM Parser: " + e.message);
620+ throw new Error(_.str.sprintf( _t("Could not find a DOM Parser: %s"), e.message));
621 }
622 xDoc.async = false;
623 xDoc.preserveWhiteSpace = true;
624
625=== modified file 'addons/web_calendar/static/src/js/calendar.js'
626--- addons/web_calendar/static/src/js/calendar.js 2012-11-21 16:04:52 +0000
627+++ addons/web_calendar/static/src/js/calendar.js 2012-11-29 11:56:19 +0000
628@@ -88,7 +88,7 @@
629 this.fields = this.fields_view.fields;
630
631 if (!this.date_start) {
632- throw new Error("Calendar view has not defined 'date_start' attribute.");
633+ throw new Error(_t("Calendar view has not defined 'date_start' attribute."));
634 }
635
636 //* Calendar Fields *
637@@ -96,7 +96,7 @@
638
639 if (this.date_delay) {
640 if (this.fields[this.date_delay].type != 'float') {
641- throw new Error("Calendar view has a 'date_delay' type != float");
642+ throw new Error(_t("Calendar view has a 'date_delay' type != float"));
643 }
644 this.calendar_fields.date_delay = {'name': this.date_delay, 'kind': this.fields[this.date_delay].type};
645 }
646
647=== modified file 'addons/web_kanban/static/src/js/kanban.js'
648--- addons/web_kanban/static/src/js/kanban.js 2012-11-28 17:13:25 +0000
649+++ addons/web_kanban/static/src/js/kanban.js 2012-11-29 11:56:19 +0000
650@@ -409,7 +409,7 @@
651 new_group.do_save_sequences();
652 }).fail(function(error, evt) {
653 evt.preventDefault();
654- alert("An error has occured while moving the record to this group.");
655+ alert(_t("An error has occured while moving the record to this group."));
656 self.do_reload(); // TODO: use draggable + sortable in order to cancel the dragging when the rcp fails
657 });
658 }
659
660=== modified file 'addons/web_view_editor/static/src/js/view_editor.js'
661--- addons/web_view_editor/static/src/js/view_editor.js 2012-11-05 09:30:13 +0000
662+++ addons/web_view_editor/static/src/js/view_editor.js 2012-11-29 11:56:19 +0000
663@@ -161,7 +161,7 @@
664 }
665 });
666 msg += "</ul>";
667- this.do_warn("The following fields are invalid :", msg);
668+ this.do_warn(_t("The following fields are invalid :"), msg);
669 },
670 add_node_name : function(node) {
671 if(node.tagName.toLowerCase() == "button" || node.tagName.toLowerCase() == "field"){
672@@ -260,7 +260,7 @@
673 "arch": view_arch_list});
674 });
675 } else {
676- self.do_warn("Please select view in list :");
677+ self.do_warn(_t("Please select view in list :"));
678 }
679 });
680 },
681@@ -387,10 +387,10 @@
682 self.inherited_view(selected_row);
683 }
684 }else{
685- alert("Can't Update View");
686+ alert(_t("Can't Update View"));
687 }
688 }else{
689- alert("Select an element");
690+ alert(_t("Select an element"));
691 }
692 }},
693 {text: _t("Preview"), click: function() {
694@@ -983,7 +983,7 @@
695 } else {
696 table_selector.append('<td align="right">' + node.string + '</td>' + type_widget.render() );
697 if (node.name == "field_value") {
698- table_selector.append('<td id="new_field" align="right" width="100px"> <button>New Field</button></td>');
699+ table_selector.append('<td id="new_field" align="right" width="100px"> <button>' + _t("New Field") + '</button></td>');
700 }
701 }
702 type_widget.start();