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
=== modified file 'addons/web/controllers/main.py'
--- addons/web/controllers/main.py 2012-11-29 09:10:38 +0000
+++ addons/web/controllers/main.py 2012-11-29 11:56:19 +0000
@@ -28,6 +28,7 @@
28 xlwt = None28 xlwt = None
2929
30import openerp30import openerp
31from openerp.tools.translate import _
3132
32from .. import http33from .. import http
33openerpweb = http34openerpweb = http
@@ -762,7 +763,7 @@
762 except xmlrpclib.Fault, e:763 except xmlrpclib.Fault, e:
763 if e.faultCode and e.faultCode.split(':')[0] == 'AccessDenied':764 if e.faultCode and e.faultCode.split(':')[0] == 'AccessDenied':
764 return {'error': e.faultCode, 'title': 'Drop Database'}765 return {'error': e.faultCode, 'title': 'Drop Database'}
765 return {'error': 'Could not drop database !', 'title': 'Drop Database'}766 return {'error': _('Could not drop database !'), 'title': _('Drop Database')}
766767
767 @openerpweb.httprequest768 @openerpweb.httprequest
768 def backup(self, req, backup_db, backup_pwd, token):769 def backup(self, req, backup_db, backup_pwd, token):
@@ -780,7 +781,7 @@
780 {'fileToken': int(token)}781 {'fileToken': int(token)}
781 )782 )
782 except xmlrpclib.Fault, e:783 except xmlrpclib.Fault, e:
783 return simplejson.dumps([[],[{'error': e.faultCode, 'title': 'backup Database'}]])784 return simplejson.dumps([[],[{'error': e.faultCode, 'title': _('Backup Database')}]])
784785
785 @openerpweb.httprequest786 @openerpweb.httprequest
786 def restore(self, req, db_file, restore_pwd, new_db):787 def restore(self, req, db_file, restore_pwd, new_db):
@@ -801,8 +802,8 @@
801 return req.session.proxy("db").change_admin_password(old_password, new_password)802 return req.session.proxy("db").change_admin_password(old_password, new_password)
802 except xmlrpclib.Fault, e:803 except xmlrpclib.Fault, e:
803 if e.faultCode and e.faultCode.split(':')[0] == 'AccessDenied':804 if e.faultCode and e.faultCode.split(':')[0] == 'AccessDenied':
804 return {'error': e.faultCode, 'title': 'Change Password'}805 return {'error': e.faultCode, 'title': _('Change Password')}
805 return {'error': 'Error, password not changed !', 'title': 'Change Password'}806 return {'error': _('Error, password not changed !'), 'title': _('Change Password')}
806807
807class Session(openerpweb.Controller):808class Session(openerpweb.Controller):
808 _cp_path = "/web/session"809 _cp_path = "/web/session"
@@ -838,16 +839,16 @@
838 old_password, new_password,confirm_password = operator.itemgetter('old_pwd', 'new_password','confirm_pwd')(839 old_password, new_password,confirm_password = operator.itemgetter('old_pwd', 'new_password','confirm_pwd')(
839 dict(map(operator.itemgetter('name', 'value'), fields)))840 dict(map(operator.itemgetter('name', 'value'), fields)))
840 if not (old_password.strip() and new_password.strip() and confirm_password.strip()):841 if not (old_password.strip() and new_password.strip() and confirm_password.strip()):
841 return {'error':'You cannot leave any password empty.','title': 'Change Password'}842 return {'error':_('You cannot leave any password empty.'),'title': _('Change Password')}
842 if new_password != confirm_password:843 if new_password != confirm_password:
843 return {'error': 'The new password and its confirmation must be identical.','title': 'Change Password'}844 return {'error': _('The new password and its confirmation must be identical.'),'title': _('Change Password')}
844 try:845 try:
845 if req.session.model('res.users').change_password(846 if req.session.model('res.users').change_password(
846 old_password, new_password):847 old_password, new_password):
847 return {'new_password':new_password}848 return {'new_password':new_password}
848 except Exception:849 except Exception:
849 return {'error': 'The old password you provided is incorrect, your password was not changed.', 'title': 'Change Password'}850 return {'error': _('The old password you provided is incorrect, your password was not changed.'), 'title': _('Change Password')}
850 return {'error': 'Error, password not changed !', 'title': 'Change Password'}851 return {'error': _('Error, password not changed !'), 'title': _('Change Password')}
851852
852 @openerpweb.jsonrequest853 @openerpweb.jsonrequest
853 def sc_list(self, req):854 def sc_list(self, req):
@@ -859,7 +860,7 @@
859 try:860 try:
860 return req.session.proxy("db").list_lang() or []861 return req.session.proxy("db").list_lang() or []
861 except Exception, e:862 except Exception, e:
862 return {"error": e, "title": "Languages"}863 return {"error": e, "title": _("Languages")}
863864
864 @openerpweb.jsonrequest865 @openerpweb.jsonrequest
865 def modules(self, req):866 def modules(self, req):
@@ -1302,7 +1303,7 @@
1302 res = Model.default_get(fields, context)1303 res = Model.default_get(fields, context)
1303 filecontent = base64.b64decode(res.get(field, ''))1304 filecontent = base64.b64decode(res.get(field, ''))
1304 if not filecontent:1305 if not filecontent:
1305 raise ValueError("No content found for field '%s' on '%s:%s'" %1306 raise ValueError(_("No content found for field '%s' on '%s:%s'") %
1306 (field, model, id))1307 (field, model, id))
1307 else:1308 else:
1308 filename = '%s_%s' % (model.replace('.', '_'), id)1309 filename = '%s_%s' % (model.replace('.', '_'), id)
13091310
=== modified file 'addons/web/static/src/js/chrome.js'
--- addons/web/static/src/js/chrome.js 2012-11-29 09:10:38 +0000
+++ addons/web/static/src/js/chrome.js 2012-11-29 11:56:19 +0000
@@ -289,7 +289,7 @@
289});289});
290290
291instance.web.Loading = instance.web.Widget.extend({291instance.web.Loading = instance.web.Widget.extend({
292 template: 'Loading',292 template: _t("Loading"),
293 init: function(parent) {293 init: function(parent) {
294 this._super(parent);294 this._super(parent);
295 this.count = 0;295 this.count = 0;
@@ -390,11 +390,11 @@
390 self.$el.find("form[name=restore_db_form]").validate({ submitHandler: self.do_restore });390 self.$el.find("form[name=restore_db_form]").validate({ submitHandler: self.do_restore });
391 self.$el.find("form[name=change_pwd_form]").validate({391 self.$el.find("form[name=change_pwd_form]").validate({
392 messages: {392 messages: {
393 old_pwd: "Please enter your previous password",393 old_pwd: _t("Please enter your previous password"),
394 new_pwd: "Please enter your new password",394 new_pwd: _t("Please enter your new password"),
395 confirm_pwd: {395 confirm_pwd: {
396 required: "Please confirm your new password",396 required: _t("Please confirm your new password"),
397 equalTo: "The confirmation does not match the password"397 equalTo: _t("The confirmation does not match the password")
398 }398 }
399 },399 },
400 submitHandler: self.do_change_password400 submitHandler: self.do_change_password
@@ -478,7 +478,7 @@
478 self.display_error(result);478 self.display_error(result);
479 return;479 return;
480 }480 }
481 self.do_notify("Duplicating database", "The database has been duplicated.");481 self.do_notify(_t("Duplicating database"), _t("The database has been duplicated."));
482 self.start();482 self.start();
483 });483 });
484 },484 },
@@ -488,7 +488,7 @@
488 fields = $form.serializeArray(),488 fields = $form.serializeArray(),
489 $db_list = $form.find('[name=drop_db]'),489 $db_list = $form.find('[name=drop_db]'),
490 db = $db_list.val();490 db = $db_list.val();
491 if (!db || !confirm("Do you really want to delete the database: " + db + " ?")) {491 if (!db || !confirm(_.str.sprintf(_t("Do you really want to delete the database: %s ?"), db))) {
492 return;492 return;
493 }493 }
494 self.rpc("/web/database/drop", {'fields': fields}).done(function(result) {494 self.rpc("/web/database/drop", {'fields': fields}).done(function(result) {
@@ -496,7 +496,7 @@
496 self.display_error(result);496 self.display_error(result);
497 return;497 return;
498 }498 }
499 self.do_notify("Dropping database", "The database '" + db + "' has been dropped");499 self.do_notify(_t("Dropping database"), _.str.sprintf(_t("The database %s has been dropped"), db));
500 self.start();500 self.start();
501 });501 });
502 },502 },
@@ -511,7 +511,7 @@
511 error: function(error){511 error: function(error){
512 if(error){512 if(error){
513 self.display_error({513 self.display_error({
514 title: 'Backup Database',514 title: _t("Backup Database"),
515 error: 'AccessDenied'515 error: 'AccessDenied'
516 });516 });
517 }517 }
@@ -534,13 +534,13 @@
534534
535 if (body.indexOf('403 Forbidden') !== -1) {535 if (body.indexOf('403 Forbidden') !== -1) {
536 self.display_error({536 self.display_error({
537 title: 'Access Denied',537 title: _t("Access Denied"),
538 error: 'Incorrect super-administrator password'538 error: _t("Incorrect super-administrator password")
539 });539 });
540 } else {540 } else {
541 self.display_error({541 self.display_error({
542 title: 'Restore Database',542 title: _t("Restore Database"),
543 error: 'Could not restore the database'543 error: _t("Could not restore the database")
544 });544 });
545 }545 }
546 },546 },
@@ -560,7 +560,7 @@
560 return;560 return;
561 }561 }
562 self.unblockUI();562 self.unblockUI();
563 self.do_notify("Changed Password", "Password has been changed successfully");563 self.do_notify(_t("Changed Password"), _t("Password has been changed successfully"));
564 });564 });
565 },565 },
566 do_exit: function () {566 do_exit: function () {
@@ -642,7 +642,7 @@
642 }642 }
643 var db = this.$("form [name=db]").val();643 var db = this.$("form [name=db]").val();
644 if (!db) {644 if (!db) {
645 this.do_warn("Login", "No database selected !");645 this.do_warn(_t("Login"), _t("No database selected !"));
646 return false;646 return false;
647 }647 }
648 var login = this.$("form input[name=login]").val();648 var login = this.$("form input[name=login]").val();
@@ -678,7 +678,7 @@
678 self.trigger('login_successful');678 self.trigger('login_successful');
679 }, function () {679 }, function () {
680 self.$(".oe_login_pane").fadeIn("fast", function() {680 self.$(".oe_login_pane").fadeIn("fast", function() {
681 self.show_error("Invalid username or password");681 self.show_error(_t("Invalid username or password"));
682 });682 });
683 });683 });
684 },684 },
@@ -765,7 +765,7 @@
765 template: "ChangePassword",765 template: "ChangePassword",
766 start: function() {766 start: function() {
767 var self = this;767 var self = this;
768 this.getParent().dialog_title = "Change Password";768 this.getParent().dialog_title = _t("Change Password");
769 var $button = self.$el.find('.oe_form_button');769 var $button = self.$el.find('.oe_form_button');
770 $button.appendTo(this.getParent().$buttons);770 $button.appendTo(this.getParent().$buttons);
771 $button.eq(2).click(function(){771 $button.eq(2).click(function(){
772772
=== modified file 'addons/web/static/src/js/dates.js'
--- addons/web/static/src/js/dates.js 2012-04-17 11:58:05 +0000
+++ addons/web/static/src/js/dates.js 2012-11-29 11:56:19 +0000
@@ -1,5 +1,6 @@
11
2openerp.web.dates = function(instance) {2openerp.web.dates = function(instance) {
3var _t = instance.web._t;
34
4/**5/**
5 * Converts a string to a Date javascript object using OpenERP's6 * Converts a string to a Date javascript object using OpenERP's
@@ -18,11 +19,11 @@
18 var regex = /^(\d\d\d\d-\d\d-\d\d \d\d:\d\d:\d\d)(?:\.\d+)?$/;19 var regex = /^(\d\d\d\d-\d\d-\d\d \d\d:\d\d:\d\d)(?:\.\d+)?$/;
19 var res = regex.exec(str);20 var res = regex.exec(str);
20 if ( !res ) {21 if ( !res ) {
21 throw new Error("'" + str + "' is not a valid datetime");22 throw new Error(_.str.sprintf(_t("'%s' is not a valid datetime"), str));
22 }23 }
23 var obj = Date.parseExact(res[1] + " UTC", 'yyyy-MM-dd HH:mm:ss zzz');24 var obj = Date.parseExact(res[1] + " UTC", 'yyyy-MM-dd HH:mm:ss zzz');
24 if (! obj) {25 if (! obj) {
25 throw new Error("'" + str + "' is not a valid datetime");26 throw new Error(_.str.sprintf(_t("'%s' is not a valid datetime"), str));
26 }27 }
27 return obj;28 return obj;
28};29};
@@ -45,11 +46,11 @@
45 var regex = /^\d\d\d\d-\d\d-\d\d$/;46 var regex = /^\d\d\d\d-\d\d-\d\d$/;
46 var res = regex.exec(str);47 var res = regex.exec(str);
47 if ( !res ) {48 if ( !res ) {
48 throw new Error("'" + str + "' is not a valid date");49 throw new Error(_.str.sprintf(_t("'%s' is not a valid date"), str));
49 }50 }
50 var obj = Date.parseExact(str, 'yyyy-MM-dd');51 var obj = Date.parseExact(str, 'yyyy-MM-dd');
51 if (! obj) {52 if (! obj) {
52 throw new Error("'" + str + "' is not a valid date");53 throw new Error(_.str.sprintf(_t("'%s' is not a valid date"), str));
53 }54 }
54 return obj;55 return obj;
55};56};
@@ -72,11 +73,11 @@
72 var regex = /^(\d\d:\d\d:\d\d)(?:\.\d+)?$/;73 var regex = /^(\d\d:\d\d:\d\d)(?:\.\d+)?$/;
73 var res = regex.exec(str);74 var res = regex.exec(str);
74 if ( !res ) {75 if ( !res ) {
75 throw new Error("'" + str + "' is not a valid time");76 throw new Error(_.str.sprintf(_t("'%s' is not a valid time"), str));
76 }77 }
77 var obj = Date.parseExact("1970-01-01 " + res[1], 'yyyy-MM-dd HH:mm:ss');78 var obj = Date.parseExact("1970-01-01 " + res[1], 'yyyy-MM-dd HH:mm:ss');
78 if (! obj) {79 if (! obj) {
79 throw new Error("'" + str + "' is not a valid time");80 throw new Error(_.str.sprintf(_t("'%s' is not a valid time"), str));
80 }81 }
81 return obj;82 return obj;
82};83};
8384
=== modified file 'addons/web/static/src/js/formats.js'
--- addons/web/static/src/js/formats.js 2012-11-12 17:11:28 +0000
+++ addons/web/static/src/js/formats.js 2012-11-29 11:56:19 +0000
@@ -224,7 +224,7 @@
224 } while(tmp !== value);224 } while(tmp !== value);
225 tmp = Number(value);225 tmp = Number(value);
226 if (isNaN(tmp))226 if (isNaN(tmp))
227 throw new Error(value + " is not a correct integer");227 throw new Error(_.str.sprintf(_t("'%s' is not a correct integer"), value));
228 return tmp;228 return tmp;
229 case 'float':229 case 'float':
230 var tmp = Number(value);230 var tmp = Number(value);
@@ -239,7 +239,7 @@
239 var reformatted_value = tmp.replace(instance.web._t.database.parameters.decimal_point, ".");239 var reformatted_value = tmp.replace(instance.web._t.database.parameters.decimal_point, ".");
240 var parsed = Number(reformatted_value);240 var parsed = Number(reformatted_value);
241 if (isNaN(parsed))241 if (isNaN(parsed))
242 throw new Error(value + " is not a correct float");242 throw new Error(_.str.sprintf(_t("'%s' is not a correct float"), value));
243 return parsed;243 return parsed;
244 case 'float_time':244 case 'float_time':
245 var factor = 1;245 var factor = 1;
@@ -263,7 +263,7 @@
263 datetime = Date.parse(value);263 datetime = Date.parse(value);
264 if (datetime !== null)264 if (datetime !== null)
265 return instance.web.datetime_to_str(datetime);265 return instance.web.datetime_to_str(datetime);
266 throw new Error(value + " is not a valid datetime");266 throw new Error(_.str.sprintf(_t("'%s' is not a correct datetime"), value));
267 case 'date':267 case 'date':
268 var date = Date.parseExact(value, date_pattern);268 var date = Date.parseExact(value, date_pattern);
269 if (date !== null)269 if (date !== null)
@@ -271,7 +271,7 @@
271 date = Date.parse(value);271 date = Date.parse(value);
272 if (date !== null)272 if (date !== null)
273 return instance.web.date_to_str(date);273 return instance.web.date_to_str(date);
274 throw new Error(value + " is not a valid date");274 throw new Error(_.str.sprintf(_t("'%s' is not a correct date"), value));
275 case 'time':275 case 'time':
276 var time = Date.parseExact(value, time_pattern);276 var time = Date.parseExact(value, time_pattern);
277 if (time !== null)277 if (time !== null)
@@ -279,7 +279,7 @@
279 time = Date.parse(value);279 time = Date.parse(value);
280 if (time !== null)280 if (time !== null)
281 return instance.web.time_to_str(time);281 return instance.web.time_to_str(time);
282 throw new Error(value + " is not a valid time");282 throw new Error(_.str.sprintf(_t("'%s' is not a correct time"), value));
283 }283 }
284 return value;284 return value;
285};285};
@@ -294,7 +294,7 @@
294 try {294 try {
295 return instance.web.str_to_time(value);295 return instance.web.str_to_time(value);
296 } catch(e) {}296 } catch(e) {}
297 throw new Error("'" + value + "' is not a valid date, datetime nor time");297 throw new Error(_.str.sprintf(_t("'%s' is not a correct date, datetime nor time"), value));
298};298};
299299
300instance.web.auto_date_to_str = function(value, type) {300instance.web.auto_date_to_str = function(value, type) {
@@ -306,7 +306,7 @@
306 case 'time':306 case 'time':
307 return instance.web.time_to_str(value);307 return instance.web.time_to_str(value);
308 default:308 default:
309 throw new Error(type + " is not convertible to date, datetime nor time");309 throw new Error(_.str.sprintf(_t("'%s' is not convertible to date, datetime nor time"), type));
310 }310 }
311};311};
312312
313313
=== modified file 'addons/web/static/src/js/pyeval.js'
--- addons/web/static/src/js/pyeval.js 2012-11-28 11:05:42 +0000
+++ addons/web/static/src/js/pyeval.js 2012-11-29 11:56:19 +0000
@@ -2,6 +2,7 @@
2 * py.js helpers and setup2 * py.js helpers and setup
3 */3 */
4openerp.web.pyeval = function (instance) {4openerp.web.pyeval = function (instance) {
5 var _t = instance.web._t;
5 instance.web.pyeval = {};6 instance.web.pyeval = {};
67
7 var obj = function () {};8 var obj = function () {};
@@ -71,7 +72,7 @@
71 var ymd2ord = function (year, month, day) {72 var ymd2ord = function (year, month, day) {
72 var dim = days_in_month(year, month);73 var dim = days_in_month(year, month);
73 if (!(1 <= day && day <= dim)) {74 if (!(1 <= day && day <= dim)) {
74 throw new Error("ValueError: day must be in 1.." + dim);75 throw new Error(_.str.sprintf(_t("ValueError: day must be in 1..%d"), dim));
75 }76 }
76 return days_before_year(year)77 return days_before_year(year)
77 + days_before_month(year, month)78 + days_before_month(year, month)
@@ -277,10 +278,11 @@
277 });278 });
278 var s = _.str.sprintf("%d:%02d:%02d", hh, mm, ss);279 var s = _.str.sprintf("%d:%02d:%02d", hh, mm, ss);
279 if (this.days) {280 if (this.days) {
280 s = _.str.sprintf("%d day%s, %s",281 if (this.days != 1 && this.days != -1) {
281 this.days,282 s = _.str.sprintf(_t("%d days, %s"), this.days, s);
282 (this.days != 1 && this.days != -1) ? 's' : '',283 } else {
283 s);284 s = _.str.sprintf(_t("%d day, %s"), this.days, s);
285 };
284 }286 }
285 if (this.microseconds) {287 if (this.microseconds) {
286 s = _.str.sprintf("%s.%06d", s, this.microseconds);288 s = _.str.sprintf("%s.%06d", s, this.microseconds);
@@ -726,7 +728,7 @@
726 case 'context': case 'compound_context':728 case 'context': case 'compound_context':
727 return instance.web.pyeval.eval('contexts', [arg]);729 return instance.web.pyeval.eval('contexts', [arg]);
728 default:730 default:
729 throw new Error(instance.web._t("Unknown nonliteral type " + arg.__ref));731 throw new Error(_t("Unknown nonliteral type ") + arg.__ref);
730 }732 }
731 };733 };
732 /**734 /**
@@ -760,11 +762,11 @@
760 } catch (e) {762 } catch (e) {
761 d.resolve({ error: {763 d.resolve({ error: {
762 code: 400,764 code: 400,
763 message: instance.web._t("Evaluation Error"),765 message: _t("Evaluation Error"),
764 data: {766 data: {
765 type: 'local_exception',767 type: 'local_exception',
766 debug: _.str.sprintf(768 debug: _.str.sprintf(
767 instance.web._t("Local evaluation failure\n%s\n\n%s"),769 _t("Local evaluation failure\n%s\n\n%s"),
768 e.message, JSON.stringify(source))770 e.message, JSON.stringify(source))
769 }771 }
770 }});772 }});
771773
=== modified file 'addons/web/static/src/js/view_form.js'
--- addons/web/static/src/js/view_form.js 2012-11-29 09:10:38 +0000
+++ addons/web/static/src/js/view_form.js 2012-11-29 11:56:19 +0000
@@ -148,7 +148,7 @@
148 load_form: function(data) {148 load_form: function(data) {
149 var self = this;149 var self = this;
150 if (!data) {150 if (!data) {
151 throw new Error("No data provided.");151 throw new Error(_t("No data provided."));
152 }152 }
153 if (this.arch) {153 if (this.arch) {
154 throw "Form view does not support multiple calls to load_form";154 throw "Form view does not support multiple calls to load_form";
@@ -316,12 +316,12 @@
316 var self = this, set_values = [];316 var self = this, set_values = [];
317 if (!record) {317 if (!record) {
318 this.set({ 'title' : undefined });318 this.set({ 'title' : undefined });
319 this.do_warn("Form", "The record could not be found in the database.", true);319 this.do_warn(_t("Form"), _t("The record could not be found in the database."), true);
320 return $.Deferred().reject();320 return $.Deferred().reject();
321 }321 }
322 this.datarecord = record;322 this.datarecord = record;
323 this._actualize_mode();323 this._actualize_mode();
324 this.set({ 'title' : record.id ? record.display_name : "New" });324 this.set({ 'title' : record.id ? record.display_name : _t("New") });
325325
326 _(this.fields).each(function (field, f) {326 _(this.fields).each(function (field, f) {
327 field._dirty_flag = false;327 field._dirty_flag = false;
@@ -431,7 +431,7 @@
431 var onchange = _.str.trim(on_change);431 var onchange = _.str.trim(on_change);
432 var call = onchange.match(/^\s?(.*?)\((.*?)\)\s?$/);432 var call = onchange.match(/^\s?(.*?)\((.*?)\)\s?$/);
433 if (!call) {433 if (!call) {
434 throw new Error("Wrong on change format: " + onchange);434 throw new Error(_.str.sprintf( _t("Wrong on change format: %s"), onchange ));
435 }435 }
436436
437 var method = call[1];437 var method = call[1];
@@ -866,7 +866,7 @@
866 }).value();866 }).value();
867 warnings.unshift('<ul>');867 warnings.unshift('<ul>');
868 warnings.push('</ul>');868 warnings.push('</ul>');
869 this.do_warn("The following fields are invalid :", warnings.join(''));869 this.do_warn(_t("The following fields are invalid:"), warnings.join(''));
870 },870 },
871 /**871 /**
872 * Reload the form after saving872 * Reload the form after saving
@@ -1235,11 +1235,11 @@
1235 _.each(this.fields_to_init, function($elem) {1235 _.each(this.fields_to_init, function($elem) {
1236 var name = $elem.attr("name");1236 var name = $elem.attr("name");
1237 if (!self.fvg.fields[name]) {1237 if (!self.fvg.fields[name]) {
1238 throw new Error("Field '" + name + "' specified in view could not be found.");1238 throw new Error(_.str.sprintf(_t("Field '%s' specified in view could not be found."), name));
1239 }1239 }
1240 var obj = self.fields_registry.get_any([$elem.attr('widget'), self.fvg.fields[name].type]);1240 var obj = self.fields_registry.get_any([$elem.attr('widget'), self.fvg.fields[name].type]);
1241 if (!obj) {1241 if (!obj) {
1242 throw new Error("Widget type '"+ $elem.attr('widget') + "' is not implemented");1242 throw new Error(_.str.sprintf(_t("Widget type '%s' is not implemented"), $elem.attr('widget')));
1243 }1243 }
1244 var w = new (obj)(self.view, instance.web.xml_to_json($elem[0]));1244 var w = new (obj)(self.view, instance.web.xml_to_json($elem[0]));
1245 var $label = self.labels[$elem.attr("name")];1245 var $label = self.labels[$elem.attr("name")];
@@ -2313,7 +2313,7 @@
2313 },2313 },
2314 on_button_clicked: function() {2314 on_button_clicked: function() {
2315 if (!this.get('value') || !this.is_syntax_valid()) {2315 if (!this.get('value') || !this.is_syntax_valid()) {
2316 this.do_warn("E-mail error", "Can't send email to invalid e-mail address");2316 this.do_warn(_t("E-mail error"), _t("Can't send email to invalid e-mail address"));
2317 } else {2317 } else {
2318 location.href = 'mailto:' + this.get('value');2318 location.href = 'mailto:' + this.get('value');
2319 }2319 }
@@ -2342,7 +2342,7 @@
2342 },2342 },
2343 on_button_clicked: function() {2343 on_button_clicked: function() {
2344 if (!this.get('value')) {2344 if (!this.get('value')) {
2345 this.do_warn("Resource error", "This resource is empty");2345 this.do_warn(_t("Resource error"), _t("This resource is empty"));
2346 } else {2346 } else {
2347 var url = $.trim(this.get('value'));2347 var url = $.trim(this.get('value'));
2348 if(/^www\./i.test(url))2348 if(/^www\./i.test(url))
@@ -3379,7 +3379,7 @@
3379 var views = [];3379 var views = [];
3380 _.each(modes, function(mode) {3380 _.each(modes, function(mode) {
3381 if (! _.include(["list", "tree", "graph", "kanban"], mode)) {3381 if (! _.include(["list", "tree", "graph", "kanban"], mode)) {
3382 throw new Error(_.str.sprintf("View type '%s' is not supported in One2Many.", mode));3382 throw new Error(_.str.sprintf(_t("View type '%s' is not supported in One2Many."), mode));
3383 }3383 }
3384 var view = {3384 var view = {
3385 view_id: false,3385 view_id: false,
@@ -4834,7 +4834,7 @@
4834 },4834 },
4835 on_file_uploaded: function(size, name, content_type, file_base64) {4835 on_file_uploaded: function(size, name, content_type, file_base64) {
4836 if (size === false) {4836 if (size === false) {
4837 this.do_warn("File Upload", "There was a problem while uploading your file");4837 this.do_warn(_t("File Upload"), _t("There was a problem while uploading your file"));
4838 // TODO: use openerp web crashmanager4838 // TODO: use openerp web crashmanager
4839 console.warn("Error while uploading file : ", name);4839 console.warn("Error while uploading file : ", name);
4840 } else {4840 } else {
@@ -5003,7 +5003,7 @@
5003 this.field_manager = field_manager;5003 this.field_manager = field_manager;
5004 this.node = node;5004 this.node = node;
5005 if(this.field.type != "many2many" || this.field.relation != 'ir.attachment') {5005 if(this.field.type != "many2many" || this.field.relation != 'ir.attachment') {
5006 throw "The type of the field '"+this.field.string+"' must be a many2many field with a relation to 'ir.attachment' model.";5006 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);
5007 }5007 }
5008 this.ds_file = new instance.web.DataSetSearch(this, 'ir.attachment');5008 this.ds_file = new instance.web.DataSetSearch(this, 'ir.attachment');
5009 this.fileupload_id = _.uniqueId('oe_fileupload_temp');5009 this.fileupload_id = _.uniqueId('oe_fileupload_temp');
50105010
=== modified file 'addons/web/static/src/js/view_list.js'
--- addons/web/static/src/js/view_list.js 2012-11-29 09:10:38 +0000
+++ addons/web/static/src/js/view_list.js 2012-11-29 11:56:19 +0000
@@ -389,7 +389,7 @@
389 if (range_stop > total) {389 if (range_stop > total) {
390 range_stop = total;390 range_stop = total;
391 }391 }
392 spager = _.str.sprintf('%d-%d of %d', range_start, range_stop, total);392 spager = _.str.sprintf(_t("%d-%d of %d"), range_start, range_stop, total);
393 }393 }
394394
395 this.$pager.find('.oe_list_pager_state').text(spager);395 this.$pager.find('.oe_list_pager_state').text(spager);
@@ -887,8 +887,8 @@
887 var $row;887 var $row;
888 if (attribute === 'id') {888 if (attribute === 'id') {
889 if (old_value) {889 if (old_value) {
890 throw new Error("Setting 'id' attribute on existing record "890 throw new Error(_.str.sprintf( _t("Setting 'id' attribute on existing record %s"),
891 + JSON.stringify(record.attributes));891 JSON.stringify(record.attributes) ));
892 }892 }
893 if (!_.contains(self.dataset.ids, value)) {893 if (!_.contains(self.dataset.ids, value)) {
894 // add record to dataset if not already in (added by894 // add record to dataset if not already in (added by
@@ -956,7 +956,7 @@
956 if (row_id) {956 if (row_id) {
957 e.stopPropagation();957 e.stopPropagation();
958 if (!self.dataset.select_id(row_id)) {958 if (!self.dataset.select_id(row_id)) {
959 throw new Error("Could not find id in dataset");959 throw new Error(_t("Could not find id in dataset"));
960 }960 }
961 self.row_clicked(e);961 self.row_clicked(e);
962 }962 }
@@ -1016,7 +1016,7 @@
1016 var command = value[0];1016 var command = value[0];
1017 // 1. an array of m2m commands (usually (6, false, ids))1017 // 1. an array of m2m commands (usually (6, false, ids))
1018 if (command[0] !== 6) {1018 if (command[0] !== 6) {
1019 throw new Error(_t("Unknown m2m command ") + command[0]);1019 throw new Error(_.str.sprintf( _t("Unknown m2m command %s"), command[0]));
1020 }1020 }
1021 ids = command[2];1021 ids = command[2];
1022 } else {1022 } else {
@@ -1324,7 +1324,7 @@
1324 }1324 }
1325 // group_label is html-clean (through format or explicit1325 // group_label is html-clean (through format or explicit
1326 // escaping if format failed), can inject straight into HTML1326 // escaping if format failed), can inject straight into HTML
1327 $group_column.html(_.str.sprintf("%s (%d)",1327 $group_column.html(_.str.sprintf(_t("%s (%d)"),
1328 group_label, group.length));1328 group_label, group.length));
13291329
1330 if (group.length && group.openable) {1330 if (group.length && group.openable) {
@@ -1743,7 +1743,7 @@
1743 } else if (val instanceof Array) {1743 } else if (val instanceof Array) {
1744 output[k] = val[0];1744 output[k] = val[0];
1745 } else {1745 } else {
1746 throw new Error("Can't convert value " + val + " to context");1746 throw new Error(_.str.sprintf(_t("Can't convert value %s to context"), val));
1747 }1747 }
1748 }1748 }
1749 return output;1749 return output;
17501750
=== modified file 'addons/web/static/src/js/view_list_editable.js'
--- addons/web/static/src/js/view_list_editable.js 2012-11-29 09:10:38 +0000
+++ addons/web/static/src/js/view_list_editable.js 2012-11-29 11:56:19 +0000
@@ -3,6 +3,8 @@
3 * @namespace3 * @namespace
4 */4 */
5openerp.web.list_editable = function (instance) {5openerp.web.list_editable = function (instance) {
6 var _t = instance.web._t;
7
6 // editability status of list rows8 // editability status of list rows
7 instance.web.ListView.prototype.defaults.editable = null;9 instance.web.ListView.prototype.defaults.editable = null;
810
@@ -775,7 +777,7 @@
775 cancel: function (force) {777 cancel: function (force) {
776 if (!(force || this.form.can_be_discarded())) {778 if (!(force || this.form.can_be_discarded())) {
777 return $.Deferred().reject({779 return $.Deferred().reject({
778 message: "The form's data can not be discarded"}).promise();780 message: _t("The form's data can not be discarded")}).promise();
779 }781 }
780 var record = this.record;782 var record = this.record;
781 this.record = null;783 this.record = null;
782784
=== modified file 'addons/web/static/src/js/views.js'
--- addons/web/static/src/js/views.js 2012-11-29 10:11:37 +0000
+++ addons/web/static/src/js/views.js 2012-11-29 11:56:19 +0000
@@ -807,7 +807,7 @@
807 break;807 break;
808 case 'tests':808 case 'tests':
809 this.do_action({809 this.do_action({
810 name: "JS Tests",810 name: _t("JS Tests"),
811 target: 'new',811 target: 'new',
812 type : 'ir.actions.act_url',812 type : 'ir.actions.act_url',
813 url: '/web/tests?mod=*'813 url: '/web/tests?mod=*'
@@ -835,7 +835,7 @@
835 break;835 break;
836 case 'translate':836 case 'translate':
837 this.do_action({837 this.do_action({
838 name: "Technical Translation",838 name: _t("Technical Translation"),
839 res_model : 'ir.translation',839 res_model : 'ir.translation',
840 domain : [['type', '!=', 'object'], '|', ['name', '=', this.dataset.model], ['name', 'ilike', this.dataset.model + ',']],840 domain : [['type', '!=', 'object'], '|', ['name', '=', this.dataset.model], ['name', 'ilike', this.dataset.model + ',']],
841 views: [[false, 'list'], [false, 'form']],841 views: [[false, 'list'], [false, 'form']],
@@ -1418,7 +1418,7 @@
1418 return sindent + node;1418 return sindent + node;
1419 } else if (typeof(node.tag) !== 'string' || !node.children instanceof Array || !node.attrs instanceof Object) {1419 } else if (typeof(node.tag) !== 'string' || !node.children instanceof Array || !node.attrs instanceof Object) {
1420 throw new Error(1420 throw new Error(
1421 _.str.sprintf("Node [%s] is not a JSONified XML node",1421 _.str.sprintf(_t("Node [%s] is not a JSONified XML node"),
1422 JSON.stringify(node)));1422 JSON.stringify(node)));
1423 }1423 }
1424 for (var attr in node.attrs) {1424 for (var attr in node.attrs) {
@@ -1452,7 +1452,7 @@
1452 } else if (window.ActiveXObject) {1452 } else if (window.ActiveXObject) {
1453 return node.xml;1453 return node.xml;
1454 } else {1454 } else {
1455 throw new Error("Could not serialize XML");1455 throw new Error(_t("Could not serialize XML"));
1456 }1456 }
1457};1457};
1458instance.web.str_to_xml = function(s) {1458instance.web.str_to_xml = function(s) {
@@ -1460,7 +1460,7 @@
1460 var dp = new DOMParser();1460 var dp = new DOMParser();
1461 var r = dp.parseFromString(s, "text/xml");1461 var r = dp.parseFromString(s, "text/xml");
1462 if (r.body && r.body.firstChild && r.body.firstChild.nodeName == 'parsererror') {1462 if (r.body && r.body.firstChild && r.body.firstChild.nodeName == 'parsererror') {
1463 throw new Error("Could not parse string to xml");1463 throw new Error(_t("Could not parse string to xml"));
1464 }1464 }
1465 return r;1465 return r;
1466 }1466 }
@@ -1468,7 +1468,7 @@
1468 try {1468 try {
1469 xDoc = new ActiveXObject("MSXML2.DOMDocument");1469 xDoc = new ActiveXObject("MSXML2.DOMDocument");
1470 } catch (e) {1470 } catch (e) {
1471 throw new Error("Could not find a DOM Parser: " + e.message);1471 throw new Error(_.str.sprintf( _t("Could not find a DOM Parser: %s"), e.message));
1472 }1472 }
1473 xDoc.async = false;1473 xDoc.async = false;
1474 xDoc.preserveWhiteSpace = true;1474 xDoc.preserveWhiteSpace = true;
14751475
=== modified file 'addons/web_calendar/static/src/js/calendar.js'
--- addons/web_calendar/static/src/js/calendar.js 2012-11-21 16:04:52 +0000
+++ addons/web_calendar/static/src/js/calendar.js 2012-11-29 11:56:19 +0000
@@ -88,7 +88,7 @@
88 this.fields = this.fields_view.fields;88 this.fields = this.fields_view.fields;
8989
90 if (!this.date_start) {90 if (!this.date_start) {
91 throw new Error("Calendar view has not defined 'date_start' attribute.");91 throw new Error(_t("Calendar view has not defined 'date_start' attribute."));
92 }92 }
9393
94 //* Calendar Fields *94 //* Calendar Fields *
@@ -96,7 +96,7 @@
9696
97 if (this.date_delay) {97 if (this.date_delay) {
98 if (this.fields[this.date_delay].type != 'float') {98 if (this.fields[this.date_delay].type != 'float') {
99 throw new Error("Calendar view has a 'date_delay' type != float");99 throw new Error(_t("Calendar view has a 'date_delay' type != float"));
100 }100 }
101 this.calendar_fields.date_delay = {'name': this.date_delay, 'kind': this.fields[this.date_delay].type};101 this.calendar_fields.date_delay = {'name': this.date_delay, 'kind': this.fields[this.date_delay].type};
102 }102 }
103103
=== modified file 'addons/web_kanban/static/src/js/kanban.js'
--- addons/web_kanban/static/src/js/kanban.js 2012-11-28 17:13:25 +0000
+++ addons/web_kanban/static/src/js/kanban.js 2012-11-29 11:56:19 +0000
@@ -409,7 +409,7 @@
409 new_group.do_save_sequences();409 new_group.do_save_sequences();
410 }).fail(function(error, evt) {410 }).fail(function(error, evt) {
411 evt.preventDefault();411 evt.preventDefault();
412 alert("An error has occured while moving the record to this group.");412 alert(_t("An error has occured while moving the record to this group."));
413 self.do_reload(); // TODO: use draggable + sortable in order to cancel the dragging when the rcp fails413 self.do_reload(); // TODO: use draggable + sortable in order to cancel the dragging when the rcp fails
414 });414 });
415 }415 }
416416
=== modified file 'addons/web_view_editor/static/src/js/view_editor.js'
--- addons/web_view_editor/static/src/js/view_editor.js 2012-11-05 09:30:13 +0000
+++ addons/web_view_editor/static/src/js/view_editor.js 2012-11-29 11:56:19 +0000
@@ -161,7 +161,7 @@
161 }161 }
162 });162 });
163 msg += "</ul>";163 msg += "</ul>";
164 this.do_warn("The following fields are invalid :", msg);164 this.do_warn(_t("The following fields are invalid :"), msg);
165 },165 },
166 add_node_name : function(node) {166 add_node_name : function(node) {
167 if(node.tagName.toLowerCase() == "button" || node.tagName.toLowerCase() == "field"){167 if(node.tagName.toLowerCase() == "button" || node.tagName.toLowerCase() == "field"){
@@ -260,7 +260,7 @@
260 "arch": view_arch_list});260 "arch": view_arch_list});
261 });261 });
262 } else {262 } else {
263 self.do_warn("Please select view in list :");263 self.do_warn(_t("Please select view in list :"));
264 }264 }
265 });265 });
266 },266 },
@@ -387,10 +387,10 @@
387 self.inherited_view(selected_row);387 self.inherited_view(selected_row);
388 }388 }
389 }else{389 }else{
390 alert("Can't Update View");390 alert(_t("Can't Update View"));
391 }391 }
392 }else{392 }else{
393 alert("Select an element");393 alert(_t("Select an element"));
394 }394 }
395 }},395 }},
396 {text: _t("Preview"), click: function() {396 {text: _t("Preview"), click: function() {
@@ -983,7 +983,7 @@
983 } else {983 } else {
984 table_selector.append('<td align="right">' + node.string + '</td>' + type_widget.render() );984 table_selector.append('<td align="right">' + node.string + '</td>' + type_widget.render() );
985 if (node.name == "field_value") {985 if (node.name == "field_value") {
986 table_selector.append('<td id="new_field" align="right" width="100px"> <button>New Field</button></td>');986 table_selector.append('<td id="new_field" align="right" width="100px"> <button>' + _t("New Field") + '</button></td>');
987 }987 }
988 }988 }
989 type_widget.start();989 type_widget.start();